1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/socket/test_addrinfo.rb
Kir Shatrov 2038cc6cab
Make Socket.getaddrinfo interruptible (#2827)
Before, Socket.getaddrinfo was using a blocking getaddrinfo(3) call.
That didn't allow to wrap it into Timeout.timeout or interrupt the thread in any way.

Combined with the default 10 sec resolv timeout on many Unix systems, this can
have a very noticeable effect on production Ruby apps being not
resilient to DNS outages and timing out name resolution, and being unable to fail fast even
with Timeout.timeout.

Since we already have support for getaddrinfo_a(3), the async version
of getaddrinfo, we should be able to make Socket.getaddrinfo leverage that
when getaddrinfo_a version is available in the system (hence #ifdef
HAVE_GETADDRINFO_A).

Related tickets:
https://bugs.ruby-lang.org/issues/16476
https://bugs.ruby-lang.org/issues/16381
https://bugs.ruby-lang.org/issues/14997
2020-08-27 16:39:13 +09:00

699 lines
22 KiB
Ruby

# frozen_string_literal: true
begin
require "socket"
rescue LoadError
end
require "test/unit"
class TestSocketAddrinfo < Test::Unit::TestCase
HAS_UNIXSOCKET = defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM
def tcp_unspecified_to_loopback(addrinfo)
if addrinfo.ipv4? && addrinfo.ip_address == "0.0.0.0"
Addrinfo.tcp("127.0.0.1", addrinfo.ip_port)
elsif addrinfo.ipv6? && addrinfo.ipv6_unspecified?
Addrinfo.tcp("::1", addrinfo.ip_port)
elsif addrinfo.ipv6? && (ai = addrinfo.ipv6_to_ipv4) && ai.ip_address == "0.0.0.0"
Addrinfo.tcp("127.0.0.1", addrinfo.ip_port)
else
addrinfo
end
end
def test_addrinfo_ip
ai = Addrinfo.ip("127.0.0.1")
assert_equal([0, "127.0.0.1"], Socket.unpack_sockaddr_in(ai))
assert_equal(Socket::AF_INET, ai.afamily)
assert_equal(Socket::PF_INET, ai.pfamily)
assert_equal(0, ai.socktype)
assert_equal(0, ai.protocol)
ai = Addrinfo.ip("<any>")
assert_equal([0, "0.0.0.0"], Socket.unpack_sockaddr_in(ai))
ai = Addrinfo.ip("<broadcast>")
assert_equal([0, "255.255.255.255"], Socket.unpack_sockaddr_in(ai))
ai = assert_nothing_raised(SocketError) do
base_str = "127.0.0.1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
addr = base_str[0, 9]
Addrinfo.ip(addr)
end
assert_equal([0, "127.0.0.1"], Socket.unpack_sockaddr_in(ai))
assert_raise(ArgumentError) do
Addrinfo.ip("127.0.0.1\000x")
end
end
def test_addrinfo_tcp
ai = Addrinfo.tcp("127.0.0.1", 80)
assert_equal([80, "127.0.0.1"], Socket.unpack_sockaddr_in(ai))
assert_equal(Socket::AF_INET, ai.afamily)
assert_equal(Socket::PF_INET, ai.pfamily)
assert_equal(Socket::SOCK_STREAM, ai.socktype)
assert_include([0, Socket::IPPROTO_TCP], ai.protocol)
ai = assert_nothing_raised(SocketError) do
Addrinfo.tcp("127.0.0.1", "0000000000000000000000080x".chop)
end
assert_equal([80, "127.0.0.1"], Socket.unpack_sockaddr_in(ai))
assert_raise(ArgumentError) do
Addrinfo.ip("127.0.0.1", "80\000x")
end
end
def test_addrinfo_udp
ai = Addrinfo.udp("127.0.0.1", 80)
assert_equal([80, "127.0.0.1"], Socket.unpack_sockaddr_in(ai))
assert_equal(Socket::AF_INET, ai.afamily)
assert_equal(Socket::PF_INET, ai.pfamily)
assert_equal(Socket::SOCK_DGRAM, ai.socktype)
assert_include([0, Socket::IPPROTO_UDP], ai.protocol)
end
def test_addrinfo_ip_unpack
ai = Addrinfo.tcp("127.0.0.1", 80)
assert_equal(["127.0.0.1", 80], ai.ip_unpack)
assert_equal("127.0.0.1", ai.ip_address)
assert_equal(80, ai.ip_port)
end
def test_addrinfo_inspect_sockaddr
ai = Addrinfo.tcp("127.0.0.1", 80)
assert_equal("127.0.0.1:80", ai.inspect_sockaddr)
end
def test_addrinfo_new_inet
ai = Addrinfo.new(["AF_INET", 46102, "localhost.localdomain", "127.0.0.2"])
assert_equal([46102, "127.0.0.2"], Socket.unpack_sockaddr_in(ai))
assert_equal(Socket::AF_INET, ai.afamily)
assert_equal(Socket::PF_INET, ai.pfamily)
assert_equal(0, ai.socktype)
assert_equal(0, ai.protocol)
end
def test_addrinfo_predicates
ipv4_ai = Addrinfo.new(Socket.sockaddr_in(80, "192.168.0.1"))
assert(ipv4_ai.ip?)
assert(ipv4_ai.ipv4?)
assert(!ipv4_ai.ipv6?)
assert(!ipv4_ai.unix?)
end
def test_error_message
e = assert_raise_with_message(SocketError, /getaddrinfo/) do
Addrinfo.ip("...")
end
m = e.message
assert_not_equal([false, Encoding::ASCII_8BIT], [m.ascii_only?, m.encoding], proc {m.inspect})
end
def test_ipv4_address_predicates
list = [
[:ipv4_private?, "10.0.0.0", "10.255.255.255",
"172.16.0.0", "172.31.255.255",
"192.168.0.0", "192.168.255.255"],
[:ipv4_loopback?, "127.0.0.1", "127.0.0.0", "127.255.255.255"],
[:ipv4_multicast?, "224.0.0.0", "224.255.255.255"]
]
list.each {|meth, *addrs|
addrs.each {|addr|
assert(Addrinfo.ip(addr).send(meth), "Addrinfo.ip(#{addr.inspect}).#{meth}")
list.each {|meth2,|
next if meth == meth2
assert(!Addrinfo.ip(addr).send(meth2), "!Addrinfo.ip(#{addr.inspect}).#{meth2}")
}
}
}
end
def test_basicsocket_send
s1 = Socket.new(:INET, :DGRAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
sa = s1.getsockname
ai = Addrinfo.new(sa)
s2 = Socket.new(:INET, :DGRAM, 0)
s2.send("test-basicsocket-send", 0, ai)
assert_equal("test-basicsocket-send", s1.recv(100))
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
end
def test_udpsocket_send
s1 = UDPSocket.new
s1.bind("127.0.0.1", 0)
ai = Addrinfo.new(s1.getsockname)
s2 = UDPSocket.new
s2.send("test-udp-send", 0, ai)
assert_equal("test-udp-send", s1.recv(100))
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
end
def test_socket_bind
s1 = Socket.new(:INET, :DGRAM, 0)
sa = Socket.sockaddr_in(0, "127.0.0.1")
ai = Addrinfo.new(sa)
s1.bind(ai)
s2 = UDPSocket.new
s2.send("test-socket-bind", 0, s1.getsockname)
assert_equal("test-socket-bind", s1.recv(100))
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
end
def test_socket_connect
s1 = Socket.new(:INET, :STREAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s1.listen(5)
ai = Addrinfo.new(s1.getsockname)
s2 = Socket.new(:INET, :STREAM, 0)
s2.connect(ai)
s3, _ = s1.accept
s2.send("test-socket-connect", 0)
assert_equal("test-socket-connect", s3.recv(100))
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
s3.close if s3 && !s3.closed?
end
def test_socket_connect_nonblock
s1 = Socket.new(:INET, :STREAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s1.listen(5)
ai = Addrinfo.new(s1.getsockname)
s2 = Socket.new(:INET, :STREAM, 0)
begin
s2.connect_nonblock(ai)
rescue IO::WaitWritable
IO.select(nil, [s2])
r = s2.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
assert_equal(0, r.int, "NOERROR is expected but #{r.inspect}")
begin
s2.connect_nonblock(ai)
rescue Errno::EISCONN
end
end
s3, _ = s1.accept
s2.send("test-socket-connect-nonblock", 0)
assert_equal("test-socket-connect-nonblock", s3.recv(100))
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
s3.close if s3 && !s3.closed?
end
def test_socket_getnameinfo
ai = Addrinfo.udp("127.0.0.1", 8888)
assert_equal(["127.0.0.1", "8888"], Socket.getnameinfo(ai, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV))
end
def test_basicsocket_local_address
s1 = Socket.new(:INET, :DGRAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
e = Socket.unpack_sockaddr_in(s1.getsockname)
a = Socket.unpack_sockaddr_in(s1.local_address.to_sockaddr)
assert_equal(e, a)
assert_equal(Socket::AF_INET, s1.local_address.afamily)
assert_equal(Socket::PF_INET, s1.local_address.pfamily)
assert_equal(Socket::SOCK_DGRAM, s1.local_address.socktype)
ensure
s1.close if s1 && !s1.closed?
end
def test_basicsocket_remote_address
s1 = TCPServer.new("127.0.0.1", 0)
s2 = Socket.new(:INET, :STREAM, 0)
s2.connect(s1.getsockname)
s3, _ = s1.accept
e = Socket.unpack_sockaddr_in(s2.getsockname)
a = Socket.unpack_sockaddr_in(s3.remote_address.to_sockaddr)
assert_equal(e, a)
assert_equal(Socket::AF_INET, s3.remote_address.afamily)
assert_equal(Socket::PF_INET, s3.remote_address.pfamily)
assert_equal(Socket::SOCK_STREAM, s3.remote_address.socktype)
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
s3.close if s3 && !s3.closed?
end
def test_socket_accept
serv = Socket.new(:INET, :STREAM, 0)
serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
serv.listen(5)
c = Socket.new(:INET, :STREAM, 0)
c.connect(serv.local_address)
ret = serv.accept
s, ai = ret
assert_kind_of(Array, ret)
assert_equal(2, ret.length)
assert_kind_of(Addrinfo, ai)
e = Socket.unpack_sockaddr_in(c.getsockname)
a = Socket.unpack_sockaddr_in(ai.to_sockaddr)
assert_equal(e, a)
ensure
serv.close if serv && !serv.closed?
s.close if s && !s.closed?
c.close if c && !c.closed?
end
def test_socket_accept_nonblock
serv = Socket.new(:INET, :STREAM, 0)
serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
serv.listen(5)
c = Socket.new(:INET, :STREAM, 0)
c.connect(serv.local_address)
begin
ret = serv.accept_nonblock
rescue IO::WaitReadable, Errno::EINTR
IO.select([serv])
retry
end
s, ai = ret
assert_kind_of(Array, ret)
assert_equal(2, ret.length)
assert_kind_of(Addrinfo, ai)
e = Socket.unpack_sockaddr_in(c.getsockname)
a = Socket.unpack_sockaddr_in(ai.to_sockaddr)
assert_equal(e, a)
ensure
serv.close if serv && !serv.closed?
s.close if s && !s.closed?
c.close if c && !c.closed?
end
def test_socket_sysaccept
serv = Socket.new(:INET, :STREAM, 0)
serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
serv.listen(5)
c = Socket.new(:INET, :STREAM, 0)
c.connect(serv.local_address)
ret = serv.sysaccept
fd, ai = ret
s = IO.new(fd)
assert_kind_of(Array, ret)
assert_equal(2, ret.length)
assert_kind_of(Addrinfo, ai)
e = Socket.unpack_sockaddr_in(c.getsockname)
a = Socket.unpack_sockaddr_in(ai.to_sockaddr)
assert_equal(e, a)
ensure
serv.close if serv && !serv.closed?
s.close if s && !s.closed?
c.close if c && !c.closed?
end
def test_socket_recvfrom
s1 = Socket.new(:INET, :DGRAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s2 = Socket.new(:INET, :DGRAM, 0)
s2.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s2.send("test-socket-recvfrom", 0, s1.getsockname)
data, ai = s1.recvfrom(100)
assert_equal("test-socket-recvfrom", data)
assert_kind_of(Addrinfo, ai)
e = Socket.unpack_sockaddr_in(s2.getsockname)
a = Socket.unpack_sockaddr_in(ai.to_sockaddr)
assert_equal(e, a)
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
end
def test_socket_recvfrom_nonblock
s1 = Socket.new(:INET, :DGRAM, 0)
s1.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s2 = Socket.new(:INET, :DGRAM, 0)
s2.bind(Socket.sockaddr_in(0, "127.0.0.1"))
s2.send("test-socket-recvfrom", 0, s1.getsockname)
begin
data, ai = s1.recvfrom_nonblock(100)
rescue IO::WaitReadable
IO.select([s1])
retry
end
assert_equal("test-socket-recvfrom", data)
assert_kind_of(Addrinfo, ai)
e = Socket.unpack_sockaddr_in(s2.getsockname)
a = Socket.unpack_sockaddr_in(ai.to_sockaddr)
assert_equal(e, a)
ensure
s1.close if s1 && !s1.closed?
s2.close if s2 && !s2.closed?
end
def test_family_addrinfo
ai = Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("127.0.0.1", 80)
assert_equal(["127.0.0.1", 80], ai.ip_unpack)
assert_equal(Socket::SOCK_STREAM, ai.socktype)
return unless Addrinfo.respond_to?(:unix)
ai = Addrinfo.unix("/testdir/sock").family_addrinfo("/testdir/sock2")
assert_equal("/testdir/sock2", ai.unix_path)
assert_equal(Socket::SOCK_STREAM, ai.socktype)
assert_raise(SocketError) { Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("::1", 80) }
end
def random_port
# IANA suggests dynamic port for 49152 to 65535
# http://www.iana.org/assignments/port-numbers
49152 + rand(65535-49152+1)
end
def errors_addrinuse
errs = [Errno::EADDRINUSE]
# MinGW fails with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721"
errs << Errno::EACCES if /mingw/ =~ RUBY_PLATFORM
errs
end
def test_connect_from
TCPServer.open("0.0.0.0", 0) {|serv|
serv_ai = Addrinfo.new(serv.getsockname, :INET, :STREAM)
serv_ai = tcp_unspecified_to_loopback(serv_ai)
port = random_port
begin
serv_ai.connect_from("0.0.0.0", port) {|s1|
s2 = serv.accept
begin
assert_equal(port, s2.remote_address.ip_port)
ensure
s2.close
end
}
rescue *errors_addrinuse
# not test failure
end
}
TCPServer.open("0.0.0.0", 0) {|serv|
serv_ai = Addrinfo.new(serv.getsockname, :INET, :STREAM)
serv_ai = tcp_unspecified_to_loopback(serv_ai)
port = random_port
begin
serv_ai.connect_from(Addrinfo.tcp("0.0.0.0", port)) {|s1|
s2 = serv.accept
begin
assert_equal(port, s2.remote_address.ip_port)
ensure
s2.close
end
}
rescue *errors_addrinuse
# not test failure
end
}
end
def test_connect_to
TCPServer.open("0.0.0.0", 0) {|serv|
serv_ai = Addrinfo.new(serv.getsockname, :INET, :STREAM)
serv_ai = tcp_unspecified_to_loopback(serv_ai)
port = random_port
client_ai = Addrinfo.tcp("0.0.0.0", port)
begin
client_ai.connect_to(*serv_ai.ip_unpack) {|s1|
s2 = serv.accept
begin
assert_equal(port, s2.remote_address.ip_port)
ensure
s2.close
end
}
rescue *errors_addrinuse
# not test failure
end
}
end
def test_connect
TCPServer.open("0.0.0.0", 0) {|serv|
serv_ai = Addrinfo.new(serv.getsockname, :INET, :STREAM)
serv_ai = tcp_unspecified_to_loopback(serv_ai)
begin
serv_ai.connect {|s1|
s2 = serv.accept
begin
assert_equal(s1.local_address.ip_unpack, s2.remote_address.ip_unpack)
assert_equal(s2.local_address.ip_unpack, s1.remote_address.ip_unpack)
ensure
s2.close
end
}
rescue *errors_addrinuse
# not test failure
end
}
end
def test_bind
port = random_port
client_ai = Addrinfo.tcp("0.0.0.0", port)
begin
client_ai.bind {|s|
assert_equal(port, s.local_address.ip_port)
}
rescue *errors_addrinuse
# not test failure
end
end
def test_listen
port = random_port
client_ai = Addrinfo.tcp("0.0.0.0", port)
begin
client_ai.listen {|serv|
assert_equal(port, serv.local_address.ip_port)
serv_addr, serv_port = serv.local_address.ip_unpack
case serv_addr
when "0.0.0.0" then serv_addr = "127.0.0.1"
end
TCPSocket.open(serv_addr, serv_port) {|s1|
s2, addr = serv.accept
begin
assert_equal(s1.local_address.ip_unpack, addr.ip_unpack)
ensure
s2.close
end
}
}
rescue *errors_addrinuse
# not test failure
end
end
def test_s_foreach
Addrinfo.foreach(nil, 80, nil, :STREAM) {|ai|
assert_kind_of(Addrinfo, ai)
}
end
def test_marshal
ai1 = Addrinfo.tcp("127.0.0.1", 80)
ai2 = Marshal.load(Marshal.dump(ai1))
assert_equal(ai1.afamily, ai2.afamily)
assert_equal(ai1.ip_unpack, ai2.ip_unpack)
assert_equal(ai1.pfamily, ai2.pfamily)
assert_equal(ai1.socktype, ai2.socktype)
assert_equal(ai1.protocol, ai2.protocol)
assert_equal(ai1.canonname, ai2.canonname)
end
def test_marshal_memory_leak
bug11051 = '[ruby-dev:48923] [Bug #11051]'
assert_no_memory_leak(%w[-rsocket], <<-PREP, <<-CODE, bug11051, rss: true)
d = Marshal.dump(Addrinfo.tcp("127.0.0.1", 80))
1000.times {Marshal.load(d)}
PREP
GC.start
20_000.times {Marshal.load(d)}
CODE
end
if Socket.const_defined?("AF_INET6") && Socket::AF_INET6.is_a?(Integer)
def test_addrinfo_new_inet6
ai = Addrinfo.new(["AF_INET6", 42304, "ip6-localhost", "::1"])
assert_equal([42304, "::1"], Socket.unpack_sockaddr_in(ai))
assert_equal(Socket::AF_INET6, ai.afamily)
assert_equal(Socket::PF_INET6, ai.pfamily)
assert_equal(0, ai.socktype)
assert_equal(0, ai.protocol)
end
def test_addrinfo_ip_unpack_inet6
ai = Addrinfo.tcp("::1", 80)
assert_equal(["::1", 80], ai.ip_unpack)
assert_equal("::1", ai.ip_address)
assert_equal(80, ai.ip_port)
end
def test_addrinfo_inspect_sockaddr_inet6
ai = Addrinfo.tcp("::1", 80)
assert_equal("[::1]:80", ai.inspect_sockaddr)
end
def test_marshal_inet6
ai1 = Addrinfo.tcp("::1", 80)
ai2 = Marshal.load(Marshal.dump(ai1))
assert_equal(ai1.afamily, ai2.afamily)
assert_equal(ai1.ip_unpack, ai2.ip_unpack)
assert_equal(ai1.pfamily, ai2.pfamily)
assert_equal(ai1.socktype, ai2.socktype)
assert_equal(ai1.protocol, ai2.protocol)
assert_equal(ai1.canonname, ai2.canonname)
end
def ipv6(str)
Addrinfo.getaddrinfo(str, nil, :INET6, :DGRAM).fetch(0)
end
def test_ipv6_address_predicates
list = [
[:ipv6_unspecified?, "::"],
[:ipv6_loopback?, "::1"],
[:ipv6_v4compat?, "::0.0.0.2", "::255.255.255.255"],
[:ipv6_v4mapped?, "::ffff:0.0.0.0", "::ffff:255.255.255.255"],
[:ipv6_linklocal?, "fe80::", "febf::"],
[:ipv6_sitelocal?, "fec0::", "feef::"],
[:ipv6_multicast?, "ff00::", "ffff::"],
[:ipv6_unique_local?, "fc00::", "fd00::"],
]
mlist = [
[:ipv6_mc_nodelocal?, "ff01::", "ff11::"],
[:ipv6_mc_linklocal?, "ff02::", "ff12::"],
[:ipv6_mc_sitelocal?, "ff05::", "ff15::"],
[:ipv6_mc_orglocal?, "ff08::", "ff18::"],
[:ipv6_mc_global?, "ff0e::", "ff1e::"]
]
list.each {|meth, *addrs|
addrs.each {|addr|
addr_exp = "Addrinfo.getaddrinfo(#{addr.inspect}, nil, :INET6, :DGRAM).fetch(0)"
if meth == :ipv6_v4compat? || meth == :ipv6_v4mapped?
# MacOS X returns IPv4 address for ::ffff:1.2.3.4 and ::1.2.3.4.
# Solaris returns IPv4 address for ::ffff:1.2.3.4.
ai = ipv6(addr)
begin
assert(ai.ipv4? || ai.send(meth), "ai=#{addr_exp}; ai.ipv4? || .#{meth}")
rescue Minitest::Assertion
if /aix/ =~ RUBY_PLATFORM
skip "Known bug in IN6_IS_ADDR_V4COMPAT and IN6_IS_ADDR_V4MAPPED on AIX"
end
raise $!
end
else
assert(ipv6(addr).send(meth), "#{addr_exp}.#{meth}")
assert_equal(addr, ipv6(addr).ip_address)
end
list.each {|meth2,|
next if meth == meth2
assert(!ipv6(addr).send(meth2), "!#{addr_exp}.#{meth2}")
}
}
}
mlist.each {|meth, *addrs|
addrs.each {|addr|
addr_exp = "Addrinfo.getaddrinfo(#{addr.inspect}, nil, :INET6, :DGRAM).fetch(0)"
assert(ipv6(addr).send(meth), "#{addr_exp}.#{meth}")
assert(ipv6(addr).ipv6_multicast?, "#{addr_exp}.ipv6_multicast?")
mlist.each {|meth2,|
next if meth == meth2
assert(!ipv6(addr).send(meth2), "!#{addr_exp}.#{meth2}")
}
list.each {|meth2,|
next if :ipv6_multicast? == meth2
assert(!ipv6(addr).send(meth2), "!#{addr_exp}.#{meth2}")
}
}
}
end
def test_ipv6_to_ipv4
ai = Addrinfo.ip("::192.0.2.3")
ai = ai.ipv6_to_ipv4 if !ai.ipv4?
assert(ai.ipv4?)
assert_equal("192.0.2.3", ai.ip_address)
ai = Addrinfo.ip("::ffff:192.0.2.3")
ai = ai.ipv6_to_ipv4 if !ai.ipv4?
assert(ai.ipv4?)
assert_equal("192.0.2.3", ai.ip_address)
assert_nil(Addrinfo.ip("::1").ipv6_to_ipv4)
assert_nil(Addrinfo.ip("192.0.2.3").ipv6_to_ipv4)
if HAS_UNIXSOCKET
assert_nil(Addrinfo.unix("/testdir/sock").ipv6_to_ipv4)
end
end
end
if HAS_UNIXSOCKET
def test_addrinfo_unix
ai = Addrinfo.unix("/testdir/sock")
assert_equal("/testdir/sock", Socket.unpack_sockaddr_un(ai))
assert_equal(Socket::AF_UNIX, ai.afamily)
assert_equal(Socket::PF_UNIX, ai.pfamily)
assert_equal(Socket::SOCK_STREAM, ai.socktype)
assert_equal(0, ai.protocol)
end
def test_addrinfo_unix_dgram
ai = Addrinfo.unix("/testdir/sock", :DGRAM)
assert_equal("/testdir/sock", Socket.unpack_sockaddr_un(ai))
assert_equal(Socket::AF_UNIX, ai.afamily)
assert_equal(Socket::PF_UNIX, ai.pfamily)
assert_equal(Socket::SOCK_DGRAM, ai.socktype)
assert_equal(0, ai.protocol)
end
def test_addrinfo_unix_path
ai = Addrinfo.unix("/testdir/sock1")
assert_equal("/testdir/sock1", ai.unix_path)
end
def test_addrinfo_inspect_sockaddr_unix
ai = Addrinfo.unix("/testdir/test_addrinfo_inspect_sockaddr_unix")
assert_equal("/testdir/test_addrinfo_inspect_sockaddr_unix", ai.inspect_sockaddr)
end
def test_addrinfo_new_unix
ai = Addrinfo.new(["AF_UNIX", "/testdir/sock"])
assert_equal("/testdir/sock", Socket.unpack_sockaddr_un(ai))
assert_equal(Socket::AF_UNIX, ai.afamily)
assert_equal(Socket::PF_UNIX, ai.pfamily)
assert_equal(Socket::SOCK_STREAM, ai.socktype) # UNIXSocket/UNIXServer is SOCK_STREAM only.
assert_equal(0, ai.protocol)
end
def test_addrinfo_predicates_unix
unix_ai = Addrinfo.new(Socket.sockaddr_un("/testdir/sososo"))
assert(!unix_ai.ip?)
assert(!unix_ai.ipv4?)
assert(!unix_ai.ipv6?)
assert(unix_ai.unix?)
end
def test_marshal_unix
ai1 = Addrinfo.unix("/testdir/sock")
ai2 = Marshal.load(Marshal.dump(ai1))
assert_equal(ai1.afamily, ai2.afamily)
assert_equal(ai1.unix_path, ai2.unix_path)
assert_equal(ai1.pfamily, ai2.pfamily)
assert_equal(ai1.socktype, ai2.socktype)
assert_equal(ai1.protocol, ai2.protocol)
assert_equal(ai1.canonname, ai2.canonname)
end
def test_addrinfo_timeout
ai = Addrinfo.getaddrinfo("localhost", "ssh", Socket::PF_INET, Socket::SOCK_STREAM, timeout: 1).fetch(0)
assert_equal(22, ai.ip_port)
end
end
end