diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | ext/socket/lib/socket.rb | 40 | ||||
-rw-r--r-- | test/socket/test_socket.rb | 17 |
4 files changed, 47 insertions, 15 deletions
@@ -1,3 +1,7 @@ +Thu Feb 26 23:14:46 2009 Tanaka Akira <akr@fsij.org> + + * ext/socket/lib/socket.rb (BasicSocket#connect_address): new method. + Thu Feb 26 19:29:10 2009 Nobuyoshi Nakada <nobu@ruby-lang.org> * hash.c (hash_foreach_iter): fix for prototype. @@ -112,6 +112,7 @@ with all sufficient information, see the ChangeLog file. * Socket#ipv6only! * BasicSocket#local_address * BasicSocket#remote_address + * BasicSocket#connect_address * BasicSocket#sendmsg * BasicSocket#sendmsg_nonblock * BasicSocket#recvmsg diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index f83e9d6e0..8a5e180f5 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -158,6 +158,46 @@ class Addrinfo end end +class BasicSocket + # Returns an address of the socket suitable for connect. + # + # This method returns _self_.local_address, except following condition. + # + # - IPv4 unspecified address (0.0.0.0) is replaced by IPv4 loopback address (127.0.0.1). + # - IPv6 unspecified address (::) is replaced by IPv6 loopback address (::1). + # + # If the local address is not suitable for connect, SocketError is raised. + # IPv4 and IPv6 address which port is 0 is not suitable for connect. + # Unix domain socket which has no path is not suitable for connect. + # + # Addrinfo.tcp("0.0.0.0", 0).listen {|serv| + # p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP> + # serv.connect_address.connect {|c| + # s, _ = serv.accept + # p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>] + # } + # } + # + def connect_address + addr = local_address + afamily = addr.afamily + if afamily == Socket::AF_INET + raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0 + if addr.ip_address == "0.0.0.0" + addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol) + end + elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6 + raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0 + if addr.ip_address == "::" + addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol) + end + elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX + raise SocketError, "unbound Unix socket" if addr.unix_path == "" + end + addr + end +end + class Socket # enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available. def ipv6only! diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index c4d14e7f3..dc7a6e112 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -73,22 +73,9 @@ class TestSocket < Test::Unit::TestCase } end - 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_tcp TCPServer.open(0) {|serv| - addr = serv.local_address - addr = tcp_unspecified_to_loopback(addr) + addr = serv.connect_address addr.connect {|s1| s2 = serv.accept begin @@ -185,7 +172,7 @@ class TestSocket < Test::Unit::TestCase tcp_servers = Socket.tcp_server_sockets(0) unix_server = Socket.unix_server_socket("#{tmpdir}/sock") tcp_servers.each {|s| - addr = tcp_unspecified_to_loopback(s.local_address) + addr = s.connect_address clients << addr.connect } clients << unix_server.local_address.connect |