diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-18 18:43:15 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-18 18:43:15 +0000 |
commit | 18afbc891c3ac8d21b7d93a2d8ad76c2f536956d (patch) | |
tree | cccfa88aaecbe132e117d95b94d243ec4c113667 | |
parent | 2485ed517745088bf2b26707f2a66217b778d4f3 (diff) | |
download | ruby-18afbc891c3ac8d21b7d93a2d8ad76c2f536956d.tar.gz |
* ext/socket/ancdata.c (ancillary_rights): new method.
(make_io_for_rights): new function to allocate
IOs for FDs in SCM_RIGHTS message.
(bsock_recvmsg_internal): use make_io_for_rights. So the FDs can be
closed by GC.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22426 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | ext/socket/ancdata.c | 58 | ||||
-rw-r--r-- | test/socket/test_unix.rb | 17 |
3 files changed, 73 insertions, 10 deletions
@@ -1,3 +1,11 @@ +Thu Feb 19 03:42:48 2009 Tanaka Akira <akr@fsij.org> + + * ext/socket/ancdata.c (ancillary_rights): new method. + (make_io_for_rights): new function to allocate + IOs for FDs in SCM_RIGHTS message. + (bsock_recvmsg_internal): use make_io_for_rights. So the FDs can be + closed by GC. + Thu Feb 19 03:28:59 2009 Akinori MUSHA <knu@iDaemons.org> * README.EXT, README.EXT.ja: Improve the document about diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c index 239d93445a..442300abb4 100644 --- a/ext/socket/ancdata.c +++ b/ext/socket/ancdata.c @@ -174,6 +174,29 @@ ancillary_data(VALUE self) return v; } +/* + * call-seq: + * ancillarydata.rights => array-of-IOs + * + * returns the array of IOs which is sent by SCM_RIGHTS control message. + * + * The class of an IO in the array is IO or Socket. + * + * s1, s2 = UNIXSocket.pair + * p s1 #=> #<UNIXSocket:fd 3> + * s1.sendmsg "standard IOs", 0, nil, [:SOCKET, :RIGHTS, [0,s1.fileno].pack("ii")] + * _, _, _, ctl = s2.recvmsg + * p ctl.rights #=> [#<IO:fd 6>, #<Socket:fd 7>] + * p File.identical?(STDIN, ctl.rights[0]) #=> true + * p File.identical?(s1, ctl.rights[1]) #=> true + * + */ +static VALUE +ancillary_rights(VALUE self) +{ + VALUE v = rb_attr_get(self, rb_intern("rights")); + return v; +} /* * call-seq: @@ -1121,6 +1144,35 @@ discard_cmsg_resource(struct msghdr *mh) #endif } +#if defined(HAVE_ST_MSG_CONTROL) +static void +make_io_for_rights(VALUE ctl, struct cmsghdr *cmh) +{ + if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) { + int *fdp = (int *)CMSG_DATA(cmh); + int *end = (int *)((char *)cmh + cmh->cmsg_len); + while (fdp < end) { + int fd = *fdp; + struct stat stbuf; + VALUE io, ary; + if (fstat(fd, &stbuf) == -1) + rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS"); + if (S_ISSOCK(stbuf.st_mode)) + io = init_sock(rb_obj_alloc(rb_cSocket), fd); + else + io = rb_io_fdopen(fd, O_RDWR, NULL); + ary = rb_attr_get(ctl, rb_intern("rights")); + if (NIL_P(ary)) { + ary = rb_ary_new(); + rb_ivar_set(ctl, rb_intern("rights"), ary); + } + rb_ary_push(ary, io); + fdp++; + } + } +} +#endif + static VALUE bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) { @@ -1145,6 +1197,7 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) } ctlbuf0; char *ctlbuf; VALUE ctl_str = Qnil; + int family; #endif rb_secure(4); @@ -1288,17 +1341,17 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) ); #if defined(HAVE_ST_MSG_CONTROL) + family = rb_sock_getfamily(fptr->fd); if (mh.msg_controllen) { for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) { VALUE ctl; size_t clen; - int family; if (cmh->cmsg_len == 0) { rb_raise(rb_eIOError, "invalid control message (cmsg_len == 0)"); } - family = rb_sock_getfamily(fptr->fd); clen = (char*)cmh + cmh->cmsg_len - (char*)CMSG_DATA(cmh); ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen)); + make_io_for_rights(ctl, cmh); rb_ary_push(ret, ctl); } } @@ -1398,6 +1451,7 @@ Init_ancdata(void) rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0); rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0); rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0); + rb_define_method(rb_cAncillaryData, "rights", ancillary_rights, 0); rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2); rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4); rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0); diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb index 6e822dbc36..e4c86f2912 100644 --- a/test/socket/test_unix.rb +++ b/test/socket/test_unix.rb @@ -53,7 +53,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase recv_io_ary = [] ctls.each {|ctl| next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS - recv_io_ary.concat ctl.data.unpack("i!*").map {|fd| IO.new(fd) } + recv_io_ary.concat ctl.rights } assert_equal(send_io_ary.length, recv_io_ary.length) send_io_ary.length.times {|i| @@ -126,13 +126,14 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase assert_instance_of(Addrinfo, srcaddr) assert_instance_of(Array, ctls) assert_equal(1, ctls.length) - assert_instance_of(Socket::AncillaryData, ctls[0]) - assert_equal(Socket::SOL_SOCKET, ctls[0].level) - assert_equal(Socket::SCM_RIGHTS, ctls[0].type) - assert_instance_of(String, ctls[0].data) - fd, rest = ctls[0].data.unpack("i!a*") - assert_equal("", rest) - r2 = IO.new(fd) + ctl = ctls[0] + assert_instance_of(Socket::AncillaryData, ctl) + assert_equal(Socket::SOL_SOCKET, ctl.level) + assert_equal(Socket::SCM_RIGHTS, ctl.type) + assert_instance_of(String, ctl.data) + ios = ctl.rights + assert_equal(1, ios.length) + r2 = ios[0] begin assert(File.identical?(r1, r2)) ensure |