ruby-changes:10856
From: akr <ko1@a...>
Date: Thu, 19 Feb 2009 03:43:32 +0900 (JST)
Subject: [ruby-changes:10856] Ruby:r22426 (trunk): * ext/socket/ancdata.c (ancillary_rights): new method.
akr 2009-02-19 03:43:15 +0900 (Thu, 19 Feb 2009) New Revision: 22426 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=22426 Log: * 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. Modified files: trunk/ChangeLog trunk/ext/socket/ancdata.c trunk/test/socket/test_unix.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 22425) +++ ChangeLog (revision 22426) @@ -1,3 +1,11 @@ +Thu Feb 19 03:42:48 2009 Tanaka Akira <akr@f...> + + * 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@i...> * README.EXT, README.EXT.ja: Improve the document about Index: ext/socket/ancdata.c =================================================================== --- ext/socket/ancdata.c (revision 22425) +++ ext/socket/ancdata.c (revision 22426) @@ -174,6 +174,29 @@ 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 @@ #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 @@ } ctlbuf0; char *ctlbuf; VALUE ctl_str = Qnil; + int family; #endif rb_secure(4); @@ -1288,17 +1341,17 @@ ); #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 @@ 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); Index: test/socket/test_unix.rb =================================================================== --- test/socket/test_unix.rb (revision 22425) +++ test/socket/test_unix.rb (revision 22426) @@ -53,7 +53,7 @@ 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 @@ 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/