From: Tanaka Akira Date: 2002-02-25T17:42:41+09:00 Subject: [ruby-dev:16068] UNIXSocket#{send_io,recv_io} --Multipart_Mon_Feb_25_17:44:01_2002-1 Content-Type: text/plain; charset=ISO-2022-JP $B$7$P$i$/A0$K$U$H5$$,8~$$$F(B UNIXSocket#{send_io,recv_io} $B$H$$$&$b$N$r$G$C(B $B$A$"$2$^$7$?!#$3$l$O(B send_msg, recv_msg $B$G(B file descriptor $B$r0[$J$k%W(B $B%m%;%94V$GAw$l$k$3$H$rMxMQ$7$F(B IO $B$rAw$k$H$$$&$b$N$G$9!#$^$!!"$@$$$?$$(B $B$N%7%9%F%`$GF0$/$h$&$G$9!#(B $B8D?ME*$K$O$H$/$KMQES$,$J$$$N$G;`B"$7$F$?$s$G$9$,!"5$$,8~$$$?$N$G(B ruby-dev $B$KAw$C$F$_$^$9!#6=L#$,$"$k?M$O$$$8$/$C$F$_$k$HLLGr$$$+$bCN$l(B $B$^$;$s!#(B $B$J$*!"(Bsocket.so $B$N%7%s%\%k$r3HD%%b%8%e!<%k$+$i;2>H$9$kJ}K!$,$o$+$i$J$+$C(B $B$?$N$G%Q%C%A$K$J$C$F$$$^$9!#(B --Multipart_Mon_Feb_25_17:44:01_2002-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="socket-extra.diff" Content-Transfer-Encoding: 7bit Index: ext/socket/extconf.rb =================================================================== RCS file: /src/ruby/ext/socket/extconf.rb,v retrieving revision 1.19 diff -u -r1.19 extconf.rb --- ext/socket/extconf.rb 2001/12/03 07:08:17 1.19 +++ ext/socket/extconf.rb 2002/02/25 08:31:53 @@ -2,6 +2,42 @@ $CPPFLAGS += " -Dss_family=__ss_family -Dss_len=__ss_len" +def have_struct_member(type, member, header=nil) + printf "checking for %s.%s... ", type, member + STDOUT.flush + + libs = $libs + src = + if /mswin32|mingw/ =~ RUBY_PLATFORM + r = <<"SRC" +#include +#include +SRC + else + "" + end + unless header.nil? + header = [header] unless header.kind_of? Array + header.each {|h| + src << <<"SRC" +#include <#{h}> +SRC + } + end + src << <<"SRC" +int main() { return 0; } +int s = (char *)&((#{type}*)0)->#{member} - (char *)0; +SRC + r = try_link(src, libs) # xxx try_compile is not available. + unless r + print "no\n" + return false + end + $defs.push(format("-DHAVE_ST_%s", member.upcase)) + print "yes\n" + return true +end + case RUBY_PLATFORM when /mswin32|mingw/ test_func = "WSACleanup" @@ -176,6 +212,9 @@ have_header("netinet/tcp.h") if not /cygwin/ === RUBY_PLATFORM # for cygwin 1.1.5 have_header("netinet/udp.h") +have_struct_member('struct msghdr', 'msg_control', header=['sys/types.h', 'sys/socket.h']) +have_struct_member('struct msghdr', 'msg_accrights', header=['sys/types.h', 'sys/socket.h']) + $getaddr_info_ok = false if not enable_config("wide-getaddrinfo", false) and try_run(< @@ -329,6 +368,7 @@ end have_header("sys/un.h") +have_header("sys/uio.h") if have_func(test_func) have_func("hsterror") Index: ext/socket/socket.c =================================================================== RCS file: /src/ruby/ext/socket/socket.c,v retrieving revision 1.65 diff -u -r1.65 socket.c --- ext/socket/socket.c 2002/02/05 07:56:31 1.65 +++ ext/socket/socket.c 2002/02/25 08:31:53 @@ -20,6 +20,10 @@ #include #endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + #ifndef NT #if defined(__BEOS__) # include @@ -684,6 +688,17 @@ } static void +thread_read_select(fd) + int fd; +{ + fd_set fds; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + rb_thread_select(fd+1, &fds, 0, 0, 0); +} + +static void thread_write_select(fd) int fd; { @@ -1382,6 +1397,161 @@ } static VALUE +unix_send_io(sock, val) + VALUE sock, val; +{ +#if defined(HAVE_ST_MSG_CONTROL) || defined(HAVE_ST_MSG_ACCRIGHTS) + int fd; + OpenFile *fptr; + struct msghdr msg; + struct iovec vec[1]; + char buf[1]; + +#if defined(HAVE_ST_MSG_CONTROL) + struct { + struct cmsghdr hdr; + int fd; + } cmsg; +#endif + + if (rb_obj_is_kind_of(val, rb_cIO)) { + OpenFile *valfptr; + GetOpenFile(val, valfptr); + fd = fileno(valfptr->f); + } + else if (FIXNUM_P(val)) { + fd = FIX2INT(val); + } + else { + rb_raise(rb_eTypeError, "IO nor file descriptor"); + } + + GetOpenFile(sock, fptr); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + /* Linux and Solaris doesn't work if msg_iov is NULL. */ + buf[0] = '\0'; + vec[0].iov_base = buf; + vec[0].iov_len = 1; + msg.msg_iov = vec; + msg.msg_iovlen = 1; + +#if defined(HAVE_ST_MSG_CONTROL) + msg.msg_control = (caddr_t)&cmsg; + msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int); + msg.msg_flags = 0; + cmsg.hdr.cmsg_len = sizeof(struct cmsghdr) + sizeof(int); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_RIGHTS; + cmsg.fd = fd; +#else + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); +#endif + + if (sendmsg(fileno(fptr->f), &msg, 0) == -1) + rb_sys_fail("sendmsg(2)"); + + return Qnil; +#else + rb_notimplement(); +#endif +} + +static VALUE +unix_recv_io(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ +#if defined(HAVE_ST_MSG_CONTROL) || defined(HAVE_ST_MSG_ACCRIGHTS) + VALUE klass, mode; + OpenFile *fptr; + struct msghdr msg; + struct iovec vec[2]; + char buf[1]; + + int fd; +#if defined(HAVE_ST_MSG_CONTROL) + struct { + struct cmsghdr hdr; + int fd; + } cmsg; +#endif + + rb_scan_args(argc, argv, "02", &mode, &klass); + if (argc == 0) + mode = Qnil; + if (argc <= 1) + klass = rb_cIO; + + GetOpenFile(sock, fptr); + + thread_read_select(fileno(fptr->f)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + vec[0].iov_base = buf; + vec[0].iov_len = sizeof(buf); + msg.msg_iov = vec; + msg.msg_iovlen = 1; + +#if defined(HAVE_ST_MSG_CONTROL) + msg.msg_control = (caddr_t)&cmsg; + msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int); + msg.msg_flags = 0; + cmsg.hdr.cmsg_len = sizeof(struct cmsghdr) + sizeof(int); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_RIGHTS; + cmsg.fd = -1; +#else + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); + fd = -1; +#endif + + if (recvmsg(fileno(fptr->f), &msg, 0) == -1) + rb_sys_fail("recvmsg(2)"); + + if ( +#if defined(HAVE_ST_MSG_CONTROL) + msg.msg_controllen != sizeof(struct cmsghdr) + sizeof(int) || + cmsg.hdr.cmsg_len != sizeof(struct cmsghdr) + sizeof(int) || + cmsg.hdr.cmsg_level != SOL_SOCKET || + cmsg.hdr.cmsg_type != SCM_RIGHTS +#else + msg.msg_accrightslen != sizeof(fd) +#endif + ) { + rb_raise(rb_eSocket, "File descriptor was not passed"); + } + +#if defined(HAVE_ST_MSG_CONTROL) + fd = cmsg.fd; +#endif + + if (klass == Qnil) + return INT2FIX(fd); + else { + static ID for_fd = 0; + int ff_argc; + VALUE ff_argv[2]; + if (!for_fd) + for_fd = rb_intern("for_fd"); + ff_argc = mode == Qnil ? 1 : 2; + ff_argv[0] = INT2FIX(fd); + ff_argv[1] = mode; + return rb_funcall2(klass, for_fd, ff_argc, ff_argv); + } +#else + rb_notimplement(); +#endif +} + +static VALUE unix_accept(sock) VALUE sock; { @@ -1564,6 +1734,26 @@ #endif } +#ifdef HAVE_SYS_UN_H +static VALUE +unix_s_socketpair(argc, argv, klass) + int argc; + VALUE *argv; + VALUE klass; +{ + VALUE domain, type, protocol; + domain = INT2FIX(PF_UNIX); + + rb_scan_args(argc, argv, "02", &type, &protocol); + if (argc == 0) + type = INT2FIX(SOCK_STREAM); + if (argc <= 1) + protocol = INT2FIX(0); + + return sock_s_socketpair(klass, domain, type, protocol); +} +#endif + static VALUE sock_connect(sock, addr) VALUE sock, addr; @@ -2177,6 +2367,10 @@ rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0); rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0); rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1); + rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1); + rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1); + rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1); + rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1); rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket); rb_define_global_const("UNIXserver", rb_cUNIXServer); --Multipart_Mon_Feb_25_17:44:01_2002-1 Content-Type: text/plain; charset=ISO-2022-JP-2 -- [$BEDCf(B $BE/(B][$B$?$J$+(B $B$"$-$i(B][Tanaka Akira] $B!V$U$($m(B! $B$o$+$a$A$c$s:n@o$G$9$(C"=$B!W(B(Little Worker, $B7KM7@84](B) --Multipart_Mon_Feb_25_17:44:01_2002-1--