にし@おかやまです。

TCPSocketでIPv4/IPv6の選択ができないのが不便に感じたので,
TCPSocket#newおよびTCPServer#newを拡張してみました。

# TCPServerの方はLinuxだとdouble bindの制限であんまり嬉しくないかも知れ
# ません。

----
* TCPSocket
TCPSocket.new('www.kame.net',80).peeraddr #=>
["AF_INET6", 80, "2001:200:0:4819:210:f3ff:fe03:4d0",
"2001:200:0:4819:210:f3ff:fe03:4d0"]

TCPSocket.new('www.kame.net',80,Socket::AF_INET).peeraddr #=>
["AF_INET", 80, "kame220.kame.net", "203.178.141.220"]

TCPSocket.new('www.kame.net',80,Socket::AF_INET6).peeraddr  #=>
["AF_INET6", 80, "apple.kame.net",
"3ffe:501:4819:2000:210:f3ff:fe03:4d0"]


* TCPServer
TCPServer.new(1500).addr #=>
["AF_INET6", 1500, "::", "::"]

TCPServer.new(1500,Socket::AF_INET).addr #=>
["AF_INET", 1500, "0.0.0.0", "0.0.0.0"]

TCPServer.new('::',1500,Socket::AF_INET6).addr #=>
["AF_INET6", 1500, "::", "::"]
----

以下,ruby 1.6.7 (2002-03-01) のext/socket/socket.cに対するパッチです。
SOCKSまわりは手抜きしてます。


--- ext/socket/socket.c.orig Wed Aug 7 03:10:52 2002 +++ ext/socket/socket.c Wed Aug 7 05:21:37 2002 @@ -784,9 +784,9 @@ } static VALUE -open_inet(class, h, serv, type) +open_inet(class, h, serv, type, ai_family) VALUE class, h, serv; - int type; + int type, ai_family; { struct addrinfo hints, *res, *res0; int fd, status; @@ -814,7 +814,7 @@ portp = pbuf; } MEMZERO(&hints, struct addrinfo, 1); - hints.ai_family = PF_UNSPEC; + hints.ai_family = ai_family; hints.ai_socktype = SOCK_STREAM; if (type == INET_SERVER) { hints.ai_flags = AI_PASSIVE; @@ -878,11 +878,24 @@ } static VALUE -tcp_s_open(class, host, serv) - VALUE class, host, serv; +tcp_s_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; { + VALUE host, serv, rb_ai_family; + int ai_family; + + if (rb_scan_args(argc, argv, "21", &host, &serv, &rb_ai_family) == 2) { + ai_family=PF_UNSPEC; + } + else{ + Check_Type(rb_ai_family, T_FIXNUM); + ai_family=FIX2INT(rb_ai_family); + } + Check_SafeStr(host); - return open_inet(class, host, serv, INET_CLIENT); + return open_inet(class, host, serv, INET_CLIENT, ai_family); } #ifdef SOCKS @@ -898,7 +911,7 @@ } Check_SafeStr(host); - return open_inet(class, host, serv, INET_SOCKS); + return open_inet(class, host, serv, INET_SOCKS, PF_UNSPEC); } #ifdef SOCKS5 @@ -1038,12 +1051,26 @@ VALUE *argv; VALUE class; { - VALUE arg1, arg2; + VALUE arg1, arg2, arg3; - if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) - return open_inet(class, arg1, arg2, INET_SERVER); - else - return open_inet(class, 0, arg1, INET_SERVER); + switch (rb_scan_args(argc, argv, "12", &arg1, &arg2, &arg3)) { + case 1: + return open_inet(class, 0, arg1, INET_SERVER, PF_UNSPEC); + break; + case 2: + if(TYPE(arg1)==T_STRING){ + return open_inet(class, arg1, arg2, INET_SERVER, PF_UNSPEC); + } + else{ + Check_Type(arg2, T_FIXNUM); + return open_inet(class, 0, arg1, INET_SERVER, FIX2INT(arg2)); + } + break; + default: + Check_Type(arg3, T_FIXNUM); + return open_inet(class, arg1, arg2, INET_SERVER, FIX2INT(arg3)); + break; + } } static VALUE @@ -2057,8 +2084,8 @@ rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket); rb_define_global_const("TCPsocket", rb_cTCPSocket); - rb_define_singleton_method(rb_cTCPSocket, "open", tcp_s_open, 2); - rb_define_singleton_method(rb_cTCPSocket, "new", tcp_s_open, 2); + rb_define_singleton_method(rb_cTCPSocket, "open", tcp_s_open, -1); + rb_define_singleton_method(rb_cTCPSocket, "new", tcp_s_open, -1); rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1); #ifdef SOCKS
-- NISHI Takao D add ninth Co.,Ltd. http://www.Dadd9.com/ 1-2-24 Toyonari, Okayama, 700-0942, Japan @@@@ Phone:+81-86-801-4216 Facsimile:+81-86-801-4217 OO/ PGP:1466 BB16 3186 CC11 1A06 713C 5518 3A2A A122 118A -|/