|
Ruby 1.9.2p180(2011-02-18revision30909)
|
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
1.7.3