ext/socket/init.c

Go to the documentation of this file.
00001 /************************************************
00002 
00003   init.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 VALUE rb_cBasicSocket;
00014 VALUE rb_cIPSocket;
00015 VALUE rb_cTCPSocket;
00016 VALUE rb_cTCPServer;
00017 VALUE rb_cUDPSocket;
00018 #ifdef AF_UNIX
00019 VALUE rb_cUNIXSocket;
00020 VALUE rb_cUNIXServer;
00021 #endif
00022 VALUE rb_cSocket;
00023 VALUE rb_cAddrinfo;
00024 
00025 VALUE rb_eSocket;
00026 
00027 #ifdef SOCKS
00028 VALUE rb_cSOCKSSocket;
00029 #endif
00030 
00031 int rsock_do_not_reverse_lookup = 1;
00032 
00033 void
00034 rsock_raise_socket_error(const char *reason, int error)
00035 {
00036 #ifdef EAI_SYSTEM
00037     if (error == EAI_SYSTEM) rb_sys_fail(reason);
00038 #endif
00039     rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
00040 }
00041 
00042 VALUE
00043 rsock_init_sock(VALUE sock, int fd)
00044 {
00045     rb_io_t *fp;
00046 #ifndef _WIN32
00047     struct stat sbuf;
00048 
00049     if (fstat(fd, &sbuf) < 0)
00050         rb_sys_fail("fstat(2)");
00051     rb_update_max_fd(fd);
00052     if (!S_ISSOCK(sbuf.st_mode))
00053         rb_raise(rb_eArgError, "not a socket file descriptor");
00054 #else
00055     rb_update_max_fd(fd);
00056     if (!rb_w32_is_socket(fd))
00057         rb_raise(rb_eArgError, "not a socket file descriptor");
00058 #endif
00059 
00060     MakeOpenFile(sock, fp);
00061     fp->fd = fd;
00062     fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
00063     rb_io_ascii8bit_binmode(sock);
00064     if (rsock_do_not_reverse_lookup) {
00065         fp->mode |= FMODE_NOREVLOOKUP;
00066     }
00067     rb_io_synchronized(fp);
00068 
00069     return sock;
00070 }
00071 
00072 VALUE
00073 rsock_sendto_blocking(void *data)
00074 {
00075     struct rsock_send_arg *arg = data;
00076     VALUE mesg = arg->mesg;
00077     return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
00078                          arg->flags, arg->to, arg->tolen);
00079 }
00080 
00081 VALUE
00082 rsock_send_blocking(void *data)
00083 {
00084     struct rsock_send_arg *arg = data;
00085     VALUE mesg = arg->mesg;
00086     return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
00087                        arg->flags);
00088 }
00089 
00090 struct recvfrom_arg {
00091     int fd, flags;
00092     VALUE str;
00093     socklen_t alen;
00094     union_sockaddr buf;
00095 };
00096 
00097 static VALUE
00098 recvfrom_blocking(void *data)
00099 {
00100     struct recvfrom_arg *arg = data;
00101     socklen_t len0 = arg->alen;
00102     ssize_t ret;
00103     ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
00104                    arg->flags, &arg->buf.addr, &arg->alen);
00105     if (ret != -1 && len0 < arg->alen)
00106         arg->alen = len0;
00107     return (VALUE)ret;
00108 }
00109 
00110 VALUE
00111 rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
00112 {
00113     rb_io_t *fptr;
00114     VALUE str, klass;
00115     struct recvfrom_arg arg;
00116     VALUE len, flg;
00117     long buflen;
00118     long slen;
00119 
00120     rb_scan_args(argc, argv, "11", &len, &flg);
00121 
00122     if (flg == Qnil) arg.flags = 0;
00123     else             arg.flags = NUM2INT(flg);
00124     buflen = NUM2INT(len);
00125 
00126     GetOpenFile(sock, fptr);
00127     if (rb_io_read_pending(fptr)) {
00128         rb_raise(rb_eIOError, "recv for buffered IO");
00129     }
00130     arg.fd = fptr->fd;
00131     arg.alen = (socklen_t)sizeof(arg.buf);
00132 
00133     arg.str = str = rb_tainted_str_new(0, buflen);
00134     klass = RBASIC(str)->klass;
00135     rb_obj_hide(str);
00136 
00137     while (rb_io_check_closed(fptr),
00138            rb_thread_wait_fd(arg.fd),
00139            (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) {
00140         if (!rb_io_wait_readable(fptr->fd)) {
00141             rb_sys_fail("recvfrom(2)");
00142         }
00143         if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
00144             rb_raise(rb_eRuntimeError, "buffer string modified");
00145         }
00146     }
00147 
00148     rb_obj_reveal(str, klass);
00149     if (slen < RSTRING_LEN(str)) {
00150         rb_str_set_len(str, slen);
00151     }
00152     rb_obj_taint(str);
00153     switch (from) {
00154       case RECV_RECV:
00155         return str;
00156       case RECV_IP:
00157 #if 0
00158         if (arg.alen != sizeof(struct sockaddr_in)) {
00159             rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
00160         }
00161 #endif
00162         if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
00163             return rb_assoc_new(str, rsock_ipaddr(&arg.buf.addr, arg.alen, fptr->mode & FMODE_NOREVLOOKUP));
00164         else
00165             return rb_assoc_new(str, Qnil);
00166 
00167 #ifdef HAVE_SYS_UN_H
00168       case RECV_UNIX:
00169         return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
00170 #endif
00171       case RECV_SOCKET:
00172         return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, &arg.buf.addr, arg.alen));
00173       default:
00174         rb_bug("rsock_s_recvfrom called with bad value");
00175     }
00176 }
00177 
00178 VALUE
00179 rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
00180 {
00181     rb_io_t *fptr;
00182     VALUE str;
00183     union_sockaddr buf;
00184     socklen_t alen = (socklen_t)sizeof buf;
00185     VALUE len, flg;
00186     long buflen;
00187     long slen;
00188     int fd, flags;
00189     VALUE addr = Qnil;
00190     socklen_t len0;
00191 
00192     rb_scan_args(argc, argv, "11", &len, &flg);
00193 
00194     if (flg == Qnil) flags = 0;
00195     else             flags = NUM2INT(flg);
00196     buflen = NUM2INT(len);
00197 
00198 #ifdef MSG_DONTWAIT
00199     /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
00200        It is not portable, though. */
00201     flags |= MSG_DONTWAIT;
00202 #endif
00203 
00204     GetOpenFile(sock, fptr);
00205     if (rb_io_read_pending(fptr)) {
00206         rb_raise(rb_eIOError, "recvfrom for buffered IO");
00207     }
00208     fd = fptr->fd;
00209 
00210     str = rb_tainted_str_new(0, buflen);
00211 
00212     rb_io_check_closed(fptr);
00213     rb_io_set_nonblock(fptr);
00214     len0 = alen;
00215     slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, &buf.addr, &alen);
00216     if (slen != -1 && len0 < alen)
00217         alen = len0;
00218 
00219     if (slen < 0) {
00220         switch (errno) {
00221           case EAGAIN:
00222 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
00223           case EWOULDBLOCK:
00224 #endif
00225             rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
00226         }
00227         rb_sys_fail("recvfrom(2)");
00228     }
00229     if (slen < RSTRING_LEN(str)) {
00230         rb_str_set_len(str, slen);
00231     }
00232     rb_obj_taint(str);
00233     switch (from) {
00234       case RECV_RECV:
00235         return str;
00236 
00237       case RECV_IP:
00238         if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
00239             addr = rsock_ipaddr(&buf.addr, alen, fptr->mode & FMODE_NOREVLOOKUP);
00240         break;
00241 
00242       case RECV_SOCKET:
00243         addr = rsock_io_socket_addrinfo(sock, &buf.addr, alen);
00244         break;
00245 
00246       default:
00247         rb_bug("rsock_s_recvfrom_nonblock called with bad value");
00248     }
00249     return rb_assoc_new(str, addr);
00250 }
00251 
00252 static int
00253 rsock_socket0(int domain, int type, int proto)
00254 {
00255     int ret;
00256 
00257 #ifdef SOCK_CLOEXEC
00258     static int try_sock_cloexec = 1;
00259     if (try_sock_cloexec) {
00260         ret = socket(domain, type|SOCK_CLOEXEC, proto);
00261         if (ret == -1 && errno == EINVAL) {
00262             /* SOCK_CLOEXEC is available since Linux 2.6.27.  Linux 2.6.18 fails with EINVAL */
00263             ret = socket(domain, type, proto);
00264             if (ret != -1) {
00265                 try_sock_cloexec = 0;
00266             }
00267         }
00268     }
00269     else {
00270         ret = socket(domain, type, proto);
00271     }
00272 #else
00273     ret = socket(domain, type, proto);
00274 #endif
00275     if (ret == -1)
00276         return -1;
00277 
00278     rb_fd_fix_cloexec(ret);
00279 
00280     return ret;
00281 
00282 }
00283 
00284 int
00285 rsock_socket(int domain, int type, int proto)
00286 {
00287     int fd;
00288 
00289     fd = rsock_socket0(domain, type, proto);
00290     if (fd < 0) {
00291        if (errno == EMFILE || errno == ENFILE) {
00292            rb_gc();
00293            fd = rsock_socket0(domain, type, proto);
00294        }
00295     }
00296     if (0 <= fd)
00297         rb_update_max_fd(fd);
00298     return fd;
00299 }
00300 
00301 static int
00302 wait_connectable(int fd)
00303 {
00304     int sockerr;
00305     socklen_t sockerrlen;
00306     int revents;
00307     int ret;
00308 
00309     for (;;) {
00310         /*
00311          * Stevens book says, succuessful finish turn on RB_WAITFD_OUT and
00312          * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
00313          */
00314         revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
00315 
00316         if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) {
00317             sockerrlen = (socklen_t)sizeof(sockerr);
00318             ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00319 
00320             /*
00321              * Solaris getsockopt(SO_ERROR) return -1 and set errno
00322              * in getsockopt(). Let's return immediately.
00323              */
00324             if (ret < 0)
00325                 break;
00326             if (sockerr == 0) {
00327                 if (revents & RB_WAITFD_OUT)
00328                     break;
00329                 else
00330                     continue;   /* workaround for winsock */
00331             }
00332 
00333             /* BSD and Linux use sockerr. */
00334             errno = sockerr;
00335             ret = -1;
00336             break;
00337         }
00338 
00339         if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) {
00340             ret = 0;
00341             break;
00342         }
00343     }
00344 
00345     return ret;
00346 }
00347 
00348 #ifdef __CYGWIN__
00349 #define WAIT_IN_PROGRESS 10
00350 #endif
00351 #ifdef __APPLE__
00352 #define WAIT_IN_PROGRESS 10
00353 #endif
00354 #ifdef __linux__
00355 /* returns correct error */
00356 #define WAIT_IN_PROGRESS 0
00357 #endif
00358 #ifndef WAIT_IN_PROGRESS
00359 /* BSD origin code apparently has a problem */
00360 #define WAIT_IN_PROGRESS 1
00361 #endif
00362 
00363 struct connect_arg {
00364     int fd;
00365     const struct sockaddr *sockaddr;
00366     socklen_t len;
00367 };
00368 
00369 static VALUE
00370 connect_blocking(void *data)
00371 {
00372     struct connect_arg *arg = data;
00373     return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
00374 }
00375 
00376 #if defined(SOCKS) && !defined(SOCKS5)
00377 static VALUE
00378 socks_connect_blocking(void *data)
00379 {
00380     struct connect_arg *arg = data;
00381     return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
00382 }
00383 #endif
00384 
00385 int
00386 rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
00387 {
00388     int status;
00389     rb_blocking_function_t *func = connect_blocking;
00390     struct connect_arg arg;
00391 #if WAIT_IN_PROGRESS > 0
00392     int wait_in_progress = -1;
00393     int sockerr;
00394     socklen_t sockerrlen;
00395 #endif
00396 
00397     arg.fd = fd;
00398     arg.sockaddr = sockaddr;
00399     arg.len = len;
00400 #if defined(SOCKS) && !defined(SOCKS5)
00401     if (socks) func = socks_connect_blocking;
00402 #endif
00403     for (;;) {
00404         status = (int)BLOCKING_REGION_FD(func, &arg);
00405         if (status < 0) {
00406             switch (errno) {
00407               case EINTR:
00408 #if defined(ERESTART)
00409               case ERESTART:
00410 #endif
00411                 continue;
00412 
00413               case EAGAIN:
00414 #ifdef EINPROGRESS
00415               case EINPROGRESS:
00416 #endif
00417 #if WAIT_IN_PROGRESS > 0
00418                 sockerrlen = (socklen_t)sizeof(sockerr);
00419                 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00420                 if (status) break;
00421                 if (sockerr) {
00422                     status = -1;
00423                     errno = sockerr;
00424                     break;
00425                 }
00426 #endif
00427 #ifdef EALREADY
00428               case EALREADY:
00429 #endif
00430 #if WAIT_IN_PROGRESS > 0
00431                 wait_in_progress = WAIT_IN_PROGRESS;
00432 #endif
00433                 status = wait_connectable(fd);
00434                 if (status) {
00435                     break;
00436                 }
00437                 errno = 0;
00438                 continue;
00439 
00440 #if WAIT_IN_PROGRESS > 0
00441               case EINVAL:
00442                 if (wait_in_progress-- > 0) {
00443                     /*
00444                      * connect() after EINPROGRESS returns EINVAL on
00445                      * some platforms, need to check true error
00446                      * status.
00447                      */
00448                     sockerrlen = (socklen_t)sizeof(sockerr);
00449                     status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00450                     if (!status && !sockerr) {
00451                         struct timeval tv = {0, 100000};
00452                         rb_thread_wait_for(tv);
00453                         continue;
00454                     }
00455                     status = -1;
00456                     errno = sockerr;
00457                 }
00458                 break;
00459 #endif
00460 
00461 #ifdef EISCONN
00462               case EISCONN:
00463                 status = 0;
00464                 errno = 0;
00465                 break;
00466 #endif
00467               default:
00468                 break;
00469             }
00470         }
00471         return status;
00472     }
00473 }
00474 
00475 static void
00476 make_fd_nonblock(int fd)
00477 {
00478     int flags;
00479 #ifdef F_GETFL
00480     flags = fcntl(fd, F_GETFL);
00481     if (flags == -1) {
00482         rb_sys_fail("fnctl(2)");
00483     }
00484 #else
00485     flags = 0;
00486 #endif
00487     flags |= O_NONBLOCK;
00488     if (fcntl(fd, F_SETFL, flags) == -1) {
00489         rb_sys_fail("fnctl(2)");
00490     }
00491 }
00492 
00493 static int
00494 cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len)
00495 {
00496     int ret;
00497     socklen_t len0 = 0;
00498 #ifdef HAVE_ACCEPT4
00499     static int try_accept4 = 1;
00500 #endif
00501     if (address_len) len0 = *address_len;
00502 #ifdef HAVE_ACCEPT4
00503     if (try_accept4) {
00504         int flags = 0;
00505 #ifdef SOCK_CLOEXEC
00506         flags |= SOCK_CLOEXEC;
00507 #endif
00508         ret = accept4(socket, address, address_len, flags);
00509         /* accept4 is available since Linux 2.6.28, glibc 2.10. */
00510         if (ret != -1) {
00511             if (ret <= 2)
00512                 rb_maygvl_fd_fix_cloexec(ret);
00513             if (address_len && len0 < *address_len) *address_len = len0;
00514             return ret;
00515         }
00516         if (errno != ENOSYS) {
00517             return -1;
00518         }
00519         try_accept4 = 0;
00520     }
00521 #endif
00522     ret = accept(socket, address, address_len);
00523     if (ret == -1) return -1;
00524     if (address_len && len0 < *address_len) *address_len = len0;
00525     rb_maygvl_fd_fix_cloexec(ret);
00526     return ret;
00527 }
00528 
00529 
00530 VALUE
00531 rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
00532 {
00533     int fd2;
00534 
00535     rb_secure(3);
00536     rb_io_set_nonblock(fptr);
00537     fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len);
00538     if (fd2 < 0) {
00539         switch (errno) {
00540           case EAGAIN:
00541 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
00542           case EWOULDBLOCK:
00543 #endif
00544           case ECONNABORTED:
00545 #if defined EPROTO
00546           case EPROTO:
00547 #endif
00548             rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
00549         }
00550         rb_sys_fail("accept(2)");
00551     }
00552     rb_update_max_fd(fd2);
00553     make_fd_nonblock(fd2);
00554     return rsock_init_sock(rb_obj_alloc(klass), fd2);
00555 }
00556 
00557 struct accept_arg {
00558     int fd;
00559     struct sockaddr *sockaddr;
00560     socklen_t *len;
00561 };
00562 
00563 static VALUE
00564 accept_blocking(void *data)
00565 {
00566     struct accept_arg *arg = data;
00567     return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len);
00568 }
00569 
00570 VALUE
00571 rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
00572 {
00573     int fd2;
00574     int retry = 0;
00575     struct accept_arg arg;
00576 
00577     rb_secure(3);
00578     arg.fd = fd;
00579     arg.sockaddr = sockaddr;
00580     arg.len = len;
00581   retry:
00582     rb_thread_wait_fd(fd);
00583     fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
00584     if (fd2 < 0) {
00585         switch (errno) {
00586           case EMFILE:
00587           case ENFILE:
00588             if (retry) break;
00589             rb_gc();
00590             retry = 1;
00591             goto retry;
00592           default:
00593             if (!rb_io_wait_readable(fd)) break;
00594             retry = 0;
00595             goto retry;
00596         }
00597         rb_sys_fail("accept(2)");
00598     }
00599     rb_update_max_fd(fd2);
00600     if (!klass) return INT2NUM(fd2);
00601     return rsock_init_sock(rb_obj_alloc(klass), fd2);
00602 }
00603 
00604 int
00605 rsock_getfamily(int sockfd)
00606 {
00607     union_sockaddr ss;
00608     socklen_t sslen = (socklen_t)sizeof(ss);
00609 
00610     ss.addr.sa_family = AF_UNSPEC;
00611     if (getsockname(sockfd, &ss.addr, &sslen) < 0)
00612         return AF_UNSPEC;
00613 
00614     return ss.addr.sa_family;
00615 }
00616 
00617 void
00618 rsock_init_socket_init()
00619 {
00620     /*
00621      * SocketError is the error class for socket.
00622      */
00623     rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
00624     rsock_init_ipsocket();
00625     rsock_init_tcpsocket();
00626     rsock_init_tcpserver();
00627     rsock_init_sockssocket();
00628     rsock_init_udpsocket();
00629     rsock_init_unixsocket();
00630     rsock_init_unixserver();
00631     rsock_init_sockopt();
00632     rsock_init_ancdata();
00633     rsock_init_addrinfo();
00634     rsock_init_sockifaddr();
00635     rsock_init_socket_constants();
00636 }
00637 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7