[#42735] [Ruby 1.9-Feature#4147][Open] Array#sample で重みを指定したい — Yoji Ojima <redmine@...>

Feature #4147: Array#sample で重みを指定したい

52 messages 2010/12/10
[#42791] [Ruby 1.9-Feature#4147][Assigned] Array#sample で重みを指定したい — Shyouhei Urabe <redmine@...> 2010/12/18

チケット #4147 が更新されました。 (by Shyouhei Urabe)

[#42800] Re: [Ruby 1.9-Feature#4147][Assigned] Array#sample で重みを指定したい — Masaya TARUI <tarui@...> 2010/12/19

> じゃあ反対ないので実装はともかく、この仕様は基本入れる方向で考えましょう。反対の人は意思表示お早めに。

[#42763] [Ruby 1.9-Bug#4159][Open] test_block_variables(TestRipper::ParserEvents) が失敗する — Kouhei Yanagita <redmine@...>

Bug #4159: test_block_variables(TestRipper::ParserEvents) が失敗する

8 messages 2010/12/14

[#42894] [Ruby 1.8-Feature#4207][Open] これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには — Shyouhei Urabe <redmine@...>

Feature #4207: これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには

24 messages 2010/12/26
[#42935] Re: [Ruby 1.8-Feature#4207][Open] これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには — Kenta Murata <muraken@...> 2011/01/04

むらたです。

[#42936] Re: [Ruby 1.8-Feature#4207][Open] これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには — Kenta Murata <muraken@...> 2011/01/05

むらたです。

[ruby-dev:42869] [feature:trunk] option for Socket#sendmsg

From: Nobuyoshi Nakada <nobu@...>
Date: 2010-12-23 12:01:19 UTC
List: ruby-dev #42869
なかだです。

Socket#recvmsgは scm_rights: true を指定するだけでメインのデータだけで
なく簡単にIOを受け取ることができますが、一方でSocket#sendmsg側には対応
する指定ができません。以下のようなオプションを追加するのはどうでしょう
か。

  s.sendmsg("foo", scm_rights: STDIN)
  s.sendmsg("foo", scm_rights: [STDIN, STDOUT])


diff --git i/ext/socket/ancdata.c w/ext/socket/ancdata.c
index abaf19d..c329e0a 100644
--- i/ext/socket/ancdata.c
+++ w/ext/socket/ancdata.c
@@ -2,6 +2,8 @@
 
 #include <time.h>
 
+static ID sym_scm_rights;
+
 #if defined(HAVE_ST_MSG_CONTROL)
 static VALUE rb_cAncillaryData;
 
@@ -1126,17 +1128,63 @@ rb_sendmsg(int fd, const struct msghdr *msg, int flags)
     return rb_thread_blocking_region(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
 }
 
+#if defined(HAVE_ST_MSG_CONTROL)
+static size_t
+io_to_fd(VALUE io)
+{
+    VALUE fnum = rb_check_to_integer(io, "to_int");
+    if (NIL_P(fnum))
+	fnum = rb_convert_type(io, T_FIXNUM, "Fixnum", "fileno");
+    return NUM2UINT(fnum);
+}
+
+static char *
+prepare_msghdr(VALUE controls_str, int level, int type, long clen)
+{
+    struct cmsghdr cmh;
+    char *cmsg;
+    size_t cspace;
+    long oldlen = RSTRING_LEN(controls_str);
+    cspace = CMSG_SPACE(clen);
+    rb_str_resize(controls_str, oldlen + cspace);
+    cmsg = RSTRING_PTR(controls_str)+oldlen;
+    memset((char *)cmsg, 0, cspace);
+    memset((char *)&cmh, 0, sizeof(cmh));
+    cmh.cmsg_level = level;
+    cmh.cmsg_type = type;
+    cmh.cmsg_len = (socklen_t)CMSG_LEN(clen);
+    MEMCPY(cmsg, &cmh, char, sizeof(cmh));
+    return cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh);
+}
+
+# if defined(__NetBSD__)
+#   define TRIM_PADDING 1
+# endif
+# if TRIM_PADDING
+#   define prepare_msghdr(controls_str, level, type, clen) \
+    (last_pad = CMSG_SPACE(clen) - CMSG_LEN(clen), \
+     prepare_msghdr((controls_str), \
+		    last_level = (level), last_type = (type), \
+		    (clen)))
+# endif
+#endif
+
 static VALUE
 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
 {
     rb_io_t *fptr;
-    VALUE data, vflags, dest_sockaddr;
+    VALUE data, vflags, dest_sockaddr, vopts = Qnil;
     VALUE *controls_ptr;
     int controls_num;
     struct msghdr mh;
     struct iovec iov;
 #if defined(HAVE_ST_MSG_CONTROL)
     volatile VALUE controls_str = 0;
+# if TRIM_PADDING
+    size_t last_pad = 0;
+    int last_level = 0;
+    int last_type = 0;
+# endif
 #endif
     int flags;
     ssize_t ss;
@@ -1152,6 +1200,8 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
 
     if (argc == 0)
         rb_raise(rb_eArgError, "mesg argument required");
+    if (1 < argc && RB_TYPE_P(argv[argc-1], T_HASH))
+        vopts = argv[--argc];
     data = argv[0];
     if (1 < argc) vflags = argv[1];
     if (2 < argc) dest_sockaddr = argv[2];
@@ -1162,19 +1212,13 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
     if (controls_num) {
 #if defined(HAVE_ST_MSG_CONTROL)
 	int i;
-	size_t last_pad = 0;
-        int last_level = 0;
-        int last_type = 0;
         controls_str = rb_str_tmp_new(0);
         for (i = 0; i < controls_num; i++) {
             VALUE elt = controls_ptr[i], v;
             VALUE vlevel, vtype;
             int level, type;
             VALUE cdata;
-            long oldlen;
-            struct cmsghdr cmh;
             char *cmsg;
-            size_t cspace;
             v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
             if (!NIL_P(v)) {
                 elt = v;
@@ -1192,21 +1236,46 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
             level = rsock_level_arg(family, vlevel);
             type = rsock_cmsg_type_arg(family, level, vtype);
             StringValue(cdata);
-            oldlen = RSTRING_LEN(controls_str);
-            cspace = CMSG_SPACE(RSTRING_LEN(cdata));
-            rb_str_resize(controls_str, oldlen + cspace);
-            cmsg = RSTRING_PTR(controls_str)+oldlen;
-            memset((char *)cmsg, 0, cspace);
-            memset((char *)&cmh, 0, sizeof(cmh));
-            cmh.cmsg_level = level;
-            cmh.cmsg_type = type;
-            cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
-            MEMCPY(cmsg, &cmh, char, sizeof(cmh));
-            MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
-            last_level = cmh.cmsg_level;
-            last_type = cmh.cmsg_type;
-	    last_pad = cspace - cmh.cmsg_len;
+            cmsg = prepare_msghdr(controls_str, level, type, RSTRING_LEN(cdata));
+            MEMCPY(cmsg, RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
         }
+#else
+      no_msg_control:
+	rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
+#endif
+    }
+    if (!NIL_P(vopts)) {
+	VALUE rights = rb_hash_aref(vopts, sym_scm_rights);
+	if (!NIL_P(rights)) {
+#if defined(HAVE_ST_MSG_CONTROL)
+	    VALUE tmp = rb_check_array_type(rights);
+            long count = NIL_P(tmp) ? 1 : RARRAY_LEN(tmp);
+            char *cmsg;
+	    int fd;
+	    if (!controls_str) controls_str = rb_str_tmp_new(0);
+            cmsg = prepare_msghdr(controls_str, SOL_SOCKET, SCM_RIGHTS,
+                                  count * sizeof(int));
+            if (NIL_P(tmp)) {
+                fd = io_to_fd(rights);
+                MEMCPY(cmsg, &fd, int, 1);
+            }
+            else {
+                long i;
+                rights = tmp;
+                for (i = 0; i < count && i < RARRAY_LEN(rights); ++i) {
+                    fd = io_to_fd(RARRAY_PTR(rights)[i]);
+                    MEMCPY(cmsg, &fd, int, 1);
+                    cmsg += sizeof(int);
+                }
+            }
+#else
+	    goto no_msg_control;
+#endif
+	}
+    }
+#if defined(HAVE_ST_MSG_CONTROL)
+    {
+# if TRIM_PADDING
 	if (last_pad) {
             /*
              * This code removes the last padding from msg_controllen.
@@ -1228,15 +1297,12 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
              * Basically, msg_controllen should contains the padding.
              * So the padding is removed only if a problem really exists.
              */
-#if defined(__NetBSD__)
             if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
                 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
-#endif
 	}
-#else
-	rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
-#endif
+# endif
     }
+#endif
 
     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
 #ifdef MSG_DONTWAIT
@@ -1492,7 +1558,7 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
     grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
 
     request_scm_rights = 0;
-    if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
+    if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, sym_scm_rights)))
         request_scm_rights = 1;
 
     GetOpenFile(sock, fptr);
@@ -1795,5 +1861,7 @@ rsock_init_ancdata(void)
     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
+
+    sym_scm_rights = ID2SYM(rb_intern("scm_rights"));
 #endif
 }
diff --git i/test/socket/test_unix.rb w/test/socket/test_unix.rb
index bde17cf..e9db22e 100644
--- i/test/socket/test_unix.rb
+++ w/test/socket/test_unix.rb
@@ -31,7 +31,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
     end
   end
 
-  def test_fd_passing_n
+  def fd_passing_test
     io_ary = []
     return if !defined?(Socket::SCM_RIGHTS)
     io_ary.concat IO.pipe
@@ -42,8 +42,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
       send_io_ary << io
       UNIXSocket.pair {|s1, s2|
         begin
-          ret = s1.sendmsg("\0", 0, nil, [Socket::SOL_SOCKET, Socket::SCM_RIGHTS,
-                                          send_io_ary.map {|io2| io2.fileno }.pack("i!*")])
+          ret = yield(s1, send_io_ary)
         rescue NotImplementedError
           return
         end
@@ -66,48 +65,38 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
     io_ary.each {|io| io.close if !io.closed? }
   end
 
+  def test_fd_passing_n
+    fd_passing_test do |s, ios|
+      s.sendmsg("\0", 0, nil,
+                [Socket::SOL_SOCKET, Socket::SCM_RIGHTS, ios.map(&:fileno).pack("i!*")])
+    end
+  end
+
   def test_fd_passing_n2
-    io_ary = []
-    return if !defined?(Socket::SCM_RIGHTS)
-    return if !defined?(Socket::AncillaryData)
-    io_ary.concat IO.pipe
-    io_ary.concat IO.pipe
-    io_ary.concat IO.pipe
-    send_io_ary = []
-    io_ary.each {|io|
-      send_io_ary << io
-      UNIXSocket.pair {|s1, s2|
-        begin
-          ancdata = Socket::AncillaryData.unix_rights(*send_io_ary)
-          ret = s1.sendmsg("\0", 0, nil, ancdata)
-        rescue NotImplementedError
-          return
-        end
-        assert_equal(1, ret)
-        ret = s2.recvmsg(:scm_rights=>true)
-        data, srcaddr, flags, *ctls = ret
-        recv_io_ary = []
-        ctls.each {|ctl|
-          next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS
-          recv_io_ary.concat ctl.unix_rights
-        }
-        assert_equal(send_io_ary.length, recv_io_ary.length)
-        send_io_ary.length.times {|i|
-          assert_not_equal(send_io_ary[i].fileno, recv_io_ary[i].fileno)
-          assert(File.identical?(send_io_ary[i], recv_io_ary[i]))
-        }
-      }
-    }
-  ensure
-    io_ary.each {|io| io.close if !io.closed? }
+    fd_passing_test do |s, ios|
+      ancdata = Socket::AncillaryData.unix_rights(*ios)
+      s.sendmsg("\0", 0, nil, ancdata)
+    end
+  end
+
+  def test_fd_passing_n3
+    fd_passing_test do |s, ios|
+      s.sendmsg("\0", 0, nil, scm_rights: ios.map(&:fileno))
+    end
+  end
+
+  def test_fd_passing_n4
+    fd_passing_test do |s, ios|
+      s.sendmsg("\0", 0, nil, scm_rights: ios)
+    end
   end
 
-  def test_sendmsg
+  def sendmsg_test
     return if !defined?(Socket::SCM_RIGHTS)
     IO.pipe {|r1, w|
       UNIXSocket.pair {|s1, s2|
         begin
-          ret = s1.sendmsg("\0", 0, nil, [Socket::SOL_SOCKET, Socket::SCM_RIGHTS, [r1.fileno].pack("i!")])
+          ret = yield(s1, r1)
         rescue NotImplementedError
           return
         end
@@ -122,6 +111,24 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
     }
   end
 
+  def test_sendmsg_1
+    sendmsg_test do |s, r|
+      s.sendmsg("\0", 0, nil, [Socket::SOL_SOCKET, Socket::SCM_RIGHTS, [r.fileno].pack("i!")])
+    end
+  end
+
+  def test_sendmsg_2
+    sendmsg_test do |s, r|
+      s.sendmsg("\0", 0, nil, scm_rights: r.fileno)
+    end
+  end
+
+  def test_sendmsg_3
+    sendmsg_test do |s, r|
+      s.sendmsg("\0", 0, nil, scm_rights: r)
+    end
+  end
+
   def test_sendmsg_ancillarydata_int
     return if !defined?(Socket::SCM_RIGHTS)
     return if !defined?(Socket::AncillaryData)


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread

Prev Next