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