Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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