diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-03 07:25:57 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-03 07:25:57 +0000 |
commit | 24eafe83763c2c71efdd9b8198d45c0cb1af4b7c (patch) | |
tree | c8f31330f1d0591357c9214e9281ae6201baaa13 /ext/socket/lib/socket.rb | |
parent | 260d0d0399f902e9c079b3447d67957678c461c5 (diff) | |
download | ruby-24eafe83763c2c71efdd9b8198d45c0cb1af4b7c.tar.gz |
* ext/socket/lib/socket.rb (Socket.tcp_server_sockets_port0): new
private function for allocating same port both IPv4 and IPv6.
(Socket.tcp_server_sockets): use tcp_server_sockets_port0 for port 0.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/socket/lib/socket.rb')
-rw-r--r-- | ext/socket/lib/socket.rb | 86 |
1 files changed, 67 insertions, 19 deletions
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index 577abca010..c9b70433c1 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -226,11 +226,50 @@ class Socket end end + def self.tcp_server_sockets_port0(host) + ai_list = AddrInfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE) + begin + sockets = [] + port = nil + ai_list.each {|ai| + s = Socket.new(ai.pfamily, ai.socktype, ai.protocol) + sockets << s + s.ipv6only! if ai.ipv6? + s.setsockopt(:SOCKET, :REUSEADDR, 1) + if !port + s.bind(ai) + port = s.local_address.ip_port + else + s.bind(AddrInfo.tcp(ai.ip_address, port)) + end + s.listen(5) + } + rescue Errno::EADDRINUSE + sockets.each {|s| + s.close + } + retry + end + sockets + ensure + if $! + sockets.each {|s| + s.close if !s.closed? + } + end + end + class << self + private :tcp_server_sockets_port0 + end + # creates TCP server sockets for _host_ and _port_. # _host_ is optional. # # It returns an array of listening sockets. # + # If _port_ is 0, actual port number is choosen dynamically. + # However all sockets in the result has same port number. + # # # tcp_server_sockets returns two sockets. # sockets = Socket.tcp_server_sockets(1296) # p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>] @@ -240,27 +279,36 @@ class Socket # #=> #<AddrInfo: [::]:1296 TCP> # # #<AddrInfo: 0.0.0.0:1296 TCP> # + # # IPv6 and IPv4 socket has same port number, 53114, even if it is choosen dynamically. + # sockets = Socket.tcp_server_sockets(0) + # sockets.each {|s| p s.local_address } + # #=> #<AddrInfo: [::]:53114 TCP> + # # #<AddrInfo: 0.0.0.0:53114 TCP> + # def self.tcp_server_sockets(host=nil, port) - last_error = nil - sockets = [] - AddrInfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai| - begin - s = ai.listen - rescue SystemCallError - last_error = $! - next - end - sockets << s - } - if sockets.empty? - raise last_error - end - sockets - ensure - if $! - sockets.each {|s| - s.close if !s.closed? + return tcp_server_sockets_port0(host) if port == 0 + begin + last_error = nil + sockets = [] + AddrInfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai| + begin + s = ai.listen + rescue SystemCallError + last_error = $! + next + end + sockets << s } + if sockets.empty? + raise last_error + end + sockets + ensure + if $! + sockets.each {|s| + s.close if !s.closed? + } + end end end |