summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--NEWS1
-rw-r--r--ext/socket/lib/socket.rb40
-rw-r--r--test/socket/test_socket.rb17
4 files changed, 47 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 1d0f702..7eae357 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NEWS b/NEWS
index 0d2e45f..252ff4f 100644
--- a/NEWS
+++ b/NEWS
@@ -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 f83e9d6..8a5e180 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 c4d14e7..dc7a6e1 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