diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | ext/socket/constants.c | 2 | ||||
-rw-r--r-- | ext/socket/mkconstants.rb | 7 | ||||
-rw-r--r-- | ext/socket/raddrinfo.c | 199 | ||||
-rw-r--r-- | ext/socket/rubysocket.h | 6 | ||||
-rw-r--r-- | test/socket/test_addrinfo.rb | 33 |
6 files changed, 253 insertions, 10 deletions
@@ -1,3 +1,19 @@ +Sun Jan 18 03:05:20 2009 Tanaka Akira <akr@fsij.org> + + * ext/socket/raddrinfo.c (addrinfo_mdump): new method. + (addrinfo_mload): new method. + (Init_addrinfo): define the method above. + + * ext/socket/constants.c (constant_arg): str_to_int's first argument + constified. + + * ext/socket/mkconstants.rb (gen_name_to_int_decl): generated + function's first argument constified. + (gen_name_to_int_func_in_guard): ditto. + (ipproto_to_int): generated. + + * ext/socket/rubysocket.h (IS_IP_FAMILY): moved from raddrinfo.c. + Sun Jan 18 01:37:50 2009 Tanaka Akira <akr@fsij.org> * ext/socket/socket.c (sock_s_getnameinfo): accept AddrInfo object. diff --git a/ext/socket/constants.c b/ext/socket/constants.c index 273b8d6612..3242cddd71 100644 --- a/ext/socket/constants.c +++ b/ext/socket/constants.c @@ -19,7 +19,7 @@ static void sock_define_uconst(const char *name, unsigned int value, VALUE mCons #undef sock_define_uconst static int -constant_arg(VALUE arg, int (*str_to_int)(char*, int, int*), const char *errmsg) +constant_arg(VALUE arg, int (*str_to_int)(const char*, int, int*), const char *errmsg) { VALUE tmp; char *ptr; diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb index 3c486d639b..cfc0fbe069 100644 --- a/ext/socket/mkconstants.rb +++ b/ext/socket/mkconstants.rb @@ -140,16 +140,16 @@ end ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_decl(funcname, pat, prefix_optional, guard=nil)") %if guard #ifdef <%=guard%> -int <%=funcname%>(char *str, int len, int *valp); +int <%=funcname%>(const char *str, int len, int *valp); #endif %else -int <%=funcname%>(char *str, int len, int *valp); +int <%=funcname%>(const char *str, int len, int *valp); %end EOS ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard=nil)") int -<%=funcname%>(char *str, int len, int *valp) +<%=funcname%>(const char *str, int len, int *valp) { switch (len) { % each_names_with_len(pat, prefix_optional) {|pairs, len| @@ -241,6 +241,7 @@ end def_name_to_int("family_to_int", /\A(AF_|PF_)/, "AF_") def_name_to_int("socktype_to_int", /\ASOCK_/, "SOCK_") +def_name_to_int("ipproto_to_int", /\AIPPROTO_/, "IPPROTO_") def_name_to_int("level_to_int", /\A(SOL_SOCKET\z|IPPROTO_)/, /\A(SOL_|IPPROTO_)/) def_name_to_int("so_optname_to_int", /\ASO_/, "SO_") def_name_to_int("ip_optname_to_int", /\AIP_/, "IP_") diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index b32428347c..ac016e28c2 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -1081,6 +1081,196 @@ addrinfo_inspect(VALUE self) return ret; } +/* :nodoc: */ +static VALUE +addrinfo_mdump(VALUE self) +{ + rb_addrinfo_t *rai = get_addrinfo(self); + VALUE sockaddr, afamily, pfamily, socktype, protocol, canonname, inspectname; + int afamily_int = ai_get_afamily(rai); + ID id; + + id = intern_protocol_family(rai->pfamily); + if (id == 0) + rb_raise(rb_eSocket, "unknown protocol family: %d", rai->pfamily); + pfamily = ID2SYM(id); + + if (rai->socktype == 0) + socktype = INT2FIX(0); + else { + id = intern_socktype(rai->socktype); + if (id == 0) + rb_raise(rb_eSocket, "unknown socktype: %d", rai->socktype); + socktype = ID2SYM(id); + } + + if (rai->protocol == 0) + protocol = INT2FIX(0); + else if (IS_IP_FAMILY(afamily_int)) { + id = intern_ipproto(rai->protocol); + if (id == 0) + rb_raise(rb_eSocket, "unknown IP protocol: %d", rai->protocol); + protocol = ID2SYM(id); + } + else { + rb_raise(rb_eSocket, "unknown protocol: %d", rai->protocol); + } + + canonname = rai->canonname; + + inspectname = rai->inspectname; + + id = intern_family(afamily_int); + if (id == 0) + rb_raise(rb_eSocket, "unknown address family: %d", afamily_int); + afamily = ID2SYM(id); + + switch(afamily_int) { + case AF_UNIX: + { + struct sockaddr_un *su = (struct sockaddr_un *)&rai->addr; + char *s, *e; + s = su->sun_path; + e = (char*)s + sizeof(su->sun_path); + while (s < e && *(e-1) == '\0') + e--; + sockaddr = rb_str_new(s, e-s); + break; + } + + default: + { + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + int error; + error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len, + hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), + NI_NUMERICHOST|NI_NUMERICSERV); + if (error) { + raise_socket_error("getnameinfo", error); + } + sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf)); + break; + } + } + + return rb_ary_new3(7, afamily, sockaddr, pfamily, socktype, protocol, canonname, inspectname); +} + +/* :nodoc: */ +static VALUE +addrinfo_mload(VALUE self, VALUE ary) +{ + VALUE v; + VALUE canonname, inspectname; + int afamily, pfamily, socktype, protocol; + struct sockaddr_storage ss; + size_t len; + const char *str; + rb_addrinfo_t *rai; + + if (check_addrinfo(self)) + rb_raise(rb_eTypeError, "already initialized socket address"); + + ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); + + v = rb_ary_entry(ary, 0); + if (!SYMBOL_P(v)) + rb_raise(rb_eTypeError, "symbol expected for address family"); + str = rb_id2name(SYM2ID(v)); + if (family_to_int(str, strlen(str), &afamily) == -1) + rb_raise(rb_eTypeError, "unexpected address family"); + + v = rb_ary_entry(ary, 2); + if (!SYMBOL_P(v)) + rb_raise(rb_eTypeError, "symbol expected for protocol family"); + str = rb_id2name(SYM2ID(v)); + if (family_to_int(str, strlen(str), &pfamily) == -1) + rb_raise(rb_eTypeError, "unexpected protocol family"); + + v = rb_ary_entry(ary, 3); + if (v == INT2FIX(0)) + socktype = 0; + else { + if (!SYMBOL_P(v)) + rb_raise(rb_eTypeError, "symbol expected for socktype"); + str = rb_id2name(SYM2ID(v)); + if (socktype_to_int(str, strlen(str), &socktype) == -1) + rb_raise(rb_eTypeError, "unexpected socktype"); + } + + v = rb_ary_entry(ary, 4); + if (v == INT2FIX(0)) + protocol = 0; + else { + if (!SYMBOL_P(v)) + rb_raise(rb_eTypeError, "symbol expected for protocol"); + if (IS_IP_FAMILY(afamily)) { + str = rb_id2name(SYM2ID(v)); + if (ipproto_to_int(str, strlen(str), &protocol) == -1) + rb_raise(rb_eTypeError, "unexpected protocol"); + } + else { + rb_raise(rb_eTypeError, "unexpected protocol"); + } + } + + v = rb_ary_entry(ary, 5); + if (NIL_P(v)) + canonname = Qnil; + else { + StringValue(v); + canonname = v; + } + + v = rb_ary_entry(ary, 6); + if (NIL_P(v)) + inspectname = Qnil; + else { + StringValue(v); + inspectname = v; + } + + v = rb_ary_entry(ary, 1); + switch(afamily) { + case AF_UNIX: + { + struct sockaddr_un *su = (struct sockaddr_un *)&ss; + memset(su, 0, sizeof(*su)); + su->sun_family = AF_UNIX; + + StringValue(v); + if (sizeof(su->sun_path) <= RSTRING_LEN(v)) + rb_raise(rb_eSocket, "too long AF_UNIX path"); + memcpy(su->sun_path, RSTRING_PTR(v), RSTRING_LEN(v)); + len = sizeof(*su); + break; + } + + default: + { + VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary"); + struct addrinfo *res; + int flags = AI_NUMERICHOST; +#ifdef AI_NUMERICSERV + flags |= AI_NUMERICSERV; +#endif + res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1), + INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol), + INT2NUM(flags), 1); + + len = res->ai_addrlen; + memcpy(&ss, res->ai_addr, res->ai_addrlen); + break; + } + } + + DATA_PTR(self) = rai = alloc_addrinfo(); + init_addrinfo(rai, (struct sockaddr *)&ss, len, + pfamily, socktype, protocol, + canonname, inspectname); + return self; +} + /* * call-seq: * addrinfo.afamily => integer @@ -1187,12 +1377,6 @@ addrinfo_canonname(VALUE self) return rai->canonname; } -#ifdef AF_INET6 -# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6) -#else -# define IS_IP_FAMILY(af) ((af) == AF_INET) -#endif - /* * call-seq: * addrinfo.ip? => true or false @@ -1603,4 +1787,7 @@ Init_addrinfo(void) rb_define_method(rb_cAddrInfo, "to_sockaddr", addrinfo_to_sockaddr, 0); rb_define_method(rb_cAddrInfo, "getnameinfo", addrinfo_getnameinfo, -1); + + rb_define_method(rb_cAddrInfo, "marshal_dump", addrinfo_mdump, 0); + rb_define_method(rb_cAddrInfo, "marshal_load", addrinfo_mload, 1); } diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 464649fc49..bb2f6a6896 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -74,6 +74,12 @@ # define NI_MAXSERV 32 #endif +#ifdef AF_INET6 +# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6) +#else +# define IS_IP_FAMILY(af) ((af) == AF_INET) +#endif + #ifndef HAVE_SOCKADDR_STORAGE /* * RFC 2553: protocol-independent placeholder for socket addresses diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb index d6c264bb8f..4e232d02a6 100644 --- a/test/socket/test_addrinfo.rb +++ b/test/socket/test_addrinfo.rb @@ -274,6 +274,17 @@ class TestSocketAddrInfo < Test::Unit::TestCase s2.close if s2 && !s2.closed? end + def test_marshal + ai1 = AddrInfo.tcp("127.0.0.1", 80) + ai2 = Marshal.load(Marshal.dump(ai1)) + assert_equal(ai1.afamily, ai2.afamily) + assert_equal(ai1.ip_unpack, ai2.ip_unpack) + assert_equal(ai1.pfamily, ai2.pfamily) + assert_equal(ai1.socktype, ai2.socktype) + assert_equal(ai1.protocol, ai2.protocol) + assert_equal(ai1.canonname, ai2.canonname) + end + if Socket.const_defined?("AF_INET6") def test_addrinfo_new_inet6 @@ -290,6 +301,17 @@ class TestSocketAddrInfo < Test::Unit::TestCase assert_equal(["::1", 80], ai.ip_unpack) end + def test_marshal_inet6 + ai1 = AddrInfo.tcp("::1", 80) + ai2 = Marshal.load(Marshal.dump(ai1)) + assert_equal(ai1.afamily, ai2.afamily) + assert_equal(ai1.ip_unpack, ai2.ip_unpack) + assert_equal(ai1.pfamily, ai2.pfamily) + assert_equal(ai1.socktype, ai2.socktype) + assert_equal(ai1.protocol, ai2.protocol) + assert_equal(ai1.canonname, ai2.canonname) + end + end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM @@ -325,5 +347,16 @@ class TestSocketAddrInfo < Test::Unit::TestCase assert(unix_ai.unix?) end + def test_marshal_unix + ai1 = AddrInfo.unix("/var/tmp/sock") + ai2 = Marshal.load(Marshal.dump(ai1)) + assert_equal(ai1.afamily, ai2.afamily) + assert_equal(ai1.unix_path, ai2.unix_path) + assert_equal(ai1.pfamily, ai2.pfamily) + assert_equal(ai1.socktype, ai2.socktype) + assert_equal(ai1.protocol, ai2.protocol) + assert_equal(ai1.canonname, ai2.canonname) + end + end end |