From 73757753aef81b97b69a82ccbbcdd7fcfafc6e16 Mon Sep 17 00:00:00 2001 From: akr Date: Mon, 12 Jan 2009 14:58:25 +0000 Subject: [PATCH] * ext/socket/socket.c (addrinfo_ip_unpack): new method AddrInfo#ip_unpack. (addrinfo_unix_path): new method AddrInfo#unix_path. (Init_socket): define above methods. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 ++++ ext/socket/socket.c | 67 +++++++++++++++++++++++++++++++++++- test/socket/test_addrinfo.rb | 15 ++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f244c689ee..cd5a228699 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Mon Jan 12 23:55:19 2009 Tanaka Akira + + * ext/socket/socket.c (addrinfo_ip_unpack): new method + AddrInfo#ip_unpack. + (addrinfo_unix_path): new method AddrInfo#unix_path. + (Init_socket): define above methods. + Mon Jan 12 23:31:42 2009 Tanaka Akira * ext/socket/socket.c (IS_IP_FAMILY): defined. diff --git a/ext/socket/socket.c b/ext/socket/socket.c index afec72e59a..b161f038f6 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -5237,6 +5237,67 @@ addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self) return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); } +/* + * call-seq: + * addrinfo.ip_unpack => [addr, port] + * + * Returns the IP address and port number as 2-element array. + * + * AddrInfo.tcp("127.0.0.1", 80).ip_unpack #=> ["127.0.0.1", 80] + * AddrInfo.tcp("::1", 80).ip_unpack #=> ["::1", 80] + */ +static VALUE +addrinfo_ip_unpack(VALUE self) +{ + rb_addrinfo_t *rai = get_addrinfo(self); + int family = ai_get_afamily(rai); + VALUE vflags; + VALUE ret, portstr; + + if (!IS_IP_FAMILY(family)) + rb_raise(rb_eSocket, "need IPv4 or IPv6 address"); + + vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV); + ret = addrinfo_getnameinfo(1, &vflags, self); + portstr = rb_ary_entry(ret, 1); + rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr)))); + return ret; +} + +#ifdef HAVE_SYS_UN_H +/* + * call-seq: + * addrinfo.unix_path => path + * + * Returns the socket path as a string. + * + * AddrInfo.unix("/tmp/sock").unix_path #=> "/tmp/sock" + */ +static VALUE +addrinfo_unix_path(VALUE self) +{ + rb_addrinfo_t *rai = get_addrinfo(self); + int family = ai_get_afamily(rai); + struct sockaddr_un *addr; + char *s, *e; + + if (family != AF_UNIX) + rb_raise(rb_eSocket, "need AF_UNIX address"); + + addr = (struct sockaddr_un *)&rai->addr; + + s = addr->sun_path; + e = (char*)addr + rai->sockaddr_len; + if (e < s) + rb_raise(rb_eSocket, "too short AF_UNIX address"); + if (addr->sun_path + sizeof(addr->sun_path) < e) + rb_raise(rb_eSocket, "too long AF_UNIX address"); + while (s < e && *(e-1) == '\0') + e--; + return rb_str_new(s, e-s); +} +#endif + /* * call-seq: * AddrInfo.getaddrinfo(nodename, service, family, socktype, protocol, flags) => [addrinfo, ...] @@ -5521,10 +5582,14 @@ Init_socket() rb_define_method(rb_cAddrInfo, "protocol", addrinfo_protocol, 0); rb_define_method(rb_cAddrInfo, "canonname", addrinfo_canonname, 0); - rb_define_method(rb_cAddrInfo, "ip?", addrinfo_ip_p, 0); + rb_define_method(rb_cAddrInfo, "ip?", addrinfo_ip_p, 0); + rb_define_method(rb_cAddrInfo, "ip_unpack", addrinfo_ip_unpack, 0); rb_define_method(rb_cAddrInfo, "ipv4?", addrinfo_ipv4_p, 0); rb_define_method(rb_cAddrInfo, "ipv6?", addrinfo_ipv6_p, 0); rb_define_method(rb_cAddrInfo, "unix?", addrinfo_unix_p, 0); +#ifdef HAVE_SYS_UN_H + rb_define_method(rb_cAddrInfo, "unix_path", addrinfo_unix_path, 0); +#endif rb_define_method(rb_cAddrInfo, "to_sockaddr", addrinfo_to_sockaddr, 0); diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb index 88e08d55d0..d205a7671a 100644 --- a/test/socket/test_addrinfo.rb +++ b/test/socket/test_addrinfo.rb @@ -25,6 +25,11 @@ class TestSocketAddrInfo < Test::Unit::TestCase assert_includes([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) + 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)) @@ -266,6 +271,11 @@ class TestSocketAddrInfo < Test::Unit::TestCase assert_equal(0, ai.protocol) end + def test_addrinfo_ip_unpack_inet6 + ai = AddrInfo.tcp("::1", 80) + assert_equal(["::1", 80], ai.ip_unpack) + end + end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM @@ -279,6 +289,11 @@ class TestSocketAddrInfo < Test::Unit::TestCase assert_equal(0, ai.protocol) end + def test_addrinfo_unix_path + ai = AddrInfo.unix("/tmp/sock1") + assert_equal("/tmp/sock1", ai.unix_path) + end + def test_addrinfo_new_unix ai = AddrInfo.new(["AF_UNIX", "/tmp/sock"]) assert_equal("/tmp/sock", Socket.unpack_sockaddr_un(ai))