[前][次][番号順一覧][スレッド一覧]

ruby-changes:18348

From: akr <ko1@a...>
Date: Sat, 25 Dec 2010 23:35:34 +0900 (JST)
Subject: [ruby-changes:18348] Ruby:r30371 (trunk): * ext/socket/option.c (inspect_ipv4_add_drop_membership): new function

akr	2010-12-25 23:35:28 +0900 (Sat, 25 Dec 2010)

  New Revision: 30371

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30371

  Log:
    * ext/socket/option.c (inspect_ipv4_add_drop_membership): new function
      to inspect struct ip_mreq and struct ip_mreqn for
      IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
      Socket::Option.new(:INET, :IP, :ADD_MEMBERSHIP,
      [239,255,99,81, 0,0,0,0].pack("CCCCCCCC")).inspect is now
      "#<Socket::Option: INET IP ADD_MEMBERSHIP 239.255.99.81 0.0.0.0>".
      (inspect_ipv4_multicast_if): new function to inspect struct in_addr
      and struct ip_mreqn for IP_MULTICAST_IF.
      Socket::Option.new(:INET, :IP, :MULTICAST_IF,
      [192,168,0,7].pack("CCCC")).inspect is now
      "#<Socket::Option: INET IP MULTICAST_IF 192.168.0.7>".
    
    * ext/socket/extconf.rb: check struct ip_mreq and struct ip_mreqn.

  Modified files:
    trunk/ChangeLog
    trunk/ext/socket/extconf.rb
    trunk/ext/socket/option.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 30370)
+++ ChangeLog	(revision 30371)
@@ -1,3 +1,19 @@
+Sat Dec 25 23:29:11 2010  Tanaka Akira  <akr@f...>
+
+	* ext/socket/option.c (inspect_ipv4_add_drop_membership): new function
+	  to inspect struct ip_mreq and struct ip_mreqn for
+	  IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+	  Socket::Option.new(:INET, :IP, :ADD_MEMBERSHIP,
+	  [239,255,99,81, 0,0,0,0].pack("CCCCCCCC")).inspect is now
+	  "#<Socket::Option: INET IP ADD_MEMBERSHIP 239.255.99.81 0.0.0.0>".
+	  (inspect_ipv4_multicast_if): new function to inspect struct in_addr
+	  and struct ip_mreqn for IP_MULTICAST_IF.
+	  Socket::Option.new(:INET, :IP, :MULTICAST_IF,
+	  [192,168,0,7].pack("CCCC")).inspect is now
+	  "#<Socket::Option: INET IP MULTICAST_IF 192.168.0.7>".
+
+	* ext/socket/extconf.rb: check struct ip_mreq and struct ip_mreqn.
+
 Sat Dec 25 22:49:10 2010  Nobuyoshi Nakada  <nobu@r...>
 
 	* test/csv: DifferentOFS needs to be include in each classes.
@@ -27,8 +43,8 @@
 	* ext/socket/option.c (inspect_ipv6_mreq): new function to inspect
 	  struct ipv6_mreq for IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP.
 	  Socket::Option.new(:INET6, :IPV6, :JOIN_GROUP,
-	  [0xff12,0,0,0,0,0,0,1, 2].pack("nnnnnnnnI!")).inspect is now:
-	  "#<Socket::Option: INET6 IPV6 JOIN_GROUP ff12::1 eth0>"
+	  [0xff12,0,0,0,0,0,0,1, 2].pack("nnnnnnnnI!")).inspect is now
+	  "#<Socket::Option: INET6 IPV6 JOIN_GROUP ff12::1 eth0>".
 
 	* ext/socket/extconf.rb: check struct ipv6_mreq.
 
Index: ext/socket/option.c
===================================================================
--- ext/socket/option.c	(revision 30370)
+++ ext/socket/option.c	(revision 30371)
@@ -396,6 +396,133 @@
     }
 }
 
+/*
+ * socket option for IPv4 multicast is bit confusing.
+ *
+ * IP Multicast is implemented by Steve Deering at first:
+ *   IP Multicast Extensions for 4.3BSD UNIX and related systems
+ *   (MULTICAST 1.2 Release)
+ *   http://www.kohala.com/start/mcast.api.txt
+ *
+ * There are 3 socket options which takes a struct.
+ *
+ *   IP_MULTICAST_IF: struct in_addr
+ *   IP_ADD_MEMBERSHIP: struct ip_mreq
+ *   IP_DROP_MEMBERSHIP: struct ip_mreq
+ *
+ * But they uses an IP address to specify an interface.
+ * This means the API cannot specify an unnumbered interface.
+ *
+ * Linux 2.4 introduces struct ip_mreqn to fix this problem.
+ * struct ip_mreqn has imr_ifindex field to specify interface index.
+ *
+ *   IP_MULTICAST_IF: struct ip_mreqn
+ *   IP_ADD_MEMBERSHIP: struct ip_mreqn
+ *   IP_DROP_MEMBERSHIP: struct ip_mreqn
+ *
+ * FreeBSD 7 obtained struct ip_mreqn for IP_MULTICAST_IF.
+ * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/netinet/in.h.diff?r1=1.99;r2=1.100
+ *
+ * Another hackish workaround is "RFC 1724 hack".
+ * RFC 1724 section 3.3 suggests unnumbered interfaces
+ * specified by pseudo address 0.0.0.0/8.
+ * NetBSD 4 documented it.
+ * http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.16&r2=1.17
+ *
+ * RFC 1724 hack is not supported by Socket::Option#inspect because
+ * it is not distinguishable by the size.
+ */
+
+#if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
+static int
+inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret)
+{
+    if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) {
+        struct ip_mreq s;
+        char addrbuf[INET_ADDRSTRLEN];
+        memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
+        if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
+            rb_str_cat2(ret, " invalid-address");
+        else
+            rb_str_catf(ret, " %s", addrbuf);
+        if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
+            rb_str_catf(ret, " invalid-address");
+        else
+            rb_str_catf(ret, " %s", addrbuf);
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+#endif
+
+#if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* GNU/Linux, FreeBSD 7 */
+static int
+inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret)
+{
+    if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
+        struct ip_mreqn s;
+        char addrbuf[INET_ADDRSTRLEN], ifbuf[IFNAMSIZ];
+        memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
+        if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
+            rb_str_cat2(ret, " invalid-address");
+        else
+            rb_str_catf(ret, " %s", addrbuf);
+        if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
+            rb_str_catf(ret, " invalid-address");
+        else
+            rb_str_catf(ret, " %s", addrbuf);
+        if (if_indextoname(s.imr_ifindex, ifbuf) == NULL)
+            rb_str_catf(ret, " ifindex:%d", s.imr_ifindex);
+        else
+            rb_str_catf(ret, " %s", ifbuf);
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+#endif
+
+#if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
+static int
+inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret)
+{
+    if (RSTRING_LEN(data) == sizeof(struct ip_mreq))
+        return inspect_ipv4_mreq(level, optname, data, ret);
+# if defined(HAVE_TYPE_STRUCT_IP_MREQN)
+    else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) 
+        return inspect_ipv4_mreqn(level, optname, data, ret);
+# endif
+    else
+        return 0;
+}
+#endif
+
+#if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) /* 4.4BSD, GNU/Linux */
+static int
+inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret)
+{
+    if (RSTRING_LEN(data) == sizeof(struct in_addr)) {
+        struct in_addr s;
+        char addrbuf[INET_ADDRSTRLEN];
+        memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
+        if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
+            rb_str_cat2(ret, " invalid-address");
+        else
+            rb_str_catf(ret, " %s", addrbuf);
+        return 1;
+    }
+    else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
+        return inspect_ipv4_mreqn(level, optname, data, ret);
+    }
+    else {
+        return 0;
+    }
+}
+#endif
+
 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ) /* POSIX, RFC 3493 */
 static int
 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
@@ -611,6 +738,22 @@
       case AF_INET6:
 #endif
         switch (level) {
+#        if defined(IPPROTO_IP)
+          case IPPROTO_IP:
+            switch (optname) {
+#            if defined(IP_MULTICAST_IF) /* 4.4BSD, GNU/Linux */
+              case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
+#            endif
+#            if defined(IP_ADD_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
+              case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
+#            endif
+#            if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
+              case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
+#            endif
+            }
+            break;
+#        endif
+
 #        if defined(IPPROTO_IPV6)
           case IPPROTO_IPV6:
             switch (optname) {
Index: ext/socket/extconf.rb
===================================================================
--- ext/socket/extconf.rb	(revision 30370)
+++ ext/socket/extconf.rb	(revision 30371)
@@ -340,7 +340,9 @@
 have_header("ucred.h", headers)
 have_func("getpeerucred")
 
-have_type("struct ipv6_mreq", headers)
+have_type("struct ip_mreq", headers) # 4.4BSD
+have_type("struct ip_mreqn", headers) # Linux 2.4
+have_type("struct ipv6_mreq", headers) # RFC 3493
 
 # workaround for recent Windows SDK
 $defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]