Ruby  2.0.0p247(2013-06-27revision41674)
ext/socket/unixsocket.c
Go to the documentation of this file.
00001 /************************************************
00002 
00003   unixsocket.c -
00004 
00005   created at: Thu Mar 31 12:21:29 JST 1994
00006 
00007   Copyright (C) 1993-2007 Yukihiro Matsumoto
00008 
00009 ************************************************/
00010 
00011 #include "rubysocket.h"
00012 
00013 #ifdef HAVE_SYS_UN_H
00014 struct unixsock_arg {
00015     struct sockaddr_un *sockaddr;
00016     socklen_t sockaddrlen;
00017     int fd;
00018 };
00019 
00020 static VALUE
00021 unixsock_connect_internal(VALUE a)
00022 {
00023     struct unixsock_arg *arg = (struct unixsock_arg *)a;
00024     return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
00025                                 arg->sockaddrlen, 0);
00026 }
00027 
00028 VALUE
00029 rsock_init_unixsock(VALUE sock, VALUE path, int server)
00030 {
00031     struct sockaddr_un sockaddr;
00032     socklen_t sockaddrlen;
00033     int fd, status;
00034     rb_io_t *fptr;
00035 
00036     SafeStringValue(path);
00037     fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0);
00038     if (fd < 0) {
00039         rb_sys_fail("socket(2)");
00040     }
00041 
00042     MEMZERO(&sockaddr, struct sockaddr_un, 1);
00043     sockaddr.sun_family = AF_UNIX;
00044     if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
00045         rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)",
00046             RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path));
00047     }
00048     memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
00049     sockaddrlen = rsock_unix_sockaddr_len(path);
00050 
00051     if (server) {
00052         status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen);
00053     }
00054     else {
00055         int prot;
00056         struct unixsock_arg arg;
00057         arg.sockaddr = &sockaddr;
00058         arg.sockaddrlen = sockaddrlen;
00059         arg.fd = fd;
00060         status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot);
00061         if (prot) {
00062             close(fd);
00063             rb_jump_tag(prot);
00064         }
00065     }
00066 
00067     if (status < 0) {
00068         close(fd);
00069         rb_sys_fail_str(rb_inspect(path));
00070     }
00071 
00072     if (server) {
00073         if (listen(fd, SOMAXCONN) < 0) {
00074             close(fd);
00075             rb_sys_fail("listen(2)");
00076         }
00077     }
00078 
00079     rsock_init_sock(sock, fd);
00080     if (server) {
00081         GetOpenFile(sock, fptr);
00082         fptr->pathv = rb_str_new_frozen(path);
00083     }
00084 
00085     return sock;
00086 }
00087 
00088 /*
00089  * call-seq:
00090  *   UNIXSocket.new(path) => unixsocket
00091  *
00092  * Creates a new UNIX client socket connected to _path_.
00093  *
00094  *   s = UNIXSocket.new("/tmp/sock")
00095  *   s.send "hello", 0
00096  *
00097  */
00098 static VALUE
00099 unix_init(VALUE sock, VALUE path)
00100 {
00101     return rsock_init_unixsock(sock, path, 0);
00102 }
00103 
00104 /*
00105  * call-seq:
00106  *   unixsocket.path => path
00107  *
00108  * Returns the path of the local address of unixsocket.
00109  *
00110  *   s = UNIXServer.new("/tmp/sock")
00111  *   p s.path #=> "/tmp/sock"
00112  *
00113  */
00114 static VALUE
00115 unix_path(VALUE sock)
00116 {
00117     rb_io_t *fptr;
00118 
00119     GetOpenFile(sock, fptr);
00120     if (NIL_P(fptr->pathv)) {
00121         struct sockaddr_un addr;
00122         socklen_t len = (socklen_t)sizeof(addr);
00123         socklen_t len0 = len;
00124         if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00125             rb_sys_fail(0);
00126         if (len0 < len) len = len0;
00127         fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len));
00128     }
00129     return rb_str_dup(fptr->pathv);
00130 }
00131 
00132 /*
00133  * call-seq:
00134  *   unixsocket.recvfrom(maxlen [, flags]) => [mesg, unixaddress]
00135  *
00136  * Receives a message via _unixsocket_.
00137  *
00138  * _maxlen_ is the maximum number of bytes to receive.
00139  *
00140  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
00141  *
00142  *   s1 = Socket.new(:UNIX, :DGRAM, 0)
00143  *   s1_ai = Addrinfo.unix("/tmp/sock1")
00144  *   s1.bind(s1_ai)
00145  *
00146  *   s2 = Socket.new(:UNIX, :DGRAM, 0)
00147  *   s2_ai = Addrinfo.unix("/tmp/sock2")
00148  *   s2.bind(s2_ai)
00149  *   s3 = UNIXSocket.for_fd(s2.fileno)
00150  *
00151  *   s1.send "a", 0, s2_ai
00152  *   p s3.recvfrom(10) #=> ["a", ["AF_UNIX", "/tmp/sock1"]]
00153  *
00154  */
00155 static VALUE
00156 unix_recvfrom(int argc, VALUE *argv, VALUE sock)
00157 {
00158     return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX);
00159 }
00160 
00161 #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS)
00162 #define FD_PASSING_BY_MSG_CONTROL 1
00163 #else
00164 #define FD_PASSING_BY_MSG_CONTROL 0
00165 #endif
00166 
00167 #if defined(HAVE_ST_MSG_ACCRIGHTS)
00168 #define FD_PASSING_BY_MSG_ACCRIGHTS 1
00169 #else
00170 #define FD_PASSING_BY_MSG_ACCRIGHTS 0
00171 #endif
00172 
00173 struct iomsg_arg {
00174     int fd;
00175     struct msghdr msg;
00176 };
00177 
00178 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
00179 static VALUE
00180 sendmsg_blocking(void *data)
00181 {
00182     struct iomsg_arg *arg = data;
00183     return sendmsg(arg->fd, &arg->msg, 0);
00184 }
00185 
00186 /*
00187  * call-seq:
00188  *   unixsocket.send_io(io) => nil
00189  *
00190  * Sends _io_ as file descriptor passing.
00191  *
00192  *   s1, s2 = UNIXSocket.pair
00193  *
00194  *   s1.send_io STDOUT
00195  *   stdout = s2.recv_io
00196  *
00197  *   p STDOUT.fileno #=> 1
00198  *   p stdout.fileno #=> 6
00199  *
00200  *   stdout.puts "hello" # outputs "hello\n" to standard output.
00201  */
00202 static VALUE
00203 unix_send_io(VALUE sock, VALUE val)
00204 {
00205     int fd;
00206     rb_io_t *fptr;
00207     struct iomsg_arg arg;
00208     struct iovec vec[1];
00209     char buf[1];
00210 
00211 #if FD_PASSING_BY_MSG_CONTROL
00212     struct {
00213         struct cmsghdr hdr;
00214         char pad[8+sizeof(int)+8];
00215     } cmsg;
00216 #endif
00217 
00218     if (rb_obj_is_kind_of(val, rb_cIO)) {
00219         rb_io_t *valfptr;
00220         GetOpenFile(val, valfptr);
00221         fd = valfptr->fd;
00222     }
00223     else if (FIXNUM_P(val)) {
00224         fd = FIX2INT(val);
00225     }
00226     else {
00227         rb_raise(rb_eTypeError, "neither IO nor file descriptor");
00228     }
00229 
00230     GetOpenFile(sock, fptr);
00231 
00232     arg.msg.msg_name = NULL;
00233     arg.msg.msg_namelen = 0;
00234 
00235     /* Linux and Solaris doesn't work if msg_iov is NULL. */
00236     buf[0] = '\0';
00237     vec[0].iov_base = buf;
00238     vec[0].iov_len = 1;
00239     arg.msg.msg_iov = vec;
00240     arg.msg.msg_iovlen = 1;
00241 
00242 #if FD_PASSING_BY_MSG_CONTROL
00243     arg.msg.msg_control = (caddr_t)&cmsg;
00244     arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int));
00245     arg.msg.msg_flags = 0;
00246     MEMZERO((char*)&cmsg, char, sizeof(cmsg));
00247     cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
00248     cmsg.hdr.cmsg_level = SOL_SOCKET;
00249     cmsg.hdr.cmsg_type = SCM_RIGHTS;
00250     memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
00251 #else
00252     arg.msg.msg_accrights = (caddr_t)&fd;
00253     arg.msg.msg_accrightslen = sizeof(fd);
00254 #endif
00255 
00256     arg.fd = fptr->fd;
00257     while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) {
00258         if (!rb_io_wait_writable(arg.fd))
00259             rb_sys_fail("sendmsg(2)");
00260     }
00261 
00262     return Qnil;
00263 }
00264 #else
00265 #define unix_send_io rb_f_notimplement
00266 #endif
00267 
00268 #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
00269 static VALUE
00270 recvmsg_blocking(void *data)
00271 {
00272     struct iomsg_arg *arg = data;
00273     int flags = 0;
00274     return rsock_recvmsg(arg->fd, &arg->msg, flags);
00275 }
00276 
00277 /*
00278  * call-seq:
00279  *   unixsocket.recv_io([klass [, mode]]) => io
00280  *
00281  *   UNIXServer.open("/tmp/sock") {|serv|
00282  *     UNIXSocket.open("/tmp/sock") {|c|
00283  *       s = serv.accept
00284  *
00285  *       c.send_io STDOUT
00286  *       stdout = s.recv_io
00287  *
00288  *       p STDOUT.fileno #=> 1
00289  *       p stdout.fileno #=> 7
00290  *
00291  *       stdout.puts "hello" # outputs "hello\n" to standard output.
00292  *     }
00293  *   }
00294  *
00295  */
00296 static VALUE
00297 unix_recv_io(int argc, VALUE *argv, VALUE sock)
00298 {
00299     VALUE klass, mode;
00300     rb_io_t *fptr;
00301     struct iomsg_arg arg;
00302     struct iovec vec[2];
00303     char buf[1];
00304 
00305     int fd;
00306 #if FD_PASSING_BY_MSG_CONTROL
00307     struct {
00308         struct cmsghdr hdr;
00309         char pad[8+sizeof(int)+8];
00310     } cmsg;
00311 #endif
00312 
00313     rb_scan_args(argc, argv, "02", &klass, &mode);
00314     if (argc == 0)
00315         klass = rb_cIO;
00316     if (argc <= 1)
00317         mode = Qnil;
00318 
00319     GetOpenFile(sock, fptr);
00320 
00321     arg.msg.msg_name = NULL;
00322     arg.msg.msg_namelen = 0;
00323 
00324     vec[0].iov_base = buf;
00325     vec[0].iov_len = sizeof(buf);
00326     arg.msg.msg_iov = vec;
00327     arg.msg.msg_iovlen = 1;
00328 
00329 #if FD_PASSING_BY_MSG_CONTROL
00330     arg.msg.msg_control = (caddr_t)&cmsg;
00331     arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int));
00332     arg.msg.msg_flags = 0;
00333     cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
00334     cmsg.hdr.cmsg_level = SOL_SOCKET;
00335     cmsg.hdr.cmsg_type = SCM_RIGHTS;
00336     fd = -1;
00337     memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
00338 #else
00339     arg.msg.msg_accrights = (caddr_t)&fd;
00340     arg.msg.msg_accrightslen = sizeof(fd);
00341     fd = -1;
00342 #endif
00343 
00344     arg.fd = fptr->fd;
00345     while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) {
00346         if (!rb_io_wait_readable(arg.fd))
00347             rb_sys_fail("recvmsg(2)");
00348     }
00349 
00350 #if FD_PASSING_BY_MSG_CONTROL
00351     if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) {
00352         rb_raise(rb_eSocket,
00353                  "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)",
00354                  (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr));
00355     }
00356     if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
00357         rb_raise(rb_eSocket,
00358                  "file descriptor was not passed (cmsg_level=%d, %d expected)",
00359                  cmsg.hdr.cmsg_level, SOL_SOCKET);
00360     }
00361     if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
00362         rb_raise(rb_eSocket,
00363                  "file descriptor was not passed (cmsg_type=%d, %d expected)",
00364                  cmsg.hdr.cmsg_type, SCM_RIGHTS);
00365     }
00366     if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) {
00367         rb_raise(rb_eSocket,
00368                  "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)",
00369                  (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int)));
00370     }
00371     if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) {
00372         rb_raise(rb_eSocket,
00373                  "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)",
00374                  (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
00375     }
00376     if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
00377         rsock_discard_cmsg_resource(&arg.msg, 0);
00378         rb_raise(rb_eSocket,
00379                  "file descriptor was not passed (cmsg_len=%d, %d expected)",
00380                  (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
00381     }
00382 #else
00383     if (arg.msg.msg_accrightslen != sizeof(fd)) {
00384         rb_raise(rb_eSocket,
00385                  "file descriptor was not passed (accrightslen) : %d != %d",
00386                  arg.msg.msg_accrightslen, (int)sizeof(fd));
00387     }
00388 #endif
00389 
00390 #if FD_PASSING_BY_MSG_CONTROL
00391     memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
00392 #endif
00393     rb_fd_fix_cloexec(fd);
00394 
00395     if (klass == Qnil)
00396         return INT2FIX(fd);
00397     else {
00398         ID for_fd;
00399         int ff_argc;
00400         VALUE ff_argv[2];
00401         CONST_ID(for_fd, "for_fd");
00402         ff_argc = mode == Qnil ? 1 : 2;
00403         ff_argv[0] = INT2FIX(fd);
00404         ff_argv[1] = mode;
00405         return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
00406     }
00407 }
00408 #else
00409 #define unix_recv_io rb_f_notimplement
00410 #endif
00411 
00412 /*
00413  * call-seq:
00414  *   unixsocket.addr => [address_family, unix_path]
00415  *
00416  * Returns the local address as an array which contains
00417  * address_family and unix_path.
00418  *
00419  * Example
00420  *   serv = UNIXServer.new("/tmp/sock")
00421  *   p serv.addr #=> ["AF_UNIX", "/tmp/sock"]
00422  */
00423 static VALUE
00424 unix_addr(VALUE sock)
00425 {
00426     rb_io_t *fptr;
00427     struct sockaddr_un addr;
00428     socklen_t len = (socklen_t)sizeof addr;
00429     socklen_t len0 = len;
00430 
00431     GetOpenFile(sock, fptr);
00432 
00433     if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00434         rb_sys_fail("getsockname(2)");
00435     if (len0 < len) len = len0;
00436     return rsock_unixaddr(&addr, len);
00437 }
00438 
00439 /*
00440  * call-seq:
00441  *   unixsocket.peeraddr => [address_family, unix_path]
00442  *
00443  * Returns the remote address as an array which contains
00444  * address_family and unix_path.
00445  *
00446  * Example
00447  *   serv = UNIXServer.new("/tmp/sock")
00448  *   c = UNIXSocket.new("/tmp/sock")
00449  *   p c.peeraddr #=> ["AF_UNIX", "/tmp/sock"]
00450  */
00451 static VALUE
00452 unix_peeraddr(VALUE sock)
00453 {
00454     rb_io_t *fptr;
00455     struct sockaddr_un addr;
00456     socklen_t len = (socklen_t)sizeof addr;
00457     socklen_t len0 = len;
00458 
00459     GetOpenFile(sock, fptr);
00460 
00461     if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00462         rb_sys_fail("getpeername(2)");
00463     if (len0 < len) len = len0;
00464     return rsock_unixaddr(&addr, len);
00465 }
00466 
00467 /*
00468  * call-seq:
00469  *   UNIXSocket.pair([type [, protocol]])       => [unixsocket1, unixsocket2]
00470  *   UNIXSocket.socketpair([type [, protocol]]) => [unixsocket1, unixsocket2]
00471  *
00472  * Creates a pair of sockets connected each other.
00473  *
00474  * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
00475  *
00476  * _protocol_ should be a protocol defined in the domain.
00477  * 0 is default protocol for the domain.
00478  *
00479  *   s1, s2 = UNIXSocket.pair
00480  *   s1.send "a", 0
00481  *   s1.send "b", 0
00482  *   p s2.recv(10) #=> "ab"
00483  *
00484  */
00485 static VALUE
00486 unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
00487 {
00488     VALUE domain, type, protocol;
00489     VALUE args[3];
00490 
00491     domain = INT2FIX(PF_UNIX);
00492     rb_scan_args(argc, argv, "02", &type, &protocol);
00493     if (argc == 0)
00494         type = INT2FIX(SOCK_STREAM);
00495     if (argc <= 1)
00496         protocol = INT2FIX(0);
00497 
00498     args[0] = domain;
00499     args[1] = type;
00500     args[2] = protocol;
00501 
00502     return rsock_sock_s_socketpair(3, args, klass);
00503 }
00504 #endif
00505 
00506 void
00507 rsock_init_unixsocket(void)
00508 {
00509 #ifdef HAVE_SYS_UN_H
00510     /*
00511      * Document-class: UNIXSocket < BasicSocket
00512      *
00513      * UNIXSocket represents a UNIX domain stream client socket.
00514      */
00515     rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
00516     rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1);
00517     rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
00518     rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
00519     rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
00520     rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
00521     rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
00522     rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
00523     rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1);
00524     rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1);
00525 #endif
00526 }
00527