Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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     struct stat sbuf;
    00047
    00048 #ifndef _WIN32
    00049     if (fstat(fd, &sbuf) < 0)
    00050         rb_sys_fail(0);
    00051     if (!S_ISSOCK(sbuf.st_mode))
    00052         rb_raise(rb_eArgError, "not a socket file descriptor");
    00053 #else
    00054     if (!rb_w32_is_socket(fd))
    00055         rb_raise(rb_eArgError, "not a socket file descriptor");
    00056 #endif
    00057
    00058     MakeOpenFile(sock, fp);
    00059     fp->fd = fd;
    00060     fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
    00061     rb_io_ascii8bit_binmode(sock);
    00062     if (rsock_do_not_reverse_lookup) {
    00063         fp->mode |= FMODE_NOREVLOOKUP;
    00064     }
    00065     rb_io_synchronized(fp);
    00066
    00067     return sock;
    00068 }
    00069
    00070 VALUE
    00071 rsock_sendto_blocking(void *data)
    00072 {
    00073     struct rsock_send_arg *arg = data;
    00074     VALUE mesg = arg->mesg;
    00075     return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
    00076                          arg->flags, arg->to, arg->tolen);
    00077 }
    00078
    00079 VALUE
    00080 rsock_send_blocking(void *data)
    00081 {
    00082     struct rsock_send_arg *arg = data;
    00083     VALUE mesg = arg->mesg;
    00084     return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
    00085                        arg->flags);
    00086 }
    00087
    00088 struct recvfrom_arg {
    00089     int fd, flags;
    00090     VALUE str;
    00091     socklen_t alen;
    00092     struct sockaddr_storage buf;
    00093 };
    00094
    00095 static VALUE
    00096 recvfrom_blocking(void *data)
    00097 {
    00098     struct recvfrom_arg *arg = data;
    00099     return (VALUE)recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
    00100                            arg->flags, (struct sockaddr*)&arg->buf, &arg->alen);
    00101 }
    00102
    00103 VALUE
    00104 rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
    00105 {
    00106     rb_io_t *fptr;
    00107     VALUE str, klass;
    00108     struct recvfrom_arg arg;
    00109     VALUE len, flg;
    00110     long buflen;
    00111     long slen;
    00112
    00113     rb_scan_args(argc, argv, "11", &len, &flg);
    00114
    00115     if (flg == Qnil) arg.flags = 0;
    00116     else             arg.flags = NUM2INT(flg);
    00117     buflen = NUM2INT(len);
    00118
    00119     GetOpenFile(sock, fptr);
    00120     if (rb_io_read_pending(fptr)) {
    00121         rb_raise(rb_eIOError, "recv for buffered IO");
    00122     }
    00123     arg.fd = fptr->fd;
    00124     arg.alen = (socklen_t)sizeof(arg.buf);
    00125
    00126     arg.str = str = rb_tainted_str_new(0, buflen);
    00127     klass = RBASIC(str)->klass;
    00128     RBASIC(str)->klass = 0;
    00129
    00130     while (rb_io_check_closed(fptr),
    00131            rb_thread_wait_fd(arg.fd),
    00132            (slen = BLOCKING_REGION(recvfrom_blocking, &arg)) < 0) {
    00133         if (!rb_io_wait_readable(fptr->fd)) {
    00134             rb_sys_fail("recvfrom(2)");
    00135         }
    00136         if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
    00137             rb_raise(rb_eRuntimeError, "buffer string modified");
    00138         }
    00139     }
    00140
    00141     RBASIC(str)->klass = klass;
    00142     if (slen < RSTRING_LEN(str)) {
    00143         rb_str_set_len(str, slen);
    00144     }
    00145     rb_obj_taint(str);
    00146     switch (from) {
    00147       case RECV_RECV:
    00148         return str;
    00149       case RECV_IP:
    00150 #if 0
    00151         if (arg.alen != sizeof(struct sockaddr_in)) {
    00152             rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
    00153         }
    00154 #endif
    00155         if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
    00156             return rb_assoc_new(str, rsock_ipaddr((struct sockaddr*)&arg.buf, fptr->mode & FMODE_NOREVLOOKUP));
    00157         else
    00158             return rb_assoc_new(str, Qnil);
    00159
    00160 #ifdef HAVE_SYS_UN_H
    00161       case RECV_UNIX:
    00162         return rb_assoc_new(str, rsock_unixaddr((struct sockaddr_un*)&arg.buf, arg.alen));
    00163 #endif
    00164       case RECV_SOCKET:
    00165         return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, (struct sockaddr*)&arg.buf, arg.alen));
    00166       default:
    00167         rb_bug("rsock_s_recvfrom called with bad value");
    00168     }
    00169 }
    00170
    00171 VALUE
    00172 rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
    00173 {
    00174     rb_io_t *fptr;
    00175     VALUE str;
    00176     struct sockaddr_storage buf;
    00177     socklen_t alen = (socklen_t)sizeof buf;
    00178     VALUE len, flg;
    00179     long buflen;
    00180     long slen;
    00181     int fd, flags;
    00182     VALUE addr = Qnil;
    00183
    00184     rb_scan_args(argc, argv, "11", &len, &flg);
    00185
    00186     if (flg == Qnil) flags = 0;
    00187     else             flags = NUM2INT(flg);
    00188     buflen = NUM2INT(len);
    00189
    00190 #ifdef MSG_DONTWAIT
    00191     /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
    00192        It is not portable, though. */
    00193     flags |= MSG_DONTWAIT;
    00194 #endif
    00195
    00196     GetOpenFile(sock, fptr);
    00197     if (rb_io_read_pending(fptr)) {
    00198         rb_raise(rb_eIOError, "recvfrom for buffered IO");
    00199     }
    00200     fd = fptr->fd;
    00201
    00202     str = rb_tainted_str_new(0, buflen);
    00203
    00204     rb_io_check_closed(fptr);
    00205     rb_io_set_nonblock(fptr);
    00206     slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, (struct sockaddr*)&buf, &alen);
    00207
    00208     if (slen < 0) {
    00209         switch (errno) {
    00210           case EAGAIN:
    00211 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
    00212           case EWOULDBLOCK:
    00213 #endif
    00214             rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block");
    00215         }
    00216         rb_sys_fail("recvfrom(2)");
    00217     }
    00218     if (slen < RSTRING_LEN(str)) {
    00219         rb_str_set_len(str, slen);
    00220     }
    00221     rb_obj_taint(str);
    00222     switch (from) {
    00223       case RECV_RECV:
    00224         return str;
    00225
    00226       case RECV_IP:
    00227         if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
    00228             addr = rsock_ipaddr((struct sockaddr*)&buf, fptr->mode & FMODE_NOREVLOOKUP);
    00229         break;
    00230
    00231       case RECV_SOCKET:
    00232         addr = rsock_io_socket_addrinfo(sock, (struct sockaddr*)&buf, alen);
    00233         break;
    00234
    00235       default:
    00236         rb_bug("rsock_s_recvfrom_nonblock called with bad value");
    00237     }
    00238     return rb_assoc_new(str, addr);
    00239 }
    00240
    00241 int
    00242 rsock_socket(int domain, int type, int proto)
    00243 {
    00244     int fd;
    00245
    00246     fd = socket(domain, type, proto);
    00247     if (fd < 0) {
    00248         if (errno == EMFILE || errno == ENFILE) {
    00249             rb_gc();
    00250             fd = socket(domain, type, proto);
    00251         }
    00252     }
    00253     return fd;
    00254 }
    00255
    00256 static int
    00257 wait_connectable0(int fd, rb_fdset_t *fds_w, rb_fdset_t *fds_e)
    00258 {
    00259     int sockerr;
    00260     socklen_t sockerrlen;
    00261
    00262     for (;;) {
    00263         rb_fd_zero(fds_w);
    00264         rb_fd_zero(fds_e);
    00265
    00266         rb_fd_set(fd, fds_w);
    00267         rb_fd_set(fd, fds_e);
    00268
    00269         rb_thread_select(fd+1, 0, rb_fd_ptr(fds_w), rb_fd_ptr(fds_e), 0);
    00270
    00271         if (rb_fd_isset(fd, fds_w)) {
    00272             return 0;
    00273         }
    00274         else if (rb_fd_isset(fd, fds_e)) {
    00275             sockerrlen = (socklen_t)sizeof(sockerr);
    00276             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr,
    00277                            &sockerrlen) == 0) {
    00278                 if (sockerr == 0)
    00279                     continue;   /* workaround for winsock */
    00280                 errno = sockerr;
    00281             }
    00282             return -1;
    00283         }
    00284     }
    00285 }
    00286
    00287 struct wait_connectable_arg {
    00288     int fd;
    00289     rb_fdset_t fds_w;
    00290     rb_fdset_t fds_e;
    00291 };
    00292
    00293 #ifdef HAVE_RB_FD_INIT
    00294 static VALUE
    00295 try_wait_connectable(VALUE arg)
    00296 {
    00297     struct wait_connectable_arg *p = (struct wait_connectable_arg *)arg;
    00298     return (VALUE)wait_connectable0(p->fd, &p->fds_w, &p->fds_e);
    00299 }
    00300
    00301 static VALUE
    00302 wait_connectable_ensure(VALUE arg)
    00303 {
    00304     struct wait_connectable_arg *p = (struct wait_connectable_arg *)arg;
    00305     rb_fd_term(&p->fds_w);
    00306     rb_fd_term(&p->fds_e);
    00307     return Qnil;
    00308 }
    00309 #endif
    00310
    00311 static int
    00312 wait_connectable(int fd)
    00313 {
    00314     struct wait_connectable_arg arg;
    00315
    00316     rb_fd_init(&arg.fds_w);
    00317     rb_fd_init(&arg.fds_e);
    00318 #ifdef HAVE_RB_FD_INIT
    00319     arg.fd = fd;
    00320     return (int)rb_ensure(try_wait_connectable, (VALUE)&arg,
    00321                           wait_connectable_ensure,(VALUE)&arg);
    00322 #else
    00323     return wait_connectable0(fd, &arg.fds_w, &arg.fds_e);
    00324 #endif
    00325 }
    00326
    00327 #ifdef __CYGWIN__
    00328 #define WAIT_IN_PROGRESS 10
    00329 #endif
    00330 #ifdef __APPLE__
    00331 #define WAIT_IN_PROGRESS 10
    00332 #endif
    00333 #ifdef __linux__
    00334 /* returns correct error */
    00335 #define WAIT_IN_PROGRESS 0
    00336 #endif
    00337 #ifndef WAIT_IN_PROGRESS
    00338 /* BSD origin code apparently has a problem */
    00339 #define WAIT_IN_PROGRESS 1
    00340 #endif
    00341
    00342 struct connect_arg {
    00343     int fd;
    00344     const struct sockaddr *sockaddr;
    00345     socklen_t len;
    00346 };
    00347
    00348 static VALUE
    00349 connect_blocking(void *data)
    00350 {
    00351     struct connect_arg *arg = data;
    00352     return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
    00353 }
    00354
    00355 #if defined(SOCKS) && !defined(SOCKS5)
    00356 static VALUE
    00357 socks_connect_blocking(void *data)
    00358 {
    00359     struct connect_arg *arg = data;
    00360     return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
    00361 }
    00362 #endif
    00363
    00364 int
    00365 rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
    00366 {
    00367     int status;
    00368     rb_blocking_function_t *func = connect_blocking;
    00369     struct connect_arg arg;
    00370 #if WAIT_IN_PROGRESS > 0
    00371     int wait_in_progress = -1;
    00372     int sockerr;
    00373     socklen_t sockerrlen;
    00374 #endif
    00375
    00376     arg.fd = fd;
    00377     arg.sockaddr = sockaddr;
    00378     arg.len = len;
    00379 #if defined(SOCKS) && !defined(SOCKS5)
    00380     if (socks) func = socks_connect_blocking;
    00381 #endif
    00382     for (;;) {
    00383         status = (int)BLOCKING_REGION(func, &arg);
    00384         if (status < 0) {
    00385             switch (errno) {
    00386               case EAGAIN:
    00387 #ifdef EINPROGRESS
    00388               case EINPROGRESS:
    00389 #endif
    00390 #if WAIT_IN_PROGRESS > 0
    00391                 sockerrlen = (socklen_t)sizeof(sockerr);
    00392                 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
    00393                 if (status) break;
    00394                 if (sockerr) {
    00395                     status = -1;
    00396                     errno = sockerr;
    00397                     break;
    00398                 }
    00399 #endif
    00400 #ifdef EALREADY
    00401               case EALREADY:
    00402 #endif
    00403 #if WAIT_IN_PROGRESS > 0
    00404                 wait_in_progress = WAIT_IN_PROGRESS;
    00405 #endif
    00406                 status = wait_connectable(fd);
    00407                 if (status) {
    00408                     break;
    00409                 }
    00410                 errno = 0;
    00411                 continue;
    00412
    00413 #if WAIT_IN_PROGRESS > 0
    00414               case EINVAL:
    00415                 if (wait_in_progress-- > 0) {
    00416                     /*
    00417                      * connect() after EINPROGRESS returns EINVAL on
    00418                      * some platforms, need to check true error
    00419                      * status.
    00420                      */
    00421                     sockerrlen = (socklen_t)sizeof(sockerr);
    00422                     status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
    00423                     if (!status && !sockerr) {
    00424                         struct timeval tv = {0, 100000};
    00425                         rb_thread_wait_for(tv);
    00426                         continue;
    00427                     }
    00428                     status = -1;
    00429                     errno = sockerr;
    00430                 }
    00431                 break;
    00432 #endif
    00433
    00434 #ifdef EISCONN
    00435               case EISCONN:
    00436                 status = 0;
    00437                 errno = 0;
    00438                 break;
    00439 #endif
    00440               default:
    00441                 break;
    00442             }
    00443         }
    00444         return status;
    00445     }
    00446 }
    00447
    00448 static void
    00449 make_fd_nonblock(int fd)
    00450 {
    00451     int flags;
    00452 #ifdef F_GETFL
    00453     flags = fcntl(fd, F_GETFL);
    00454     if (flags == -1) {
    00455         rb_sys_fail(0);
    00456     }
    00457 #else
    00458     flags = 0;
    00459 #endif
    00460     flags |= O_NONBLOCK;
    00461     if (fcntl(fd, F_SETFL, flags) == -1) {
    00462         rb_sys_fail(0);
    00463     }
    00464 }
    00465
    00466 VALUE
    00467 rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
    00468 {
    00469     int fd2;
    00470
    00471     rb_secure(3);
    00472     rb_io_set_nonblock(fptr);
    00473     fd2 = accept(fptr->fd, (struct sockaddr*)sockaddr, len);
    00474     if (fd2 < 0) {
    00475         switch (errno) {
    00476           case EAGAIN:
    00477 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
    00478           case EWOULDBLOCK:
    00479 #endif
    00480           case ECONNABORTED:
    00481 #if defined EPROTO
    00482           case EPROTO:
    00483 #endif
    00484             rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block");
    00485         }
    00486         rb_sys_fail("accept(2)");
    00487     }
    00488     make_fd_nonblock(fd2);
    00489     return rsock_init_sock(rb_obj_alloc(klass), fd2);
    00490 }
    00491
    00492 struct accept_arg {
    00493     int fd;
    00494     struct sockaddr *sockaddr;
    00495     socklen_t *len;
    00496 };
    00497
    00498 static VALUE
    00499 accept_blocking(void *data)
    00500 {
    00501     struct accept_arg *arg = data;
    00502     return (VALUE)accept(arg->fd, arg->sockaddr, arg->len);
    00503 }
    00504
    00505 VALUE
    00506 rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
    00507 {
    00508     int fd2;
    00509     int retry = 0;
    00510     struct accept_arg arg;
    00511
    00512     rb_secure(3);
    00513     arg.fd = fd;
    00514     arg.sockaddr = sockaddr;
    00515     arg.len = len;
    00516   retry:
    00517     rb_thread_wait_fd(fd);
    00518     fd2 = (int)BLOCKING_REGION(accept_blocking, &arg);
    00519     if (fd2 < 0) {
    00520         switch (errno) {
    00521           case EMFILE:
    00522           case ENFILE:
    00523             if (retry) break;
    00524             rb_gc();
    00525             retry = 1;
    00526             goto retry;
    00527           default:
    00528             if (!rb_io_wait_readable(fd)) break;
    00529             retry = 0;
    00530             goto retry;
    00531         }
    00532         rb_sys_fail(0);
    00533     }
    00534     if (!klass) return INT2NUM(fd2);
    00535     return rsock_init_sock(rb_obj_alloc(klass), fd2);
    00536 }
    00537
    00538 int
    00539 rsock_getfamily(int sockfd)
    00540 {
    00541     struct sockaddr_storage ss;
    00542     socklen_t sslen = (socklen_t)sizeof(ss);
    00543
    00544     ss.ss_family = AF_UNSPEC;
    00545     if (getsockname(sockfd, (struct sockaddr*)&ss, &sslen) < 0)
    00546         return AF_UNSPEC;
    00547
    00548     return ss.ss_family;
    00549 }
    00550
    00551 /*
    00552  * SocketError is the error class for socket.
    00553  */
    00554 void
    00555 rsock_init_socket_init()
    00556 {
    00557     rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
    00558     rsock_init_ipsocket();
    00559     rsock_init_tcpsocket();
    00560     rsock_init_tcpserver();
    00561     rsock_init_sockssocket();
    00562     rsock_init_udpsocket();
    00563     rsock_init_unixsocket();
    00564     rsock_init_unixserver();
    00565     rsock_init_sockopt();
    00566     rsock_init_ancdata();
    00567     rsock_init_addrinfo();
    00568     rsock_init_socket_constants();
    00569 }
    00570