• 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 

Generated on Wed Sep 8 2010 09:55:31 for Ruby by  doxygen 1.7.1