1/************************************************ 2 3 init.c - 4 5 created at: Thu Mar 31 12:21:29 JST 1994 6 7 Copyright (C) 1993-2007 Yukihiro Matsumoto 8 9************************************************/ 10 11#include "rubysocket.h" 12 13VALUE rb_cBasicSocket; 14VALUE rb_cIPSocket; 15VALUE rb_cTCPSocket; 16VALUE rb_cTCPServer; 17VALUE rb_cUDPSocket; 18#ifdef AF_UNIX 19VALUE rb_cUNIXSocket; 20VALUE rb_cUNIXServer; 21#endif 22VALUE rb_cSocket; 23VALUE rb_cAddrinfo; 24 25VALUE rb_eSocket; 26 27#ifdef SOCKS 28VALUE rb_cSOCKSSocket; 29#endif 30 31int rsock_do_not_reverse_lookup = 1; 32 33void 34rsock_raise_socket_error(const char *reason, int error) 35{ 36#ifdef EAI_SYSTEM 37 if (error == EAI_SYSTEM) rb_sys_fail(reason); 38#endif 39 rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error)); 40} 41 42VALUE 43rsock_init_sock(VALUE sock, int fd) 44{ 45 rb_io_t *fp; 46#ifndef _WIN32 47 struct stat sbuf; 48 49 if (fstat(fd, &sbuf) < 0) 50 rb_sys_fail(0); 51 rb_update_max_fd(fd); 52 if (!S_ISSOCK(sbuf.st_mode)) 53 rb_raise(rb_eArgError, "not a socket file descriptor"); 54#else 55 rb_update_max_fd(fd); 56 if (!rb_w32_is_socket(fd)) 57 rb_raise(rb_eArgError, "not a socket file descriptor"); 58#endif 59 60 MakeOpenFile(sock, fp); 61 fp->fd = fd; 62 fp->mode = FMODE_READWRITE|FMODE_DUPLEX; 63 rb_io_ascii8bit_binmode(sock); 64 if (rsock_do_not_reverse_lookup) { 65 fp->mode |= FMODE_NOREVLOOKUP; 66 } 67 rb_io_synchronized(fp); 68 69 return sock; 70} 71 72VALUE 73rsock_sendto_blocking(void *data) 74{ 75 struct rsock_send_arg *arg = data; 76 VALUE mesg = arg->mesg; 77 return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg), 78 arg->flags, arg->to, arg->tolen); 79} 80 81VALUE 82rsock_send_blocking(void *data) 83{ 84 struct rsock_send_arg *arg = data; 85 VALUE mesg = arg->mesg; 86 return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg), 87 arg->flags); 88} 89 90struct recvfrom_arg { 91 int fd, flags; 92 VALUE str; 93 socklen_t alen; 94 struct sockaddr_storage buf; 95}; 96 97static VALUE 98recvfrom_blocking(void *data) 99{ 100 struct recvfrom_arg *arg = data; 101 return (VALUE)recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str), 102 arg->flags, (struct sockaddr*)&arg->buf, &arg->alen); 103} 104 105VALUE 106rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) 107{ 108 rb_io_t *fptr; 109 VALUE str, klass; 110 struct recvfrom_arg arg; 111 VALUE len, flg; 112 long buflen; 113 long slen; 114 115 rb_scan_args(argc, argv, "11", &len, &flg); 116 117 if (flg == Qnil) arg.flags = 0; 118 else arg.flags = NUM2INT(flg); 119 buflen = NUM2INT(len); 120 121 GetOpenFile(sock, fptr); 122 if (rb_io_read_pending(fptr)) { 123 rb_raise(rb_eIOError, "recv for buffered IO"); 124 } 125 arg.fd = fptr->fd; 126 arg.alen = (socklen_t)sizeof(arg.buf); 127 128 arg.str = str = rb_tainted_str_new(0, buflen); 129 klass = RBASIC(str)->klass; 130 RBASIC(str)->klass = 0; 131 132 while (rb_io_check_closed(fptr), 133 rb_thread_wait_fd(arg.fd), 134 (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) { 135 if (!rb_io_wait_readable(fptr->fd)) { 136 rb_sys_fail("recvfrom(2)"); 137 } 138 if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) { 139 rb_raise(rb_eRuntimeError, "buffer string modified"); 140 } 141 } 142 143 RBASIC(str)->klass = klass; 144 if (slen < RSTRING_LEN(str)) { 145 rb_str_set_len(str, slen); 146 } 147 rb_obj_taint(str); 148 switch (from) { 149 case RECV_RECV: 150 return str; 151 case RECV_IP: 152#if 0 153 if (arg.alen != sizeof(struct sockaddr_in)) { 154 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); 155 } 156#endif 157 if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */ 158 return rb_assoc_new(str, rsock_ipaddr((struct sockaddr*)&arg.buf, fptr->mode & FMODE_NOREVLOOKUP)); 159 else 160 return rb_assoc_new(str, Qnil); 161 162#ifdef HAVE_SYS_UN_H 163 case RECV_UNIX: 164 return rb_assoc_new(str, rsock_unixaddr((struct sockaddr_un*)&arg.buf, arg.alen)); 165#endif 166 case RECV_SOCKET: 167 return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, (struct sockaddr*)&arg.buf, arg.alen)); 168 default: 169 rb_bug("rsock_s_recvfrom called with bad value"); 170 } 171} 172 173VALUE 174rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) 175{ 176 rb_io_t *fptr; 177 VALUE str; 178 struct sockaddr_storage buf; 179 socklen_t alen = (socklen_t)sizeof buf; 180 VALUE len, flg; 181 long buflen; 182 long slen; 183 int fd, flags; 184 VALUE addr = Qnil; 185 186 rb_scan_args(argc, argv, "11", &len, &flg); 187 188 if (flg == Qnil) flags = 0; 189 else flags = NUM2INT(flg); 190 buflen = NUM2INT(len); 191 192#ifdef MSG_DONTWAIT 193 /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom. 194 It is not portable, though. */ 195 flags |= MSG_DONTWAIT; 196#endif 197 198 GetOpenFile(sock, fptr); 199 if (rb_io_read_pending(fptr)) { 200 rb_raise(rb_eIOError, "recvfrom for buffered IO"); 201 } 202 fd = fptr->fd; 203 204 str = rb_tainted_str_new(0, buflen); 205 206 rb_io_check_closed(fptr); 207 rb_io_set_nonblock(fptr); 208 slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, (struct sockaddr*)&buf, &alen); 209 210 if (slen < 0) { 211 switch (errno) { 212 case EAGAIN: 213#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 214 case EWOULDBLOCK: 215#endif 216 rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block"); 217 } 218 rb_sys_fail("recvfrom(2)"); 219 } 220 if (slen < RSTRING_LEN(str)) { 221 rb_str_set_len(str, slen); 222 } 223 rb_obj_taint(str); 224 switch (from) { 225 case RECV_RECV: 226 return str; 227 228 case RECV_IP: 229 if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */ 230 addr = rsock_ipaddr((struct sockaddr*)&buf, fptr->mode & FMODE_NOREVLOOKUP); 231 break; 232 233 case RECV_SOCKET: 234 addr = rsock_io_socket_addrinfo(sock, (struct sockaddr*)&buf, alen); 235 break; 236 237 default: 238 rb_bug("rsock_s_recvfrom_nonblock called with bad value"); 239 } 240 return rb_assoc_new(str, addr); 241} 242 243static int 244rsock_socket0(int domain, int type, int proto) 245{ 246 int ret; 247 248#ifdef SOCK_CLOEXEC 249 static int try_sock_cloexec = 1; 250 if (try_sock_cloexec) { 251 ret = socket(domain, type|SOCK_CLOEXEC, proto); 252 if (ret == -1 && errno == EINVAL) { 253 /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */ 254 ret = socket(domain, type, proto); 255 if (ret != -1) { 256 try_sock_cloexec = 0; 257 } 258 } 259 } 260 else { 261 ret = socket(domain, type, proto); 262 } 263#else 264 ret = socket(domain, type, proto); 265#endif 266 if (ret == -1) 267 return -1; 268 269 rb_fd_fix_cloexec(ret); 270 271 return ret; 272 273} 274 275int 276rsock_socket(int domain, int type, int proto) 277{ 278 int fd; 279 280 fd = rsock_socket0(domain, type, proto); 281 if (fd < 0) { 282 if (errno == EMFILE || errno == ENFILE) { 283 rb_gc(); 284 fd = rsock_socket0(domain, type, proto); 285 } 286 } 287 if (0 <= fd) 288 rb_update_max_fd(fd); 289 return fd; 290} 291 292static int 293wait_connectable(int fd) 294{ 295 int sockerr; 296 socklen_t sockerrlen; 297 int revents; 298 int ret; 299 300 for (;;) { 301 /* 302 * Stevens book says, succuessful finish turn on RB_WAITFD_OUT and 303 * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT. 304 */ 305 revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL); 306 307 if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) { 308 sockerrlen = (socklen_t)sizeof(sockerr); 309 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); 310 311 /* 312 * Solaris getsockopt(SO_ERROR) return -1 and set errno 313 * in getsockopt(). Let's return immediately. 314 */ 315 if (ret < 0) 316 break; 317 if (sockerr == 0) { 318 if (revents & RB_WAITFD_OUT) 319 break; 320 else 321 continue; /* workaround for winsock */ 322 } 323 324 /* BSD and Linux use sockerr. */ 325 errno = sockerr; 326 ret = -1; 327 break; 328 } 329 330 if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) { 331 ret = 0; 332 break; 333 } 334 } 335 336 return ret; 337} 338 339#ifdef __CYGWIN__ 340#define WAIT_IN_PROGRESS 10 341#endif 342#ifdef __APPLE__ 343#define WAIT_IN_PROGRESS 10 344#endif 345#ifdef __linux__ 346/* returns correct error */ 347#define WAIT_IN_PROGRESS 0 348#endif 349#ifndef WAIT_IN_PROGRESS 350/* BSD origin code apparently has a problem */ 351#define WAIT_IN_PROGRESS 1 352#endif 353 354struct connect_arg { 355 int fd; 356 const struct sockaddr *sockaddr; 357 socklen_t len; 358}; 359 360static VALUE 361connect_blocking(void *data) 362{ 363 struct connect_arg *arg = data; 364 return (VALUE)connect(arg->fd, arg->sockaddr, arg->len); 365} 366 367#if defined(SOCKS) && !defined(SOCKS5) 368static VALUE 369socks_connect_blocking(void *data) 370{ 371 struct connect_arg *arg = data; 372 return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len); 373} 374#endif 375 376int 377rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks) 378{ 379 int status; 380 rb_blocking_function_t *func = connect_blocking; 381 struct connect_arg arg; 382#if WAIT_IN_PROGRESS > 0 383 int wait_in_progress = -1; 384 int sockerr; 385 socklen_t sockerrlen; 386#endif 387 388 arg.fd = fd; 389 arg.sockaddr = sockaddr; 390 arg.len = len; 391#if defined(SOCKS) && !defined(SOCKS5) 392 if (socks) func = socks_connect_blocking; 393#endif 394 for (;;) { 395 status = (int)BLOCKING_REGION_FD(func, &arg); 396 if (status < 0) { 397 switch (errno) { 398 case EINTR: 399#if defined(ERESTART) 400 case ERESTART: 401#endif 402 continue; 403 404 case EAGAIN: 405#ifdef EINPROGRESS 406 case EINPROGRESS: 407#endif 408#if WAIT_IN_PROGRESS > 0 409 sockerrlen = (socklen_t)sizeof(sockerr); 410 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); 411 if (status) break; 412 if (sockerr) { 413 status = -1; 414 errno = sockerr; 415 break; 416 } 417#endif 418#ifdef EALREADY 419 case EALREADY: 420#endif 421#if WAIT_IN_PROGRESS > 0 422 wait_in_progress = WAIT_IN_PROGRESS; 423#endif 424 status = wait_connectable(fd); 425 if (status) { 426 break; 427 } 428 errno = 0; 429 continue; 430 431#if WAIT_IN_PROGRESS > 0 432 case EINVAL: 433 if (wait_in_progress-- > 0) { 434 /* 435 * connect() after EINPROGRESS returns EINVAL on 436 * some platforms, need to check true error 437 * status. 438 */ 439 sockerrlen = (socklen_t)sizeof(sockerr); 440 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); 441 if (!status && !sockerr) { 442 struct timeval tv = {0, 100000}; 443 rb_thread_wait_for(tv); 444 continue; 445 } 446 status = -1; 447 errno = sockerr; 448 } 449 break; 450#endif 451 452#ifdef EISCONN 453 case EISCONN: 454 status = 0; 455 errno = 0; 456 break; 457#endif 458 default: 459 break; 460 } 461 } 462 return status; 463 } 464} 465 466static void 467make_fd_nonblock(int fd) 468{ 469 int flags; 470#ifdef F_GETFL 471 flags = fcntl(fd, F_GETFL); 472 if (flags == -1) { 473 rb_sys_fail(0); 474 } 475#else 476 flags = 0; 477#endif 478 flags |= O_NONBLOCK; 479 if (fcntl(fd, F_SETFL, flags) == -1) { 480 rb_sys_fail(0); 481 } 482} 483 484static int 485cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len) 486{ 487 int ret; 488 socklen_t len0 = 0; 489#ifdef HAVE_ACCEPT4 490 static int try_accept4 = 1; 491#endif 492 if (address_len) len0 = *address_len; 493#ifdef HAVE_ACCEPT4 494 if (try_accept4) { 495 int flags = 0; 496#ifdef SOCK_CLOEXEC 497 flags |= SOCK_CLOEXEC; 498#endif 499 ret = accept4(socket, address, address_len, flags); 500 /* accept4 is available since Linux 2.6.28, glibc 2.10. */ 501 if (ret != -1) { 502 if (ret <= 2) 503 rb_maygvl_fd_fix_cloexec(ret); 504 if (address_len && len0 < *address_len) *address_len = len0; 505 return ret; 506 } 507 if (errno != ENOSYS) { 508 return -1; 509 } 510 try_accept4 = 0; 511 } 512#endif 513 ret = accept(socket, address, address_len); 514 if (ret == -1) return -1; 515 if (address_len && len0 < *address_len) *address_len = len0; 516 rb_maygvl_fd_fix_cloexec(ret); 517 return ret; 518} 519 520 521VALUE 522rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len) 523{ 524 int fd2; 525 526 rb_secure(3); 527 rb_io_set_nonblock(fptr); 528 fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len); 529 if (fd2 < 0) { 530 switch (errno) { 531 case EAGAIN: 532#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 533 case EWOULDBLOCK: 534#endif 535 case ECONNABORTED: 536#if defined EPROTO 537 case EPROTO: 538#endif 539 rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block"); 540 } 541 rb_sys_fail("accept(2)"); 542 } 543 rb_update_max_fd(fd2); 544 make_fd_nonblock(fd2); 545 return rsock_init_sock(rb_obj_alloc(klass), fd2); 546} 547 548struct accept_arg { 549 int fd; 550 struct sockaddr *sockaddr; 551 socklen_t *len; 552}; 553 554static VALUE 555accept_blocking(void *data) 556{ 557 struct accept_arg *arg = data; 558 return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len); 559} 560 561VALUE 562rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len) 563{ 564 int fd2; 565 int retry = 0; 566 struct accept_arg arg; 567 568 rb_secure(3); 569 arg.fd = fd; 570 arg.sockaddr = sockaddr; 571 arg.len = len; 572 retry: 573 rb_thread_wait_fd(fd); 574 fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg); 575 if (fd2 < 0) { 576 switch (errno) { 577 case EMFILE: 578 case ENFILE: 579 if (retry) break; 580 rb_gc(); 581 retry = 1; 582 goto retry; 583 default: 584 if (!rb_io_wait_readable(fd)) break; 585 retry = 0; 586 goto retry; 587 } 588 rb_sys_fail(0); 589 } 590 rb_update_max_fd(fd2); 591 if (!klass) return INT2NUM(fd2); 592 return rsock_init_sock(rb_obj_alloc(klass), fd2); 593} 594 595int 596rsock_getfamily(int sockfd) 597{ 598 struct sockaddr_storage ss; 599 socklen_t sslen = (socklen_t)sizeof(ss); 600 601 ss.ss_family = AF_UNSPEC; 602 if (getsockname(sockfd, (struct sockaddr*)&ss, &sslen) < 0) 603 return AF_UNSPEC; 604 605 return ss.ss_family; 606} 607 608void 609rsock_init_socket_init() 610{ 611 /* 612 * SocketError is the error class for socket. 613 */ 614 rb_eSocket = rb_define_class("SocketError", rb_eStandardError); 615 rsock_init_ipsocket(); 616 rsock_init_tcpsocket(); 617 rsock_init_tcpserver(); 618 rsock_init_sockssocket(); 619 rsock_init_udpsocket(); 620 rsock_init_unixsocket(); 621 rsock_init_unixserver(); 622 rsock_init_sockopt(); 623 rsock_init_ancdata(); 624 rsock_init_addrinfo(); 625 rsock_init_socket_constants(); 626} 627