resolv 0.7.2 → 0.8.1
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 +7 -6
- data/lib/resolv.rb +184 -76
- 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: 6d41ba56feaadbca7be99976683ea0272a2e9e87234b24d1c96a841b48c8fab8
|
|
4
|
+
data.tar.gz: 07e1a1cacdf7385307d1be4f276db467703b642a1227a3f264b62be73846d23e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a0a5b43154d5f3653de9705843b8c37205913df18dba719023b729711b32527c08544a340e73a2adf3835f5c0a0f1f6876f68ac2005c4305647a033177ac1fc
|
|
7
|
+
data.tar.gz: 3ee24cfd9b10cef67fd53e62a1cbfb9e63dd4709ec6248c9b65ffd020ec70b8eb71aa8acd39704cb068be4a6ce301709bff0cca2ff3b783f3b786965bb7422e4
|
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
|
{
|
|
@@ -246,11 +247,11 @@ InitVM_resolv(void)
|
|
|
246
247
|
|
|
247
248
|
reg_key_class = regkey;
|
|
248
249
|
rb_undef_alloc_func(regkey);
|
|
249
|
-
rb_define_private_method(singl, "get_dns_server_list", get_dns_server_list, 0);
|
|
250
|
-
rb_define_private_method(singl, "tcpip_params", tcpip_params_open, 0);
|
|
251
|
-
rb_define_method(regkey, "open", reg_open, 1);
|
|
252
|
-
rb_define_method(regkey, "each_key", reg_each_key, 0);
|
|
253
|
-
rb_define_method(regkey, "value", reg_value, 1);
|
|
250
|
+
rb_define_private_method(singl, "get_dns_server_list", RUBY_METHOD_FUNC(get_dns_server_list), 0);
|
|
251
|
+
rb_define_private_method(singl, "tcpip_params", RUBY_METHOD_FUNC(tcpip_params_open), 0);
|
|
252
|
+
rb_define_method(regkey, "open", RUBY_METHOD_FUNC(reg_open), 1);
|
|
253
|
+
rb_define_method(regkey, "each_key", RUBY_METHOD_FUNC(reg_each_key), 0);
|
|
254
|
+
rb_define_method(regkey, "value", RUBY_METHOD_FUNC(reg_value), 1);
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
void
|
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.1"
|
|
39
39
|
|
|
40
40
|
##
|
|
41
41
|
# Looks up the first IP address for +name+.
|
|
@@ -179,7 +179,7 @@ class Resolv
|
|
|
179
179
|
# Resolv::Hosts is a hostname resolver that uses the system hosts file.
|
|
180
180
|
|
|
181
181
|
class Hosts
|
|
182
|
-
if /mswin|cygwin|mingw
|
|
182
|
+
if /mswin|cygwin|mingw/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
|
|
183
183
|
begin
|
|
184
184
|
require 'win32/resolv' unless defined?(Win32::Resolv)
|
|
185
185
|
hosts = Win32::Resolv.get_hosts_path || IO::NULL
|
|
@@ -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
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
def reusable?
|
|
996
|
+
@reusable
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
def send_failed
|
|
1000
|
+
@reusable = false
|
|
936
1001
|
end
|
|
937
1002
|
|
|
938
|
-
def recv_reply(readable_socks)
|
|
939
|
-
|
|
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
|
##
|
|
@@ -1030,14 +1132,15 @@ class Resolv
|
|
|
1030
1132
|
end
|
|
1031
1133
|
|
|
1032
1134
|
def Config.default_config_hash(filename="/etc/resolv.conf")
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
elsif defined?(Win32::Resolv)
|
|
1135
|
+
# Native Windows resolves the path against the current drive, while Cygwin's own resolver honors it.
|
|
1136
|
+
if defined?(Win32::Resolv) and !(/cygwin/ =~ RUBY_PLATFORM and File.exist?(filename))
|
|
1036
1137
|
search, nameserver = Win32::Resolv.get_resolv_info
|
|
1037
1138
|
config_hash = {}
|
|
1038
1139
|
config_hash[:nameserver] = nameserver if nameserver
|
|
1039
1140
|
config_hash[:search] = [search].flatten if search
|
|
1040
1141
|
config_hash
|
|
1142
|
+
elsif File.exist? filename
|
|
1143
|
+
Config.parse_resolv_conf(filename)
|
|
1041
1144
|
else
|
|
1042
1145
|
{}
|
|
1043
1146
|
end
|
|
@@ -1089,7 +1192,7 @@ class Resolv
|
|
|
1089
1192
|
if /\./ =~ hostname
|
|
1090
1193
|
@search = [Label.split($')]
|
|
1091
1194
|
else
|
|
1092
|
-
@search = [
|
|
1195
|
+
@search = []
|
|
1093
1196
|
end
|
|
1094
1197
|
end
|
|
1095
1198
|
|
|
@@ -1136,23 +1239,18 @@ class Resolv
|
|
|
1136
1239
|
end
|
|
1137
1240
|
|
|
1138
1241
|
def generate_candidates(name)
|
|
1139
|
-
candidates = nil
|
|
1140
1242
|
name = Name.create(name)
|
|
1141
1243
|
if name.absolute?
|
|
1142
|
-
|
|
1244
|
+
[name]
|
|
1143
1245
|
else
|
|
1246
|
+
abs = Name.new(name.to_a)
|
|
1247
|
+
search = @search.map {|domain| Name.new(name.to_a + domain)}
|
|
1144
1248
|
if @ndots <= name.length - 1
|
|
1145
|
-
|
|
1249
|
+
[abs, *search].uniq
|
|
1146
1250
|
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
|
|
1251
|
+
[*search, abs].uniq
|
|
1153
1252
|
end
|
|
1154
1253
|
end
|
|
1155
|
-
return candidates
|
|
1156
1254
|
end
|
|
1157
1255
|
|
|
1158
1256
|
InitialTimeout = 5
|
|
@@ -1747,6 +1845,9 @@ class Resolv
|
|
|
1747
1845
|
# size counts the encoded form, so it starts at 1 for the root
|
|
1748
1846
|
# label's terminating zero octet. [RFC 1035 3.1]
|
|
1749
1847
|
size = 1
|
|
1848
|
+
# A pointer chain decodes to few or no labels, so the 255-octet cap
|
|
1849
|
+
# never bounds its work; cap the pointers followed per name too.
|
|
1850
|
+
pointers = 0
|
|
1750
1851
|
while true
|
|
1751
1852
|
raise DecodeError.new("limit exceeded") if @limit <= @index
|
|
1752
1853
|
case @data.getbyte(@index)
|
|
@@ -1757,6 +1858,8 @@ class Resolv
|
|
|
1757
1858
|
end
|
|
1758
1859
|
return d
|
|
1759
1860
|
when 192..255
|
|
1861
|
+
pointers += 1
|
|
1862
|
+
raise DecodeError.new("too many compression pointers") if pointers > 128
|
|
1760
1863
|
idx = self.get_unpack('n')[0] & 0x3fff
|
|
1761
1864
|
if prev_index <= idx
|
|
1762
1865
|
raise DecodeError.new("non-backward name pointer")
|
|
@@ -3347,7 +3450,7 @@ class Resolv
|
|
|
3347
3450
|
|
|
3348
3451
|
# Regular expression LOC size must match.
|
|
3349
3452
|
|
|
3350
|
-
Regex =
|
|
3453
|
+
Regex = /\A0*(\d{1,8}(?:\.\d+)?)m\z/
|
|
3351
3454
|
|
|
3352
3455
|
##
|
|
3353
3456
|
# Creates a new LOC::Size from +arg+ which may be:
|
|
@@ -3360,13 +3463,14 @@ class Resolv
|
|
|
3360
3463
|
when Size
|
|
3361
3464
|
return arg
|
|
3362
3465
|
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
|
|
3466
|
+
unless Regex =~ arg
|
|
3367
3467
|
raise ArgumentError.new("not a properly formed Size string: " + arg)
|
|
3368
3468
|
end
|
|
3369
|
-
|
|
3469
|
+
unless (0.0...1e8) === (scalar = $1.to_f)
|
|
3470
|
+
raise ArgumentError.new("out of range as Size: #{arg}")
|
|
3471
|
+
end
|
|
3472
|
+
str = (scalar * 100).to_i.to_s
|
|
3473
|
+
return new([(str[0].to_i << 4) + (str.bytesize-1)].pack("C"))
|
|
3370
3474
|
else
|
|
3371
3475
|
raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
|
|
3372
3476
|
end
|
|
@@ -3383,8 +3487,8 @@ class Resolv
|
|
|
3383
3487
|
attr_reader :scalar
|
|
3384
3488
|
|
|
3385
3489
|
def to_s # :nodoc:
|
|
3386
|
-
s = @scalar.unpack("
|
|
3387
|
-
return (
|
|
3490
|
+
s, = @scalar.unpack("C")
|
|
3491
|
+
return "#{(s >> 4) * (10.0 ** ((s & 0xf) - 2))}m"
|
|
3388
3492
|
end
|
|
3389
3493
|
|
|
3390
3494
|
def inspect # :nodoc:
|
|
@@ -3412,7 +3516,10 @@ class Resolv
|
|
|
3412
3516
|
|
|
3413
3517
|
# Regular expression LOC Coord must match.
|
|
3414
3518
|
|
|
3415
|
-
Regex =
|
|
3519
|
+
Regex = /\A0*(\d{1,3})\s([0-5]?\d)\s([0-5]?\d(?:\.\d+)?)\s([NESW])\z/
|
|
3520
|
+
|
|
3521
|
+
# Bias for the equator/prime meridian, in thousandths of a second of arc.
|
|
3522
|
+
Bias = 1 << 31
|
|
3416
3523
|
|
|
3417
3524
|
##
|
|
3418
3525
|
# Creates a new LOC::Coord from +arg+ which may be:
|
|
@@ -3425,17 +3532,19 @@ class Resolv
|
|
|
3425
3532
|
when Coord
|
|
3426
3533
|
return arg
|
|
3427
3534
|
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
|
|
3535
|
+
unless m = Regex.match(arg)
|
|
3436
3536
|
raise ArgumentError.new("not a properly formed Coord string: " + arg)
|
|
3437
3537
|
end
|
|
3438
|
-
|
|
3538
|
+
|
|
3539
|
+
arc = (m[1].to_i * 3_600_000) + (m[2].to_i * 60_000) + (m[3].to_f * 1_000).to_i
|
|
3540
|
+
dir = m[4]
|
|
3541
|
+
lat = dir[/[NS]/]
|
|
3542
|
+
unless arc <= (lat ? 324_000_000 : 648_000_000) # (lat ? 90 : 180) * 3_600_000
|
|
3543
|
+
raise ArgumentError.new("out of range as Coord: #{arg}")
|
|
3544
|
+
end
|
|
3545
|
+
|
|
3546
|
+
hemi = dir[/[NE]/] ? 1 : -1
|
|
3547
|
+
return new([arc * hemi + Bias].pack("N"), lat ? "lat" : "lon")
|
|
3439
3548
|
else
|
|
3440
3549
|
raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
|
|
3441
3550
|
end
|
|
@@ -3443,10 +3552,10 @@ class Resolv
|
|
|
3443
3552
|
|
|
3444
3553
|
# Internal use; use self.create.
|
|
3445
3554
|
def initialize(coordinates,orientation)
|
|
3446
|
-
unless coordinates.kind_of?(String)
|
|
3555
|
+
unless coordinates.kind_of?(String) and coordinates.bytesize == 4
|
|
3447
3556
|
raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
|
|
3448
3557
|
end
|
|
3449
|
-
unless orientation
|
|
3558
|
+
unless orientation == "lon" || orientation == "lat"
|
|
3450
3559
|
raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
|
|
3451
3560
|
end
|
|
3452
3561
|
@coordinates = coordinates
|
|
@@ -3463,22 +3572,17 @@ class Resolv
|
|
|
3463
3572
|
attr_reader :orientation
|
|
3464
3573
|
|
|
3465
3574
|
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"
|
|
3575
|
+
c, = @coordinates.unpack("N")
|
|
3576
|
+
val = (c -= Bias).abs
|
|
3577
|
+
val, fracsecs = val.divmod(1000)
|
|
3578
|
+
val, secs = val.divmod(60)
|
|
3579
|
+
degs, mins = val.divmod(60)
|
|
3580
|
+
hemi = if c.negative?
|
|
3581
|
+
@orientation == "lon" ? "W" : "S"
|
|
3478
3582
|
else
|
|
3479
|
-
|
|
3583
|
+
@orientation == "lat" ? "N" : "E"
|
|
3480
3584
|
end
|
|
3481
|
-
|
|
3585
|
+
format("%d %02d %02d.%03d %s", degs, mins, secs, fracsecs, hemi)
|
|
3482
3586
|
end
|
|
3483
3587
|
|
|
3484
3588
|
def inspect # :nodoc:
|
|
@@ -3506,7 +3610,10 @@ class Resolv
|
|
|
3506
3610
|
|
|
3507
3611
|
# Regular expression LOC Alt must match.
|
|
3508
3612
|
|
|
3509
|
-
Regex =
|
|
3613
|
+
Regex = /\A([+-]?0*\d{1,8}(?:\.\d+)?)m\z/
|
|
3614
|
+
|
|
3615
|
+
# Bias to a base of 100,000m below the WGS 84 reference spheroid.
|
|
3616
|
+
Bias = 100_000_00
|
|
3510
3617
|
|
|
3511
3618
|
##
|
|
3512
3619
|
# Creates a new LOC::Alt from +arg+ which may be:
|
|
@@ -3519,13 +3626,14 @@ class Resolv
|
|
|
3519
3626
|
when Alt
|
|
3520
3627
|
return arg
|
|
3521
3628
|
when String
|
|
3522
|
-
|
|
3523
|
-
if Regex =~ arg
|
|
3524
|
-
altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
|
|
3525
|
-
else
|
|
3629
|
+
unless Regex =~ arg
|
|
3526
3630
|
raise ArgumentError.new("not a properly formed Alt string: " + arg)
|
|
3527
3631
|
end
|
|
3528
|
-
|
|
3632
|
+
altitude = ($1.to_f * 100).to_i + Bias
|
|
3633
|
+
unless (0...0x1_0000_0000) === altitude
|
|
3634
|
+
raise ArgumentError.new("out of raise as Alt: #{arg}")
|
|
3635
|
+
end
|
|
3636
|
+
return new([altitude].pack("N"))
|
|
3529
3637
|
else
|
|
3530
3638
|
raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
|
|
3531
3639
|
end
|
|
@@ -3542,8 +3650,8 @@ class Resolv
|
|
|
3542
3650
|
attr_reader :altitude
|
|
3543
3651
|
|
|
3544
3652
|
def to_s # :nodoc:
|
|
3545
|
-
a = @altitude.unpack("N")
|
|
3546
|
-
return (
|
|
3653
|
+
a, = @altitude.unpack("N")
|
|
3654
|
+
return "#{(a - Bias).fdiv(100)}m"
|
|
3547
3655
|
end
|
|
3548
3656
|
|
|
3549
3657
|
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.1
|
|
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
|