resolv 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/win32/resolv/depend +3 -0
- data/ext/win32/resolv/lib/resolv.rb +2 -1
- data/ext/win32/resolv/resolv.c +2 -1
- data/lib/resolv.rb +174 -72
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '017129811e9d2a2c49065d8f95e96f73acba713f6e1e2ee1cd65abb448bea1ce'
|
|
4
|
+
data.tar.gz: 9fe320e19d45e74055b648326efc8bc975b9cbc5aad2a4cd47e1b3660fb81f5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9632f2e80d4ce1d581f3271b70913e2acef6af77a0289539d0954b191382234d6d53fa190f79bd27468724e917b4ba68fb27e2c8e247ce89f0cabccec1c956a5
|
|
7
|
+
data.tar.gz: 59623cf40d63ab667ce5a39301e2eff5186d8c98306cec5c41fd720aad5b74bca7fcfce877ea44b54de297809d41c4822d7bdd5603964c4e772544998a6a5ef7
|
data/ext/win32/resolv/resolv.c
CHANGED
|
@@ -53,6 +53,7 @@ wchar_to_utf8(const WCHAR *w, int n)
|
|
|
53
53
|
return str;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/* :nodoc: */
|
|
56
57
|
static VALUE
|
|
57
58
|
get_dns_server_list(VALUE self)
|
|
58
59
|
{
|
|
@@ -81,7 +82,6 @@ get_dns_server_list(VALUE self)
|
|
|
81
82
|
return nameservers;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
|
|
85
85
|
static const WCHAR TCPIP_Params[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
|
|
86
86
|
|
|
87
87
|
static void
|
|
@@ -116,6 +116,7 @@ reg_open_key(VALUE klass, HKEY hkey, const WCHAR *wname)
|
|
|
116
116
|
return rb_ensure(rb_yield, k, hkey_close, k);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/* :nodoc: */
|
|
119
120
|
static VALUE
|
|
120
121
|
tcpip_params_open(VALUE klass)
|
|
121
122
|
{
|
data/lib/resolv.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'socket'
|
|
4
4
|
require 'timeout'
|
|
5
|
-
require 'io/wait'
|
|
5
|
+
require 'io/wait' if RUBY_VERSION < '3.2'
|
|
6
6
|
require 'securerandom'
|
|
7
7
|
require 'rbconfig'
|
|
8
8
|
|
|
@@ -35,7 +35,7 @@ require 'rbconfig'
|
|
|
35
35
|
class Resolv
|
|
36
36
|
|
|
37
37
|
# The version string
|
|
38
|
-
VERSION = "0.
|
|
38
|
+
VERSION = "0.8.0"
|
|
39
39
|
|
|
40
40
|
##
|
|
41
41
|
# Looks up the first IP address for +name+.
|
|
@@ -562,7 +562,19 @@ class Resolv
|
|
|
562
562
|
next if !sender
|
|
563
563
|
senders[[candidate, requester, nameserver, port]] = sender
|
|
564
564
|
end
|
|
565
|
-
|
|
565
|
+
begin
|
|
566
|
+
reply, reply_name = requester.request(sender, tout)
|
|
567
|
+
rescue ResolvTimeout
|
|
568
|
+
# Giving up part way through a frame loses stream sync, and a peer
|
|
569
|
+
# seen going away leaves the socket dead. Either way the requester
|
|
570
|
+
# says so, and the next attempt has to open a fresh connection. A
|
|
571
|
+
# timeout with the stream still on a frame boundary keeps it.
|
|
572
|
+
unless requester.reusable?
|
|
573
|
+
requesters.delete([nameserver, port])
|
|
574
|
+
requester.close
|
|
575
|
+
end
|
|
576
|
+
raise
|
|
577
|
+
end
|
|
566
578
|
case reply.rcode
|
|
567
579
|
when RCode::NoError
|
|
568
580
|
if reply.tc == 1 and not Requester::TCP === requester
|
|
@@ -698,13 +710,27 @@ class Resolv
|
|
|
698
710
|
@socks = nil
|
|
699
711
|
end
|
|
700
712
|
|
|
713
|
+
# Whether another request may be sent over the same transport. Only a
|
|
714
|
+
# stream transport can end up in a state that rules this out.
|
|
715
|
+
def reusable?
|
|
716
|
+
true
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
# A request could not be written. Only a stream transport can be left
|
|
720
|
+
# unusable by that; see #reusable?.
|
|
721
|
+
def send_failed
|
|
722
|
+
end
|
|
723
|
+
|
|
701
724
|
def request(sender, tout)
|
|
702
725
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
703
726
|
timelimit = start + tout
|
|
704
727
|
begin
|
|
705
728
|
sender.send
|
|
706
729
|
rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this
|
|
707
|
-
Errno::ENETUNREACH
|
|
730
|
+
Errno::ENETUNREACH,
|
|
731
|
+
Errno::EPIPE, # a peer that went away between requests
|
|
732
|
+
Errno::ECONNRESET # the same, as Windows reports it
|
|
733
|
+
send_failed
|
|
708
734
|
raise ResolvTimeout
|
|
709
735
|
end
|
|
710
736
|
while true
|
|
@@ -724,7 +750,7 @@ class Resolv
|
|
|
724
750
|
raise ResolvTimeout
|
|
725
751
|
end
|
|
726
752
|
begin
|
|
727
|
-
reply, from = recv_reply(select_result[0])
|
|
753
|
+
reply, from = recv_reply(select_result[0], timelimit)
|
|
728
754
|
rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
|
|
729
755
|
Errno::ECONNRESET, # Windows
|
|
730
756
|
EOFError
|
|
@@ -801,7 +827,7 @@ class Resolv
|
|
|
801
827
|
self
|
|
802
828
|
end
|
|
803
829
|
|
|
804
|
-
def recv_reply(readable_socks)
|
|
830
|
+
def recv_reply(readable_socks, timelimit = nil)
|
|
805
831
|
lazy_initialize
|
|
806
832
|
reply, from = readable_socks[0].recvfrom(UDPSize)
|
|
807
833
|
return reply, [from[3],from[1]]
|
|
@@ -860,20 +886,37 @@ class Resolv
|
|
|
860
886
|
@mutex.synchronize {
|
|
861
887
|
next if @initialized
|
|
862
888
|
@initialized = true
|
|
863
|
-
|
|
864
|
-
sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
|
|
865
|
-
@socks = [sock]
|
|
866
|
-
sock.do_not_reverse_lookup = true
|
|
867
|
-
DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
|
|
868
|
-
sock.connect(@host, @port)
|
|
889
|
+
connect_socket
|
|
869
890
|
}
|
|
870
891
|
self
|
|
871
892
|
end
|
|
872
893
|
|
|
873
|
-
|
|
894
|
+
# The socket to talk to the nameserver over, opening one if there is
|
|
895
|
+
# none yet. #recv_reply may have replaced it since a sender was
|
|
896
|
+
# created, so senders ask for it per request instead of holding on to
|
|
897
|
+
# one.
|
|
898
|
+
def sock
|
|
899
|
+
lazy_initialize
|
|
900
|
+
@socks[0]
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
def recv_reply(readable_socks, timelimit = nil)
|
|
874
904
|
lazy_initialize
|
|
875
905
|
reply = readable_socks[0].recv(UDPSize)
|
|
876
906
|
return reply, nil
|
|
907
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
|
908
|
+
# The kernel reports these from an ICMP message, and a second one for
|
|
909
|
+
# the same pair of endpoints is not always passed on: macOS 26.1 and
|
|
910
|
+
# later deliver every other one. A retry over this socket would then
|
|
911
|
+
# wait out its whole timeout rather than fail at once, so start over
|
|
912
|
+
# from a new source port.
|
|
913
|
+
@mutex.synchronize {
|
|
914
|
+
if @initialized
|
|
915
|
+
@socks&.each(&:close)
|
|
916
|
+
connect_socket
|
|
917
|
+
end
|
|
918
|
+
}
|
|
919
|
+
raise
|
|
877
920
|
end
|
|
878
921
|
|
|
879
922
|
def sender(msg, data, host=@host, port=@port)
|
|
@@ -884,7 +927,7 @@ class Resolv
|
|
|
884
927
|
id = DNS.allocate_request_id(@host, @port)
|
|
885
928
|
request = msg.encode
|
|
886
929
|
request[0,2] = [id].pack('n')
|
|
887
|
-
return @senders[[nil,id]] = Sender.new(request, data,
|
|
930
|
+
return @senders[[nil,id]] = Sender.new(request, data, self)
|
|
888
931
|
end
|
|
889
932
|
|
|
890
933
|
def close
|
|
@@ -899,10 +942,23 @@ class Resolv
|
|
|
899
942
|
end
|
|
900
943
|
end
|
|
901
944
|
|
|
945
|
+
private def connect_socket
|
|
946
|
+
is_ipv6 = @host.index(':')
|
|
947
|
+
sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
|
|
948
|
+
@socks = [sock]
|
|
949
|
+
sock.do_not_reverse_lookup = true
|
|
950
|
+
DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
|
|
951
|
+
sock.connect(@host, @port)
|
|
952
|
+
end
|
|
953
|
+
|
|
902
954
|
class Sender < Requester::Sender # :nodoc:
|
|
955
|
+
def initialize(msg, data, requester)
|
|
956
|
+
super(msg, data, nil)
|
|
957
|
+
@requester = requester
|
|
958
|
+
end
|
|
959
|
+
|
|
903
960
|
def send
|
|
904
|
-
|
|
905
|
-
@sock.send(@msg, 0)
|
|
961
|
+
@requester.sock.send(@msg, 0)
|
|
906
962
|
end
|
|
907
963
|
attr_reader :data
|
|
908
964
|
end
|
|
@@ -933,15 +989,32 @@ class Resolv
|
|
|
933
989
|
sock = TCPSocket.new(@host, @port)
|
|
934
990
|
@socks = [sock]
|
|
935
991
|
@senders = {}
|
|
992
|
+
@reusable = true
|
|
936
993
|
end
|
|
937
994
|
|
|
938
|
-
def
|
|
939
|
-
|
|
995
|
+
def reusable?
|
|
996
|
+
@reusable
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
def send_failed
|
|
1000
|
+
@reusable = false
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
def recv_reply(readable_socks, timelimit = nil)
|
|
1004
|
+
sock = readable_socks[0]
|
|
1005
|
+
len_data = read_exactly(sock, 2, timelimit)
|
|
940
1006
|
raise EOFError if len_data.nil? || len_data.bytesize != 2
|
|
941
1007
|
len = len_data.unpack('n')[0]
|
|
942
|
-
reply =
|
|
1008
|
+
reply = read_exactly(sock, len, timelimit)
|
|
943
1009
|
raise EOFError if reply.nil? || reply.bytesize != len
|
|
1010
|
+
@reusable = true
|
|
944
1011
|
return reply, nil
|
|
1012
|
+
rescue EOFError, SystemCallError
|
|
1013
|
+
# Whatever the kernel reported, this socket cannot be trusted for
|
|
1014
|
+
# another frame. In practice that is the peer closing or resetting;
|
|
1015
|
+
# the rest is rare enough that erring towards reconnecting is right.
|
|
1016
|
+
@reusable = false
|
|
1017
|
+
raise
|
|
945
1018
|
end
|
|
946
1019
|
|
|
947
1020
|
def sender(msg, data, host=@host, port=@port)
|
|
@@ -963,11 +1036,40 @@ class Resolv
|
|
|
963
1036
|
end
|
|
964
1037
|
|
|
965
1038
|
def close
|
|
1039
|
+
@reusable = false
|
|
966
1040
|
super
|
|
967
1041
|
@senders.each_key {|from,id|
|
|
968
1042
|
DNS.free_request_id(@host, @port, id)
|
|
969
1043
|
}
|
|
970
1044
|
end
|
|
1045
|
+
|
|
1046
|
+
private
|
|
1047
|
+
|
|
1048
|
+
# Read +len+ bytes, giving up with ResolvTimeout once +timelimit+ (a
|
|
1049
|
+
# CLOCK_MONOTONIC value) has passed. A shorter result means the peer
|
|
1050
|
+
# closed the connection, which the caller turns into an EOFError.
|
|
1051
|
+
# Consuming any byte marks the requester unusable until the whole frame
|
|
1052
|
+
# has been read, since giving up in between loses frame sync. Without a
|
|
1053
|
+
# +timelimit+ the read blocks instead and keeps no such mark; that is
|
|
1054
|
+
# only for a caller still using the one argument form of #recv_reply.
|
|
1055
|
+
def read_exactly(sock, len, timelimit)
|
|
1056
|
+
return sock.read(len) unless timelimit
|
|
1057
|
+
buf = String.new
|
|
1058
|
+
while buf.bytesize < len
|
|
1059
|
+
case chunk = sock.read_nonblock(len - buf.bytesize, exception: false)
|
|
1060
|
+
when :wait_readable
|
|
1061
|
+
remaining = timelimit - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1062
|
+
raise ResolvTimeout if remaining <= 0
|
|
1063
|
+
sock.wait_readable(remaining) or raise ResolvTimeout
|
|
1064
|
+
when nil
|
|
1065
|
+
break
|
|
1066
|
+
else
|
|
1067
|
+
@reusable = false
|
|
1068
|
+
buf << chunk
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
buf
|
|
1072
|
+
end
|
|
971
1073
|
end
|
|
972
1074
|
|
|
973
1075
|
##
|
|
@@ -1089,7 +1191,7 @@ class Resolv
|
|
|
1089
1191
|
if /\./ =~ hostname
|
|
1090
1192
|
@search = [Label.split($')]
|
|
1091
1193
|
else
|
|
1092
|
-
@search = [
|
|
1194
|
+
@search = []
|
|
1093
1195
|
end
|
|
1094
1196
|
end
|
|
1095
1197
|
|
|
@@ -1136,23 +1238,18 @@ class Resolv
|
|
|
1136
1238
|
end
|
|
1137
1239
|
|
|
1138
1240
|
def generate_candidates(name)
|
|
1139
|
-
candidates = nil
|
|
1140
1241
|
name = Name.create(name)
|
|
1141
1242
|
if name.absolute?
|
|
1142
|
-
|
|
1243
|
+
[name]
|
|
1143
1244
|
else
|
|
1245
|
+
abs = Name.new(name.to_a)
|
|
1246
|
+
search = @search.map {|domain| Name.new(name.to_a + domain)}
|
|
1144
1247
|
if @ndots <= name.length - 1
|
|
1145
|
-
|
|
1248
|
+
[abs, *search].uniq
|
|
1146
1249
|
else
|
|
1147
|
-
|
|
1148
|
-
end
|
|
1149
|
-
candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
|
|
1150
|
-
fname = Name.create("#{name}.")
|
|
1151
|
-
if !candidates.include?(fname)
|
|
1152
|
-
candidates << fname
|
|
1250
|
+
[*search, abs].uniq
|
|
1153
1251
|
end
|
|
1154
1252
|
end
|
|
1155
|
-
return candidates
|
|
1156
1253
|
end
|
|
1157
1254
|
|
|
1158
1255
|
InitialTimeout = 5
|
|
@@ -3347,7 +3444,7 @@ class Resolv
|
|
|
3347
3444
|
|
|
3348
3445
|
# Regular expression LOC size must match.
|
|
3349
3446
|
|
|
3350
|
-
Regex =
|
|
3447
|
+
Regex = /\A0*(\d{1,8}(?:\.\d+)?)m\z/
|
|
3351
3448
|
|
|
3352
3449
|
##
|
|
3353
3450
|
# Creates a new LOC::Size from +arg+ which may be:
|
|
@@ -3360,13 +3457,14 @@ class Resolv
|
|
|
3360
3457
|
when Size
|
|
3361
3458
|
return arg
|
|
3362
3459
|
when String
|
|
3363
|
-
|
|
3364
|
-
if Regex =~ arg
|
|
3365
|
-
scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C")
|
|
3366
|
-
else
|
|
3460
|
+
unless Regex =~ arg
|
|
3367
3461
|
raise ArgumentError.new("not a properly formed Size string: " + arg)
|
|
3368
3462
|
end
|
|
3369
|
-
|
|
3463
|
+
unless (0.0...1e8) === (scalar = $1.to_f)
|
|
3464
|
+
raise ArgumentError.new("out of range as Size: #{arg}")
|
|
3465
|
+
end
|
|
3466
|
+
str = (scalar * 100).to_i.to_s
|
|
3467
|
+
return new([(str[0].to_i << 4) + (str.bytesize-1)].pack("C"))
|
|
3370
3468
|
else
|
|
3371
3469
|
raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
|
|
3372
3470
|
end
|
|
@@ -3383,8 +3481,8 @@ class Resolv
|
|
|
3383
3481
|
attr_reader :scalar
|
|
3384
3482
|
|
|
3385
3483
|
def to_s # :nodoc:
|
|
3386
|
-
s = @scalar.unpack("
|
|
3387
|
-
return (
|
|
3484
|
+
s, = @scalar.unpack("C")
|
|
3485
|
+
return "#{(s >> 4) * (10.0 ** ((s & 0xf) - 2))}m"
|
|
3388
3486
|
end
|
|
3389
3487
|
|
|
3390
3488
|
def inspect # :nodoc:
|
|
@@ -3412,7 +3510,10 @@ class Resolv
|
|
|
3412
3510
|
|
|
3413
3511
|
# Regular expression LOC Coord must match.
|
|
3414
3512
|
|
|
3415
|
-
Regex =
|
|
3513
|
+
Regex = /\A0*(\d{1,3})\s([0-5]?\d)\s([0-5]?\d(?:\.\d+)?)\s([NESW])\z/
|
|
3514
|
+
|
|
3515
|
+
# Bias for the equator/prime meridian, in thousandths of a second of arc.
|
|
3516
|
+
Bias = 1 << 31
|
|
3416
3517
|
|
|
3417
3518
|
##
|
|
3418
3519
|
# Creates a new LOC::Coord from +arg+ which may be:
|
|
@@ -3425,17 +3526,19 @@ class Resolv
|
|
|
3425
3526
|
when Coord
|
|
3426
3527
|
return arg
|
|
3427
3528
|
when String
|
|
3428
|
-
|
|
3429
|
-
if Regex =~ arg && $1.to_f < 180
|
|
3430
|
-
m = $~
|
|
3431
|
-
hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1
|
|
3432
|
-
coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) +
|
|
3433
|
-
(m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N")
|
|
3434
|
-
orientation = m[4][/[NS]/] ? 'lat' : 'lon'
|
|
3435
|
-
else
|
|
3529
|
+
unless m = Regex.match(arg)
|
|
3436
3530
|
raise ArgumentError.new("not a properly formed Coord string: " + arg)
|
|
3437
3531
|
end
|
|
3438
|
-
|
|
3532
|
+
|
|
3533
|
+
arc = (m[1].to_i * 3_600_000) + (m[2].to_i * 60_000) + (m[3].to_f * 1_000).to_i
|
|
3534
|
+
dir = m[4]
|
|
3535
|
+
lat = dir[/[NS]/]
|
|
3536
|
+
unless arc <= (lat ? 324_000_000 : 648_000_000) # (lat ? 90 : 180) * 3_600_000
|
|
3537
|
+
raise ArgumentError.new("out of range as Coord: #{arg}")
|
|
3538
|
+
end
|
|
3539
|
+
|
|
3540
|
+
hemi = dir[/[NE]/] ? 1 : -1
|
|
3541
|
+
return new([arc * hemi + Bias].pack("N"), lat ? "lat" : "lon")
|
|
3439
3542
|
else
|
|
3440
3543
|
raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
|
|
3441
3544
|
end
|
|
@@ -3443,10 +3546,10 @@ class Resolv
|
|
|
3443
3546
|
|
|
3444
3547
|
# Internal use; use self.create.
|
|
3445
3548
|
def initialize(coordinates,orientation)
|
|
3446
|
-
unless coordinates.kind_of?(String)
|
|
3549
|
+
unless coordinates.kind_of?(String) and coordinates.bytesize == 4
|
|
3447
3550
|
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
|
|
3448
3551
|
end
|
|
3449
|
-
unless orientation
|
|
3552
|
+
unless orientation == "lon" || orientation == "lat"
|
|
3450
3553
|
raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
|
|
3451
3554
|
end
|
|
3452
3555
|
@coordinates = coordinates
|
|
@@ -3463,22 +3566,17 @@ class Resolv
|
|
|
3463
3566
|
attr_reader :orientation
|
|
3464
3567
|
|
|
3465
3568
|
def to_s # :nodoc:
|
|
3466
|
-
c = @coordinates.unpack("N")
|
|
3467
|
-
val
|
|
3468
|
-
fracsecs = (
|
|
3469
|
-
val
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
degs = (val / 60).to_i.to_s
|
|
3474
|
-
posi = (c >= 2**31)
|
|
3475
|
-
case posi
|
|
3476
|
-
when true
|
|
3477
|
-
hemi = @orientation[/^lat$/] ? "N" : "E"
|
|
3569
|
+
c, = @coordinates.unpack("N")
|
|
3570
|
+
val = (c -= Bias).abs
|
|
3571
|
+
val, fracsecs = val.divmod(1000)
|
|
3572
|
+
val, secs = val.divmod(60)
|
|
3573
|
+
degs, mins = val.divmod(60)
|
|
3574
|
+
hemi = if c.negative?
|
|
3575
|
+
@orientation == "lon" ? "W" : "S"
|
|
3478
3576
|
else
|
|
3479
|
-
|
|
3577
|
+
@orientation == "lat" ? "N" : "E"
|
|
3480
3578
|
end
|
|
3481
|
-
|
|
3579
|
+
format("%d %02d %02d.%03d %s", degs, mins, secs, fracsecs, hemi)
|
|
3482
3580
|
end
|
|
3483
3581
|
|
|
3484
3582
|
def inspect # :nodoc:
|
|
@@ -3506,7 +3604,10 @@ class Resolv
|
|
|
3506
3604
|
|
|
3507
3605
|
# Regular expression LOC Alt must match.
|
|
3508
3606
|
|
|
3509
|
-
Regex =
|
|
3607
|
+
Regex = /\A([+-]?0*\d{1,8}(?:\.\d+)?)m\z/
|
|
3608
|
+
|
|
3609
|
+
# Bias to a base of 100,000m below the WGS 84 reference spheroid.
|
|
3610
|
+
Bias = 100_000_00
|
|
3510
3611
|
|
|
3511
3612
|
##
|
|
3512
3613
|
# Creates a new LOC::Alt from +arg+ which may be:
|
|
@@ -3519,13 +3620,14 @@ class Resolv
|
|
|
3519
3620
|
when Alt
|
|
3520
3621
|
return arg
|
|
3521
3622
|
when String
|
|
3522
|
-
|
|
3523
|
-
if Regex =~ arg
|
|
3524
|
-
altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
|
|
3525
|
-
else
|
|
3623
|
+
unless Regex =~ arg
|
|
3526
3624
|
raise ArgumentError.new("not a properly formed Alt string: " + arg)
|
|
3527
3625
|
end
|
|
3528
|
-
|
|
3626
|
+
altitude = ($1.to_f * 100).to_i + Bias
|
|
3627
|
+
unless (0...0x1_0000_0000) === altitude
|
|
3628
|
+
raise ArgumentError.new("out of raise as Alt: #{arg}")
|
|
3629
|
+
end
|
|
3630
|
+
return new([altitude].pack("N"))
|
|
3529
3631
|
else
|
|
3530
3632
|
raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
|
|
3531
3633
|
end
|
|
@@ -3542,8 +3644,8 @@ class Resolv
|
|
|
3542
3644
|
attr_reader :altitude
|
|
3543
3645
|
|
|
3544
3646
|
def to_s # :nodoc:
|
|
3545
|
-
a = @altitude.unpack("N")
|
|
3546
|
-
return (
|
|
3647
|
+
a, = @altitude.unpack("N")
|
|
3648
|
+
return "#{(a - Bias).fdiv(100)}m"
|
|
3547
3649
|
end
|
|
3548
3650
|
|
|
3549
3651
|
def inspect # :nodoc:
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: resolv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tanaka Akira
|
|
@@ -21,6 +21,7 @@ files:
|
|
|
21
21
|
- BSDL
|
|
22
22
|
- COPYING
|
|
23
23
|
- README.md
|
|
24
|
+
- ext/win32/resolv/depend
|
|
24
25
|
- ext/win32/resolv/extconf.rb
|
|
25
26
|
- ext/win32/resolv/lib/resolv.rb
|
|
26
27
|
- ext/win32/resolv/resolv.c
|