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