[#42672] [Ruby 1.9-Bug#4110][Open] ホスト名の先頭が数字であるとき、WEBrickのテストでErrorが出る — Kouhei Yanagita <redmine@...>
Bug #4110: ホスト名の先頭が数字であるとき、WEBrickのテストでErrorが出る
[#42684] [Ruby 1.9-Bug#4120][Assigned] 2 failures on test/mkmf/test_convertible.rb — Usaku NAKAMURA <redmine@...>
Bug #4120: 2 failures on test/mkmf/test_convertible.rb
なかだです。
こんにちは、なかむら(う)です。
[#42692] [Feature: trunk] String#encode(:fallback) should accept default handler — SASADA Koichi <ko1@...>
ささだです.
[#42701] 1.9.x release and trunk branch policy — Yusuke ENDOH <mame@...>
まつもとさん、Yugui さん
[#42730] [Ruby 1.9-Bug#4143][Open] warning: "SUPPORT_JOKE" is not defined — Kazuhiro NISHIYAMA <redmine@...>
Bug #4143: warning: "SUPPORT_JOKE" is not defined
チケット #4143 が更新されました。 (by Kazuhiro NISHIYAMA)
2010年12月10日22:38 Kazuhiro NISHIYAMA <redmine@ruby-lang.org>:
(2010/12/10 23:49), KOSAKI Motohiro wrote:
[#42735] [Ruby 1.9-Feature#4147][Open] Array#sample で重みを指定したい — Yoji Ojima <redmine@...>
Feature #4147: Array#sample で重みを指定したい
チケット #4147 が更新されました。 (by Shyouhei Urabe)
> じゃあ反対ないので実装はともかく、この仕様は基本入れる方向で考えましょう。反対の人は意思表示お早めに。
Yuguiです。
2010年12月19日21:15 Yugui <yugui@yugui.jp>:
チケット #4147 が更新されました。 (by Yoji Ojima)
遠藤です。
チケット #4147 が更新されました。 (by Yoji Ojima)
[#42758] [Ruby 1.9-Bug#4157][Open] test_pty で、たまに出る Failure — Makoto Kishimoto <redmine@...>
Bug #4157: test_pty で、たまに出る Failure
[#42763] [Ruby 1.9-Bug#4159][Open] test_block_variables(TestRipper::ParserEvents) が失敗する — Kouhei Yanagita <redmine@...>
Bug #4159: test_block_variables(TestRipper::ParserEvents) が失敗する
[#42778] BasicObject#object_id — keiju@... (Keiju ISHITSUKA)
けいじゅ@いしつかです.
[#42782] [Ruby 1.9-Feature#4165][Open] win32ビルドでbaserubyを設定しなかったときのエラーが非常に不親切 — Motohiro KOSAKI <redmine@...>
Feature #4165: win32ビルドでbaserubyを設定しなかったときのエラーが非常に不親切
[#42832] [Ruby 1.9-Bug#4178][Open] test/rubygems/gemutilities.rb で、よくわからない ArgumentError — Makoto Kishimoto <redmine@...>
Bug #4178: test/rubygems/gemutilities.rb で、よくわからない ArgumentError
[#42869] [feature:trunk] option for Socket#sendmsg — Nobuyoshi Nakada <nobu@...>
なかだです。
2010年12月23日21:01 Nobuyoshi Nakada <nobu@ruby-lang.org>:
[#42887] [Ruby 1.9-Feature#4204][Open] IO#advise should raise error for unknown symbol — Tomoyuki Chikanaga <redmine@...>
Feature #4204: IO#advise should raise error for unknown symbol
[#42893] [Ruby 1.8-Bug#4206][Open] failed to set ext option for win32/configure.bat — Akio Tajima <redmine@...>
Bug #4206: failed to set ext option for win32/configure.bat
[#42894] [Ruby 1.8-Feature#4207][Open] これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには — Shyouhei Urabe <redmine@...>
Feature #4207: これから「1.8.8」の話をしよう -- 1.8がこの先生きのこるには
むらたです。
むらたです。
2011/1/5 Kenta Murata <muraken@gmail.com>:
こんにちは、なかむら(う)です。
チケット #4207 が更新されました。 (by Shyouhei Urabe)
[ruby-dev:42869] [feature:trunk] option for Socket#sendmsg
なかだです。
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はできる。
中田 伸悦