• 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 EINTR:
00387 #if defined(ERESTART)
00388               case ERESTART:
00389 #endif
00390                 continue;
00391 
00392               case EAGAIN:
00393 #ifdef EINPROGRESS
00394               case EINPROGRESS:
00395 #endif
00396 #if WAIT_IN_PROGRESS > 0
00397                 sockerrlen = (socklen_t)sizeof(sockerr);
00398                 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00399                 if (status) break;
00400                 if (sockerr) {
00401                     status = -1;
00402                     errno = sockerr;
00403                     break;
00404                 }
00405 #endif
00406 #ifdef EALREADY
00407               case EALREADY:
00408 #endif
00409 #if WAIT_IN_PROGRESS > 0
00410                 wait_in_progress = WAIT_IN_PROGRESS;
00411 #endif
00412                 status = wait_connectable(fd);
00413                 if (status) {
00414                     break;
00415                 }
00416                 errno = 0;
00417                 continue;
00418 
00419 #if WAIT_IN_PROGRESS > 0
00420               case EINVAL:
00421                 if (wait_in_progress-- > 0) {
00422                     /*
00423                      * connect() after EINPROGRESS returns EINVAL on
00424                      * some platforms, need to check true error
00425                      * status.
00426                      */
00427                     sockerrlen = (socklen_t)sizeof(sockerr);
00428                     status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00429                     if (!status && !sockerr) {
00430                         struct timeval tv = {0, 100000};
00431                         rb_thread_wait_for(tv);
00432                         continue;
00433                     }
00434                     status = -1;
00435                     errno = sockerr;
00436                 }
00437                 break;
00438 #endif
00439 
00440 #ifdef EISCONN
00441               case EISCONN:
00442                 status = 0;
00443                 errno = 0;
00444                 break;
00445 #endif
00446               default:
00447                 break;
00448             }
00449         }
00450         return status;
00451     }
00452 }
00453 
00454 static void
00455 make_fd_nonblock(int fd)
00456 {
00457     int flags;
00458 #ifdef F_GETFL
00459     flags = fcntl(fd, F_GETFL);
00460     if (flags == -1) {
00461         rb_sys_fail(0);
00462     }
00463 #else
00464     flags = 0;
00465 #endif
00466     flags |= O_NONBLOCK;
00467     if (fcntl(fd, F_SETFL, flags) == -1) {
00468         rb_sys_fail(0);
00469     }
00470 }
00471 
00472 VALUE
00473 rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
00474 {
00475     int fd2;
00476 
00477     rb_secure(3);
00478     rb_io_set_nonblock(fptr);
00479     fd2 = accept(fptr->fd, (struct sockaddr*)sockaddr, len);
00480     if (fd2 < 0) {
00481         switch (errno) {
00482           case EAGAIN:
00483 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
00484           case EWOULDBLOCK:
00485 #endif
00486           case ECONNABORTED:
00487 #if defined EPROTO
00488           case EPROTO:
00489 #endif
00490             rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block");
00491         }
00492         rb_sys_fail("accept(2)");
00493     }
00494     make_fd_nonblock(fd2);
00495     return rsock_init_sock(rb_obj_alloc(klass), fd2);
00496 }
00497 
00498 struct accept_arg {
00499     int fd;
00500     struct sockaddr *sockaddr;
00501     socklen_t *len;
00502 };
00503 
00504 static VALUE
00505 accept_blocking(void *data)
00506 {
00507     struct accept_arg *arg = data;
00508     return (VALUE)accept(arg->fd, arg->sockaddr, arg->len);
00509 }
00510 
00511 VALUE
00512 rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
00513 {
00514     int fd2;
00515     int retry = 0;
00516     struct accept_arg arg;
00517 
00518     rb_secure(3);
00519     arg.fd = fd;
00520     arg.sockaddr = sockaddr;
00521     arg.len = len;
00522   retry:
00523     rb_thread_wait_fd(fd);
00524     fd2 = (int)BLOCKING_REGION(accept_blocking, &arg);
00525     if (fd2 < 0) {
00526         switch (errno) {
00527           case EMFILE:
00528           case ENFILE:
00529             if (retry) break;
00530             rb_gc();
00531             retry = 1;
00532             goto retry;
00533           default:
00534             if (!rb_io_wait_readable(fd)) break;
00535             retry = 0;
00536             goto retry;
00537         }
00538         rb_sys_fail(0);
00539     }
00540     if (!klass) return INT2NUM(fd2);
00541     return rsock_init_sock(rb_obj_alloc(klass), fd2);
00542 }
00543 
00544 int
00545 rsock_getfamily(int sockfd)
00546 {
00547     struct sockaddr_storage ss;
00548     socklen_t sslen = (socklen_t)sizeof(ss);
00549 
00550     ss.ss_family = AF_UNSPEC;
00551     if (getsockname(sockfd, (struct sockaddr*)&ss, &sslen) < 0)
00552         return AF_UNSPEC;
00553 
00554     return ss.ss_family;
00555 }
00556 
00557 /*
00558  * SocketError is the error class for socket.
00559  */
00560 void
00561 rsock_init_socket_init()
00562 {
00563     rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
00564     rsock_init_ipsocket();
00565     rsock_init_tcpsocket();
00566     rsock_init_tcpserver();
00567     rsock_init_sockssocket();
00568     rsock_init_udpsocket();
00569     rsock_init_unixsocket();
00570     rsock_init_unixserver();
00571     rsock_init_sockopt();
00572     rsock_init_ancdata();
00573     rsock_init_addrinfo();
00574     rsock_init_socket_constants();
00575 }
00576 

Generated on Thu Sep 8 2011 03:50:29 for Ruby by  doxygen 1.7.1