summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--ext/socket/constants.c2
-rw-r--r--ext/socket/mkconstants.rb7
-rw-r--r--ext/socket/raddrinfo.c199
-rw-r--r--ext/socket/rubysocket.h6
-rw-r--r--test/socket/test_addrinfo.rb33
6 files changed, 253 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index aa7ad1861d..0d01356523 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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