mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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
This commit is contained in:
parent
2485ed5177
commit
18afbc891c
3 changed files with 73 additions and 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>
|
Thu Feb 19 03:28:59 2009 Akinori MUSHA <knu@iDaemons.org>
|
||||||
|
|
||||||
* README.EXT, README.EXT.ja: Improve the document about
|
* README.EXT, README.EXT.ja: Improve the document about
|
||||||
|
|
|
@ -174,6 +174,29 @@ ancillary_data(VALUE self)
|
||||||
return v;
|
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:
|
* call-seq:
|
||||||
|
@ -1121,6 +1144,35 @@ discard_cmsg_resource(struct msghdr *mh)
|
||||||
#endif
|
#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
|
static VALUE
|
||||||
bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
|
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;
|
} ctlbuf0;
|
||||||
char *ctlbuf;
|
char *ctlbuf;
|
||||||
VALUE ctl_str = Qnil;
|
VALUE ctl_str = Qnil;
|
||||||
|
int family;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rb_secure(4);
|
rb_secure(4);
|
||||||
|
@ -1288,17 +1341,17 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
|
||||||
);
|
);
|
||||||
|
|
||||||
#if defined(HAVE_ST_MSG_CONTROL)
|
#if defined(HAVE_ST_MSG_CONTROL)
|
||||||
|
family = rb_sock_getfamily(fptr->fd);
|
||||||
if (mh.msg_controllen) {
|
if (mh.msg_controllen) {
|
||||||
for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
|
for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
|
||||||
VALUE ctl;
|
VALUE ctl;
|
||||||
size_t clen;
|
size_t clen;
|
||||||
int family;
|
|
||||||
if (cmh->cmsg_len == 0) {
|
if (cmh->cmsg_len == 0) {
|
||||||
rb_raise(rb_eIOError, "invalid control message (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);
|
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));
|
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);
|
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, "level", ancillary_level_m, 0);
|
||||||
rb_define_method(rb_cAncillaryData, "type", ancillary_type_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, "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_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
|
||||||
rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
|
rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
|
||||||
rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
|
rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
|
||||||
|
|
|
@ -53,7 +53,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
||||||
recv_io_ary = []
|
recv_io_ary = []
|
||||||
ctls.each {|ctl|
|
ctls.each {|ctl|
|
||||||
next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS
|
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)
|
assert_equal(send_io_ary.length, recv_io_ary.length)
|
||||||
send_io_ary.length.times {|i|
|
send_io_ary.length.times {|i|
|
||||||
|
@ -126,13 +126,14 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase
|
||||||
assert_instance_of(Addrinfo, srcaddr)
|
assert_instance_of(Addrinfo, srcaddr)
|
||||||
assert_instance_of(Array, ctls)
|
assert_instance_of(Array, ctls)
|
||||||
assert_equal(1, ctls.length)
|
assert_equal(1, ctls.length)
|
||||||
assert_instance_of(Socket::AncillaryData, ctls[0])
|
ctl = ctls[0]
|
||||||
assert_equal(Socket::SOL_SOCKET, ctls[0].level)
|
assert_instance_of(Socket::AncillaryData, ctl)
|
||||||
assert_equal(Socket::SCM_RIGHTS, ctls[0].type)
|
assert_equal(Socket::SOL_SOCKET, ctl.level)
|
||||||
assert_instance_of(String, ctls[0].data)
|
assert_equal(Socket::SCM_RIGHTS, ctl.type)
|
||||||
fd, rest = ctls[0].data.unpack("i!a*")
|
assert_instance_of(String, ctl.data)
|
||||||
assert_equal("", rest)
|
ios = ctl.rights
|
||||||
r2 = IO.new(fd)
|
assert_equal(1, ios.length)
|
||||||
|
r2 = ios[0]
|
||||||
begin
|
begin
|
||||||
assert(File.identical?(r1, r2))
|
assert(File.identical?(r1, r2))
|
||||||
ensure
|
ensure
|
||||||
|
|
Loading…
Add table
Reference in a new issue