00001
00002
00003
00004
00005
00006
00007
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(0);
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 struct sockaddr_storage buf;
00095 };
00096
00097 static VALUE
00098 recvfrom_blocking(void *data)
00099 {
00100 struct recvfrom_arg *arg = data;
00101 return (VALUE)recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
00102 arg->flags, (struct sockaddr*)&arg->buf, &arg->alen);
00103 }
00104
00105 VALUE
00106 rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
00107 {
00108 rb_io_t *fptr;
00109 VALUE str, klass;
00110 struct recvfrom_arg arg;
00111 VALUE len, flg;
00112 long buflen;
00113 long slen;
00114
00115 rb_scan_args(argc, argv, "11", &len, &flg);
00116
00117 if (flg == Qnil) arg.flags = 0;
00118 else arg.flags = NUM2INT(flg);
00119 buflen = NUM2INT(len);
00120
00121 GetOpenFile(sock, fptr);
00122 if (rb_io_read_pending(fptr)) {
00123 rb_raise(rb_eIOError, "recv for buffered IO");
00124 }
00125 arg.fd = fptr->fd;
00126 arg.alen = (socklen_t)sizeof(arg.buf);
00127
00128 arg.str = str = rb_tainted_str_new(0, buflen);
00129 klass = RBASIC(str)->klass;
00130 RBASIC(str)->klass = 0;
00131
00132 while (rb_io_check_closed(fptr),
00133 rb_thread_wait_fd(arg.fd),
00134 (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) {
00135 if (!rb_io_wait_readable(fptr->fd)) {
00136 rb_sys_fail("recvfrom(2)");
00137 }
00138 if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
00139 rb_raise(rb_eRuntimeError, "buffer string modified");
00140 }
00141 }
00142
00143 RBASIC(str)->klass = klass;
00144 if (slen < RSTRING_LEN(str)) {
00145 rb_str_set_len(str, slen);
00146 }
00147 rb_obj_taint(str);
00148 switch (from) {
00149 case RECV_RECV:
00150 return str;
00151 case RECV_IP:
00152 #if 0
00153 if (arg.alen != sizeof(struct sockaddr_in)) {
00154 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
00155 }
00156 #endif
00157 if (arg.alen && arg.alen != sizeof(arg.buf))
00158 return rb_assoc_new(str, rsock_ipaddr((struct sockaddr*)&arg.buf, arg.alen, fptr->mode & FMODE_NOREVLOOKUP));
00159 else
00160 return rb_assoc_new(str, Qnil);
00161
00162 #ifdef HAVE_SYS_UN_H
00163 case RECV_UNIX:
00164 return rb_assoc_new(str, rsock_unixaddr((struct sockaddr_un*)&arg.buf, arg.alen));
00165 #endif
00166 case RECV_SOCKET:
00167 return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, (struct sockaddr*)&arg.buf, arg.alen));
00168 default:
00169 rb_bug("rsock_s_recvfrom called with bad value");
00170 }
00171 }
00172
00173 VALUE
00174 rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
00175 {
00176 rb_io_t *fptr;
00177 VALUE str;
00178 struct sockaddr_storage buf;
00179 socklen_t alen = (socklen_t)sizeof buf;
00180 VALUE len, flg;
00181 long buflen;
00182 long slen;
00183 int fd, flags;
00184 VALUE addr = Qnil;
00185
00186 rb_scan_args(argc, argv, "11", &len, &flg);
00187
00188 if (flg == Qnil) flags = 0;
00189 else flags = NUM2INT(flg);
00190 buflen = NUM2INT(len);
00191
00192 #ifdef MSG_DONTWAIT
00193
00194
00195 flags |= MSG_DONTWAIT;
00196 #endif
00197
00198 GetOpenFile(sock, fptr);
00199 if (rb_io_read_pending(fptr)) {
00200 rb_raise(rb_eIOError, "recvfrom for buffered IO");
00201 }
00202 fd = fptr->fd;
00203
00204 str = rb_tainted_str_new(0, buflen);
00205
00206 rb_io_check_closed(fptr);
00207 rb_io_set_nonblock(fptr);
00208 slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, (struct sockaddr*)&buf, &alen);
00209
00210 if (slen < 0) {
00211 switch (errno) {
00212 case EAGAIN:
00213 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
00214 case EWOULDBLOCK:
00215 #endif
00216 rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block");
00217 }
00218 rb_sys_fail("recvfrom(2)");
00219 }
00220 if (slen < RSTRING_LEN(str)) {
00221 rb_str_set_len(str, slen);
00222 }
00223 rb_obj_taint(str);
00224 switch (from) {
00225 case RECV_RECV:
00226 return str;
00227
00228 case RECV_IP:
00229 if (alen && alen != sizeof(buf))
00230 addr = rsock_ipaddr((struct sockaddr*)&buf, alen, fptr->mode & FMODE_NOREVLOOKUP);
00231 break;
00232
00233 case RECV_SOCKET:
00234 addr = rsock_io_socket_addrinfo(sock, (struct sockaddr*)&buf, alen);
00235 break;
00236
00237 default:
00238 rb_bug("rsock_s_recvfrom_nonblock called with bad value");
00239 }
00240 return rb_assoc_new(str, addr);
00241 }
00242
00243 static int
00244 rsock_socket0(int domain, int type, int proto)
00245 {
00246 int ret;
00247
00248 #ifdef SOCK_CLOEXEC
00249 static int try_sock_cloexec = 1;
00250 if (try_sock_cloexec) {
00251 ret = socket(domain, type|SOCK_CLOEXEC, proto);
00252 if (ret == -1 && errno == EINVAL) {
00253
00254 ret = socket(domain, type, proto);
00255 if (ret != -1) {
00256 try_sock_cloexec = 0;
00257 }
00258 }
00259 }
00260 else {
00261 ret = socket(domain, type, proto);
00262 }
00263 #else
00264 ret = socket(domain, type, proto);
00265 #endif
00266 if (ret == -1)
00267 return -1;
00268
00269 rb_fd_fix_cloexec(ret);
00270
00271 return ret;
00272
00273 }
00274
00275 int
00276 rsock_socket(int domain, int type, int proto)
00277 {
00278 int fd;
00279
00280 fd = rsock_socket0(domain, type, proto);
00281 if (fd < 0) {
00282 if (errno == EMFILE || errno == ENFILE) {
00283 rb_gc();
00284 fd = rsock_socket0(domain, type, proto);
00285 }
00286 }
00287 if (0 <= fd)
00288 rb_update_max_fd(fd);
00289 return fd;
00290 }
00291
00292 static int
00293 wait_connectable(int fd)
00294 {
00295 int sockerr;
00296 socklen_t sockerrlen;
00297 int revents;
00298 int ret;
00299
00300 for (;;) {
00301
00302
00303
00304
00305 revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
00306
00307 if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) {
00308 sockerrlen = (socklen_t)sizeof(sockerr);
00309 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00310
00311
00312
00313
00314
00315 if (ret < 0)
00316 break;
00317 if (sockerr == 0) {
00318 if (revents & RB_WAITFD_OUT)
00319 break;
00320 else
00321 continue;
00322 }
00323
00324
00325 errno = sockerr;
00326 ret = -1;
00327 break;
00328 }
00329
00330 if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) {
00331 ret = 0;
00332 break;
00333 }
00334 }
00335
00336 return ret;
00337 }
00338
00339 #ifdef __CYGWIN__
00340 #define WAIT_IN_PROGRESS 10
00341 #endif
00342 #ifdef __APPLE__
00343 #define WAIT_IN_PROGRESS 10
00344 #endif
00345 #ifdef __linux__
00346
00347 #define WAIT_IN_PROGRESS 0
00348 #endif
00349 #ifndef WAIT_IN_PROGRESS
00350
00351 #define WAIT_IN_PROGRESS 1
00352 #endif
00353
00354 struct connect_arg {
00355 int fd;
00356 const struct sockaddr *sockaddr;
00357 socklen_t len;
00358 };
00359
00360 static VALUE
00361 connect_blocking(void *data)
00362 {
00363 struct connect_arg *arg = data;
00364 return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
00365 }
00366
00367 #if defined(SOCKS) && !defined(SOCKS5)
00368 static VALUE
00369 socks_connect_blocking(void *data)
00370 {
00371 struct connect_arg *arg = data;
00372 return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
00373 }
00374 #endif
00375
00376 int
00377 rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
00378 {
00379 int status;
00380 rb_blocking_function_t *func = connect_blocking;
00381 struct connect_arg arg;
00382 #if WAIT_IN_PROGRESS > 0
00383 int wait_in_progress = -1;
00384 int sockerr;
00385 socklen_t sockerrlen;
00386 #endif
00387
00388 arg.fd = fd;
00389 arg.sockaddr = sockaddr;
00390 arg.len = len;
00391 #if defined(SOCKS) && !defined(SOCKS5)
00392 if (socks) func = socks_connect_blocking;
00393 #endif
00394 for (;;) {
00395 status = (int)BLOCKING_REGION_FD(func, &arg);
00396 if (status < 0) {
00397 switch (errno) {
00398 case EINTR:
00399 #if defined(ERESTART)
00400 case ERESTART:
00401 #endif
00402 continue;
00403
00404 case EAGAIN:
00405 #ifdef EINPROGRESS
00406 case EINPROGRESS:
00407 #endif
00408 #if WAIT_IN_PROGRESS > 0
00409 sockerrlen = (socklen_t)sizeof(sockerr);
00410 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00411 if (status) break;
00412 if (sockerr) {
00413 status = -1;
00414 errno = sockerr;
00415 break;
00416 }
00417 #endif
00418 #ifdef EALREADY
00419 case EALREADY:
00420 #endif
00421 #if WAIT_IN_PROGRESS > 0
00422 wait_in_progress = WAIT_IN_PROGRESS;
00423 #endif
00424 status = wait_connectable(fd);
00425 if (status) {
00426 break;
00427 }
00428 errno = 0;
00429 continue;
00430
00431 #if WAIT_IN_PROGRESS > 0
00432 case EINVAL:
00433 if (wait_in_progress-- > 0) {
00434
00435
00436
00437
00438
00439 sockerrlen = (socklen_t)sizeof(sockerr);
00440 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
00441 if (!status && !sockerr) {
00442 struct timeval tv = {0, 100000};
00443 rb_thread_wait_for(tv);
00444 continue;
00445 }
00446 status = -1;
00447 errno = sockerr;
00448 }
00449 break;
00450 #endif
00451
00452 #ifdef EISCONN
00453 case EISCONN:
00454 status = 0;
00455 errno = 0;
00456 break;
00457 #endif
00458 default:
00459 break;
00460 }
00461 }
00462 return status;
00463 }
00464 }
00465
00466 static void
00467 make_fd_nonblock(int fd)
00468 {
00469 int flags;
00470 #ifdef F_GETFL
00471 flags = fcntl(fd, F_GETFL);
00472 if (flags == -1) {
00473 rb_sys_fail(0);
00474 }
00475 #else
00476 flags = 0;
00477 #endif
00478 flags |= O_NONBLOCK;
00479 if (fcntl(fd, F_SETFL, flags) == -1) {
00480 rb_sys_fail(0);
00481 }
00482 }
00483
00484 static int
00485 cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len)
00486 {
00487 int ret;
00488 socklen_t len0 = 0;
00489 #ifdef HAVE_ACCEPT4
00490 static int try_accept4 = 1;
00491 #endif
00492 if (address_len) len0 = *address_len;
00493 #ifdef HAVE_ACCEPT4
00494 if (try_accept4) {
00495 int flags = 0;
00496 #ifdef SOCK_CLOEXEC
00497 flags |= SOCK_CLOEXEC;
00498 #endif
00499 ret = accept4(socket, address, address_len, flags);
00500
00501 if (ret != -1) {
00502 if (ret <= 2)
00503 rb_maygvl_fd_fix_cloexec(ret);
00504 if (address_len && len0 < *address_len) *address_len = len0;
00505 return ret;
00506 }
00507 if (errno != ENOSYS) {
00508 return -1;
00509 }
00510 try_accept4 = 0;
00511 }
00512 #endif
00513 ret = accept(socket, address, address_len);
00514 if (ret == -1) return -1;
00515 if (address_len && len0 < *address_len) *address_len = len0;
00516 rb_maygvl_fd_fix_cloexec(ret);
00517 return ret;
00518 }
00519
00520
00521 VALUE
00522 rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
00523 {
00524 int fd2;
00525
00526 rb_secure(3);
00527 rb_io_set_nonblock(fptr);
00528 fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len);
00529 if (fd2 < 0) {
00530 switch (errno) {
00531 case EAGAIN:
00532 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
00533 case EWOULDBLOCK:
00534 #endif
00535 case ECONNABORTED:
00536 #if defined EPROTO
00537 case EPROTO:
00538 #endif
00539 rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block");
00540 }
00541 rb_sys_fail("accept(2)");
00542 }
00543 rb_update_max_fd(fd2);
00544 make_fd_nonblock(fd2);
00545 return rsock_init_sock(rb_obj_alloc(klass), fd2);
00546 }
00547
00548 struct accept_arg {
00549 int fd;
00550 struct sockaddr *sockaddr;
00551 socklen_t *len;
00552 };
00553
00554 static VALUE
00555 accept_blocking(void *data)
00556 {
00557 struct accept_arg *arg = data;
00558 return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len);
00559 }
00560
00561 VALUE
00562 rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
00563 {
00564 int fd2;
00565 int retry = 0;
00566 struct accept_arg arg;
00567
00568 rb_secure(3);
00569 arg.fd = fd;
00570 arg.sockaddr = sockaddr;
00571 arg.len = len;
00572 retry:
00573 rb_thread_wait_fd(fd);
00574 fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
00575 if (fd2 < 0) {
00576 switch (errno) {
00577 case EMFILE:
00578 case ENFILE:
00579 if (retry) break;
00580 rb_gc();
00581 retry = 1;
00582 goto retry;
00583 default:
00584 if (!rb_io_wait_readable(fd)) break;
00585 retry = 0;
00586 goto retry;
00587 }
00588 rb_sys_fail(0);
00589 }
00590 rb_update_max_fd(fd2);
00591 if (!klass) return INT2NUM(fd2);
00592 return rsock_init_sock(rb_obj_alloc(klass), fd2);
00593 }
00594
00595 int
00596 rsock_getfamily(int sockfd)
00597 {
00598 struct sockaddr_storage ss;
00599 socklen_t sslen = (socklen_t)sizeof(ss);
00600
00601 ss.ss_family = AF_UNSPEC;
00602 if (getsockname(sockfd, (struct sockaddr*)&ss, &sslen) < 0)
00603 return AF_UNSPEC;
00604
00605 return ss.ss_family;
00606 }
00607
00608 void
00609 rsock_init_socket_init()
00610 {
00611
00612
00613
00614 rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
00615 rsock_init_ipsocket();
00616 rsock_init_tcpsocket();
00617 rsock_init_tcpserver();
00618 rsock_init_sockssocket();
00619 rsock_init_udpsocket();
00620 rsock_init_unixsocket();
00621 rsock_init_unixserver();
00622 rsock_init_sockopt();
00623 rsock_init_ancdata();
00624 rsock_init_addrinfo();
00625 rsock_init_socket_constants();
00626 }
00627