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 
13 #ifdef _WIN32
14 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
15 #endif
16 
17 VALUE rb_cBasicSocket;
18 VALUE rb_cIPSocket;
19 VALUE rb_cTCPSocket;
20 VALUE rb_cTCPServer;
21 VALUE rb_cUDPSocket;
22 #ifdef AF_UNIX
23 VALUE rb_cUNIXSocket;
24 VALUE rb_cUNIXServer;
25 #endif
26 VALUE rb_cSocket;
27 VALUE rb_cAddrinfo;
28 
29 VALUE rb_eSocket;
30 
31 #ifdef SOCKS
32 VALUE rb_cSOCKSSocket;
33 #endif
34 
35 int rsock_do_not_reverse_lookup = 1;
36 static VALUE sym_wait_readable;
37 
38 void
rsock_raise_socket_error(const char * reason,int error)39 rsock_raise_socket_error(const char *reason, int error)
40 {
41 #ifdef EAI_SYSTEM
42     int e;
43     if (error == EAI_SYSTEM && (e = errno) != 0)
44 	rb_syserr_fail(e, reason);
45 #endif
46 #ifdef _WIN32
47     rb_encoding *enc = rb_default_internal_encoding();
48     VALUE msg = rb_sprintf("%s: ", reason);
49     if (!enc) enc = rb_default_internal_encoding();
50     rb_str_concat(msg, rb_w32_conv_from_wchar(gai_strerrorW(error), enc));
51     rb_exc_raise(rb_exc_new_str(rb_eSocket, msg));
52 #else
53     rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
54 #endif
55 }
56 
57 #ifdef _WIN32
58 #define is_socket(fd) rb_w32_is_socket(fd)
59 #else
60 static int
is_socket(int fd)61 is_socket(int fd)
62 {
63     struct stat sbuf;
64 
65     if (fstat(fd, &sbuf) < 0)
66         rb_sys_fail("fstat(2)");
67     return S_ISSOCK(sbuf.st_mode);
68 }
69 #endif
70 
71 #if defined __APPLE__
72 # define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
73 #else
74 # define do_write_retry(code) ret = code
75 #endif
76 
77 VALUE
rsock_init_sock(VALUE sock,int fd)78 rsock_init_sock(VALUE sock, int fd)
79 {
80     rb_io_t *fp;
81 
82     if (!is_socket(fd) || rb_reserved_fd_p(fd)) {
83 	rb_syserr_fail(EBADF, "not a socket file descriptor");
84     }
85 
86     rb_update_max_fd(fd);
87     MakeOpenFile(sock, fp);
88     fp->fd = fd;
89     fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
90     rb_io_ascii8bit_binmode(sock);
91     if (rsock_do_not_reverse_lookup) {
92 	fp->mode |= FMODE_NOREVLOOKUP;
93     }
94     rb_io_synchronized(fp);
95 
96     return sock;
97 }
98 
99 VALUE
rsock_sendto_blocking(void * data)100 rsock_sendto_blocking(void *data)
101 {
102     struct rsock_send_arg *arg = data;
103     VALUE mesg = arg->mesg;
104     ssize_t ret;
105     do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
106 			  arg->flags, arg->to, arg->tolen));
107     return (VALUE)ret;
108 }
109 
110 VALUE
rsock_send_blocking(void * data)111 rsock_send_blocking(void *data)
112 {
113     struct rsock_send_arg *arg = data;
114     VALUE mesg = arg->mesg;
115     ssize_t ret;
116     do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
117 			arg->flags));
118     return (VALUE)ret;
119 }
120 
121 struct recvfrom_arg {
122     int fd, flags;
123     VALUE str;
124     size_t length;
125     socklen_t alen;
126     union_sockaddr buf;
127 };
128 
129 static VALUE
recvfrom_blocking(void * data)130 recvfrom_blocking(void *data)
131 {
132     struct recvfrom_arg *arg = data;
133     socklen_t len0 = arg->alen;
134     ssize_t ret;
135     ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), arg->length,
136                    arg->flags, &arg->buf.addr, &arg->alen);
137     if (ret != -1 && len0 < arg->alen)
138         arg->alen = len0;
139 
140     return (VALUE)ret;
141 }
142 
143 static VALUE
rsock_strbuf(VALUE str,long buflen)144 rsock_strbuf(VALUE str, long buflen)
145 {
146     long len;
147 
148     if (NIL_P(str)) return rb_tainted_str_new(0, buflen);
149 
150     StringValue(str);
151     len = RSTRING_LEN(str);
152     if (len >= buflen) {
153 	rb_str_modify(str);
154     } else {
155 	rb_str_modify_expand(str, buflen - len);
156     }
157     return str;
158 }
159 
160 static VALUE
recvfrom_locktmp(VALUE v)161 recvfrom_locktmp(VALUE v)
162 {
163     struct recvfrom_arg *arg = (struct recvfrom_arg *)v;
164 
165     return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd);
166 }
167 
168 VALUE
rsock_s_recvfrom(VALUE sock,int argc,VALUE * argv,enum sock_recv_type from)169 rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
170 {
171     rb_io_t *fptr;
172     VALUE str;
173     struct recvfrom_arg arg;
174     VALUE len, flg;
175     long buflen;
176     long slen;
177 
178     rb_scan_args(argc, argv, "12", &len, &flg, &str);
179 
180     if (flg == Qnil) arg.flags = 0;
181     else             arg.flags = NUM2INT(flg);
182     buflen = NUM2INT(len);
183     str = rsock_strbuf(str, buflen);
184 
185     GetOpenFile(sock, fptr);
186     if (rb_io_read_pending(fptr)) {
187 	rb_raise(rb_eIOError, "recv for buffered IO");
188     }
189     arg.fd = fptr->fd;
190     arg.alen = (socklen_t)sizeof(arg.buf);
191     arg.str = str;
192     arg.length = buflen;
193 
194     while (rb_io_check_closed(fptr),
195 	   rsock_maybe_wait_fd(arg.fd),
196 	   (slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp,
197 	                                       (VALUE)&arg)) < 0) {
198         if (!rb_io_wait_readable(fptr->fd)) {
199             rb_sys_fail("recvfrom(2)");
200         }
201     }
202 
203     /* Resize the string to the amount of data received */
204     rb_str_set_len(str, slen);
205     rb_obj_taint(str);
206     switch (from) {
207       case RECV_RECV:
208 	return str;
209       case RECV_IP:
210 #if 0
211 	if (arg.alen != sizeof(struct sockaddr_in)) {
212 	    rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
213 	}
214 #endif
215 	if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
216 	    return rb_assoc_new(str, rsock_ipaddr(&arg.buf.addr, arg.alen, fptr->mode & FMODE_NOREVLOOKUP));
217 	else
218 	    return rb_assoc_new(str, Qnil);
219 
220 #ifdef HAVE_SYS_UN_H
221       case RECV_UNIX:
222         return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
223 #endif
224       case RECV_SOCKET:
225 	return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, &arg.buf.addr, arg.alen));
226       default:
227 	rb_bug("rsock_s_recvfrom called with bad value");
228     }
229 }
230 
231 VALUE
rsock_s_recvfrom_nonblock(VALUE sock,VALUE len,VALUE flg,VALUE str,VALUE ex,enum sock_recv_type from)232 rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
233 			  VALUE ex, enum sock_recv_type from)
234 {
235     rb_io_t *fptr;
236     union_sockaddr buf;
237     socklen_t alen = (socklen_t)sizeof buf;
238     long buflen;
239     long slen;
240     int fd, flags;
241     VALUE addr = Qnil;
242     socklen_t len0;
243 
244     flags = NUM2INT(flg);
245     buflen = NUM2INT(len);
246     str = rsock_strbuf(str, buflen);
247 
248 #ifdef MSG_DONTWAIT
249     /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
250        It is not portable, though. */
251     flags |= MSG_DONTWAIT;
252 #endif
253 
254     GetOpenFile(sock, fptr);
255     if (rb_io_read_pending(fptr)) {
256 	rb_raise(rb_eIOError, "recvfrom for buffered IO");
257     }
258     fd = fptr->fd;
259 
260     rb_io_check_closed(fptr);
261 
262     if (!MSG_DONTWAIT_RELIABLE)
263 	rb_io_set_nonblock(fptr);
264 
265     len0 = alen;
266     slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, &buf.addr, &alen);
267     if (slen != -1 && len0 < alen)
268         alen = len0;
269 
270     if (slen < 0) {
271 	int e = errno;
272 	switch (e) {
273 	  case EAGAIN:
274 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
275 	  case EWOULDBLOCK:
276 #endif
277             if (ex == Qfalse)
278 		return sym_wait_readable;
279             rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "recvfrom(2) would block");
280 	}
281 	rb_syserr_fail(e, "recvfrom(2)");
282     }
283     if (slen != RSTRING_LEN(str)) {
284 	rb_str_set_len(str, slen);
285     }
286     rb_obj_taint(str);
287     switch (from) {
288       case RECV_RECV:
289         return str;
290 
291       case RECV_IP:
292         if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
293             addr = rsock_ipaddr(&buf.addr, alen, fptr->mode & FMODE_NOREVLOOKUP);
294         break;
295 
296       case RECV_SOCKET:
297         addr = rsock_io_socket_addrinfo(sock, &buf.addr, alen);
298         break;
299 
300       default:
301         rb_bug("rsock_s_recvfrom_nonblock called with bad value");
302     }
303     return rb_assoc_new(str, addr);
304 }
305 
306 #if MSG_DONTWAIT_RELIABLE
307 static VALUE sym_wait_writable;
308 
309 /* copied from io.c :< */
310 static long
read_buffered_data(char * ptr,long len,rb_io_t * fptr)311 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
312 {
313     int n = fptr->rbuf.len;
314 
315     if (n <= 0) return 0;
316     if (n > len) n = (int)len;
317     MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
318     fptr->rbuf.off += n;
319     fptr->rbuf.len -= n;
320     return n;
321 }
322 
323 /* :nodoc: */
324 VALUE
rsock_read_nonblock(VALUE sock,VALUE length,VALUE buf,VALUE ex)325 rsock_read_nonblock(VALUE sock, VALUE length, VALUE buf, VALUE ex)
326 {
327     rb_io_t *fptr;
328     long n;
329     long len = NUM2LONG(length);
330     VALUE str = rsock_strbuf(buf, len);
331     char *ptr;
332 
333     OBJ_TAINT(str);
334     GetOpenFile(sock, fptr);
335 
336     if (len == 0) {
337 	rb_str_set_len(str, 0);
338 	return str;
339     }
340 
341     ptr = RSTRING_PTR(str);
342     n = read_buffered_data(ptr, len, fptr);
343     if (n <= 0) {
344 	n = (long)recv(fptr->fd, ptr, len, MSG_DONTWAIT);
345 	if (n < 0) {
346 	    int e = errno;
347 	    if ((e == EWOULDBLOCK || e == EAGAIN)) {
348 		if (ex == Qfalse) return sym_wait_readable;
349 		rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
350 					 e, "read would block");
351 	    }
352 	    rb_syserr_fail_path(e, fptr->pathv);
353 	}
354     }
355     if (n != RSTRING_LEN(str)) {
356 	rb_str_modify(str);
357 	rb_str_set_len(str, n);
358     }
359     if (n == 0) {
360 	if (ex == Qfalse) return Qnil;
361 	rb_eof_error();
362     }
363 
364     return str;
365 }
366 
367 /* :nodoc: */
368 VALUE
rsock_write_nonblock(VALUE sock,VALUE str,VALUE ex)369 rsock_write_nonblock(VALUE sock, VALUE str, VALUE ex)
370 {
371     rb_io_t *fptr;
372     long n;
373 
374     if (!RB_TYPE_P(str, T_STRING))
375 	str = rb_obj_as_string(str);
376 
377     sock = rb_io_get_write_io(sock);
378     GetOpenFile(sock, fptr);
379     rb_io_check_writable(fptr);
380 
381     /*
382      * As with IO#write_nonblock, we may block if somebody is relying on
383      * buffered I/O; but nobody actually hits this because pipes and sockets
384      * are not userspace-buffered in Ruby by default.
385      */
386     if (fptr->wbuf.len > 0) {
387 	rb_io_flush(sock);
388     }
389 
390 #ifdef __APPLE__
391   again:
392 #endif
393     n = (long)send(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str), MSG_DONTWAIT);
394     if (n < 0) {
395 	int e = errno;
396 
397 #ifdef __APPLE__
398 	if (e == EPROTOTYPE) {
399 	    goto again;
400 	}
401 #endif
402 	if (e == EWOULDBLOCK || e == EAGAIN) {
403 	    if (ex == Qfalse) return sym_wait_writable;
404 	    rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
405 				    "write would block");
406 	}
407 	rb_syserr_fail_path(e, fptr->pathv);
408     }
409 
410     return LONG2FIX(n);
411 }
412 #endif /* MSG_DONTWAIT_RELIABLE */
413 
414 /* returns true if SOCK_CLOEXEC is supported */
rsock_detect_cloexec(int fd)415 int rsock_detect_cloexec(int fd)
416 {
417 #ifdef SOCK_CLOEXEC
418     int flags = fcntl(fd, F_GETFD);
419 
420     if (flags == -1)
421 	rb_bug("rsock_detect_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
422 
423     if (flags & FD_CLOEXEC)
424 	return 1;
425 #endif
426     return 0;
427 }
428 
429 #ifdef SOCK_CLOEXEC
430 static int
rsock_socket0(int domain,int type,int proto)431 rsock_socket0(int domain, int type, int proto)
432 {
433     int ret;
434     static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
435 
436     if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
437         ret = socket(domain, type|SOCK_CLOEXEC|RSOCK_NONBLOCK_DEFAULT, proto);
438         if (ret >= 0) {
439             if (ret <= 2)
440                 goto fix_cloexec;
441             goto update_max_fd;
442         }
443     }
444     else if (cloexec_state < 0) { /* usually runs once only for detection */
445         ret = socket(domain, type|SOCK_CLOEXEC|RSOCK_NONBLOCK_DEFAULT, proto);
446         if (ret >= 0) {
447             cloexec_state = rsock_detect_cloexec(ret);
448             if (cloexec_state == 0 || ret <= 2)
449                 goto fix_cloexec;
450             goto update_max_fd;
451         }
452         else if (ret == -1 && errno == EINVAL) {
453             /* SOCK_CLOEXEC is available since Linux 2.6.27.  Linux 2.6.18 fails with EINVAL */
454             ret = socket(domain, type, proto);
455             if (ret != -1) {
456                 cloexec_state = 0;
457                 /* fall through to fix_cloexec */
458             }
459         }
460     }
461     else { /* cloexec_state == 0 */
462         ret = socket(domain, type, proto);
463     }
464     if (ret == -1)
465         return -1;
466 fix_cloexec:
467     rb_maygvl_fd_fix_cloexec(ret);
468     if (RSOCK_NONBLOCK_DEFAULT) {
469         rsock_make_fd_nonblock(ret);
470     }
471 update_max_fd:
472     rb_update_max_fd(ret);
473 
474     return ret;
475 }
476 #else /* !SOCK_CLOEXEC */
477 static int
rsock_socket0(int domain,int type,int proto)478 rsock_socket0(int domain, int type, int proto)
479 {
480     int ret = socket(domain, type, proto);
481 
482     if (ret == -1)
483         return -1;
484     rb_fd_fix_cloexec(ret);
485     if (RSOCK_NONBLOCK_DEFAULT) {
486         rsock_make_fd_nonblock(ret);
487     }
488 
489     return ret;
490 }
491 #endif /* !SOCK_CLOEXEC */
492 
493 int
rsock_socket(int domain,int type,int proto)494 rsock_socket(int domain, int type, int proto)
495 {
496     int fd;
497 
498     fd = rsock_socket0(domain, type, proto);
499     if (fd < 0) {
500        if (rb_gc_for_fd(errno)) {
501            fd = rsock_socket0(domain, type, proto);
502        }
503     }
504     if (0 <= fd)
505         rb_update_max_fd(fd);
506     return fd;
507 }
508 
509 /* emulate blocking connect behavior on EINTR or non-blocking socket */
510 static int
wait_connectable(int fd)511 wait_connectable(int fd)
512 {
513     int sockerr, revents;
514     socklen_t sockerrlen;
515 
516     sockerrlen = (socklen_t)sizeof(sockerr);
517     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
518         return -1;
519 
520     /* necessary for non-blocking sockets (at least ECONNREFUSED) */
521     switch (sockerr) {
522       case 0:
523         break;
524 #ifdef EALREADY
525       case EALREADY:
526 #endif
527 #ifdef EISCONN
528       case EISCONN:
529 #endif
530 #ifdef ECONNREFUSED
531       case ECONNREFUSED:
532 #endif
533 #ifdef EHOSTUNREACH
534       case EHOSTUNREACH:
535 #endif
536         errno = sockerr;
537         return -1;
538     }
539 
540     /*
541      * Stevens book says, successful finish turn on RB_WAITFD_OUT and
542      * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
543      * So it's enough to wait only RB_WAITFD_OUT and check the pending error
544      * by getsockopt().
545      *
546      * Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
547      */
548     revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
549 
550     if (revents < 0)
551         return -1;
552 
553     sockerrlen = (socklen_t)sizeof(sockerr);
554     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
555         return -1;
556 
557     switch (sockerr) {
558       case 0:
559       /*
560        * be defensive in case some platforms set SO_ERROR on the original,
561        * interrupted connect()
562        */
563       case EINTR:
564 #ifdef ERESTART
565       case ERESTART:
566 #endif
567       case EAGAIN:
568 #ifdef EINPROGRESS
569       case EINPROGRESS:
570 #endif
571 #ifdef EALREADY
572       case EALREADY:
573 #endif
574 #ifdef EISCONN
575       case EISCONN:
576 #endif
577 	return 0; /* success */
578       default:
579         /* likely (but not limited to): ECONNREFUSED, ETIMEDOUT, EHOSTUNREACH */
580         errno = sockerr;
581         return -1;
582     }
583 
584     return 0;
585 }
586 
587 struct connect_arg {
588     int fd;
589     socklen_t len;
590     const struct sockaddr *sockaddr;
591 };
592 
593 static VALUE
connect_blocking(void * data)594 connect_blocking(void *data)
595 {
596     struct connect_arg *arg = data;
597     return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
598 }
599 
600 #if defined(SOCKS) && !defined(SOCKS5)
601 static VALUE
socks_connect_blocking(void * data)602 socks_connect_blocking(void *data)
603 {
604     struct connect_arg *arg = data;
605     return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
606 }
607 #endif
608 
609 int
rsock_connect(int fd,const struct sockaddr * sockaddr,int len,int socks)610 rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
611 {
612     int status;
613     rb_blocking_function_t *func = connect_blocking;
614     struct connect_arg arg;
615 
616     arg.fd = fd;
617     arg.sockaddr = sockaddr;
618     arg.len = len;
619 #if defined(SOCKS) && !defined(SOCKS5)
620     if (socks) func = socks_connect_blocking;
621 #endif
622     status = (int)BLOCKING_REGION_FD(func, &arg);
623 
624     if (status < 0) {
625         switch (errno) {
626           case EINTR:
627 #ifdef ERESTART
628           case ERESTART:
629 #endif
630           case EAGAIN:
631 #ifdef EINPROGRESS
632           case EINPROGRESS:
633 #endif
634             return wait_connectable(fd);
635         }
636     }
637     return status;
638 }
639 
640 void
rsock_make_fd_nonblock(int fd)641 rsock_make_fd_nonblock(int fd)
642 {
643     int flags;
644 #ifdef F_GETFL
645     flags = fcntl(fd, F_GETFL);
646     if (flags == -1) {
647         rb_sys_fail("fnctl(2)");
648     }
649 #else
650     flags = 0;
651 #endif
652     flags |= O_NONBLOCK;
653     if (fcntl(fd, F_SETFL, flags) == -1) {
654         rb_sys_fail("fnctl(2)");
655     }
656 }
657 
658 static int
cloexec_accept(int socket,struct sockaddr * address,socklen_t * address_len,int nonblock)659 cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len,
660 	       int nonblock)
661 {
662     int ret;
663     socklen_t len0 = 0;
664 #ifdef HAVE_ACCEPT4
665     static int try_accept4 = 1;
666 #endif
667     if (RSOCK_NONBLOCK_DEFAULT) {
668         nonblock = 1;
669     }
670     if (address_len) len0 = *address_len;
671 #ifdef HAVE_ACCEPT4
672     if (try_accept4) {
673         int flags = 0;
674 #ifdef SOCK_CLOEXEC
675         flags |= SOCK_CLOEXEC;
676 #endif
677 #ifdef SOCK_NONBLOCK
678         if (nonblock) {
679             flags |= SOCK_NONBLOCK;
680         }
681 #endif
682         ret = accept4(socket, address, address_len, flags);
683         /* accept4 is available since Linux 2.6.28, glibc 2.10. */
684         if (ret != -1) {
685             if (ret <= 2)
686                 rb_maygvl_fd_fix_cloexec(ret);
687 #ifndef SOCK_NONBLOCK
688             if (nonblock) {
689                 rsock_make_fd_nonblock(ret);
690             }
691 #endif
692             if (address_len && len0 < *address_len) *address_len = len0;
693             return ret;
694         }
695         if (errno != ENOSYS) {
696             return -1;
697         }
698         try_accept4 = 0;
699     }
700 #endif
701     ret = accept(socket, address, address_len);
702     if (ret == -1) return -1;
703     if (address_len && len0 < *address_len) *address_len = len0;
704     rb_maygvl_fd_fix_cloexec(ret);
705     if (nonblock) {
706         rsock_make_fd_nonblock(ret);
707     }
708     return ret;
709 }
710 
711 VALUE
rsock_s_accept_nonblock(VALUE klass,VALUE ex,rb_io_t * fptr,struct sockaddr * sockaddr,socklen_t * len)712 rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
713 			struct sockaddr *sockaddr, socklen_t *len)
714 {
715     int fd2;
716 
717     rb_io_set_nonblock(fptr);
718     fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len, 1);
719     if (fd2 < 0) {
720 	int e = errno;
721 	switch (e) {
722 	  case EAGAIN:
723 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
724 	  case EWOULDBLOCK:
725 #endif
726 	  case ECONNABORTED:
727 #if defined EPROTO
728 	  case EPROTO:
729 #endif
730             if (ex == Qfalse)
731 		return sym_wait_readable;
732             rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "accept(2) would block");
733 	}
734         rb_syserr_fail(e, "accept(2)");
735     }
736     rb_update_max_fd(fd2);
737     return rsock_init_sock(rb_obj_alloc(klass), fd2);
738 }
739 
740 struct accept_arg {
741     int fd;
742     struct sockaddr *sockaddr;
743     socklen_t *len;
744 };
745 
746 static VALUE
accept_blocking(void * data)747 accept_blocking(void *data)
748 {
749     struct accept_arg *arg = data;
750     return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len, 0);
751 }
752 
753 VALUE
rsock_s_accept(VALUE klass,int fd,struct sockaddr * sockaddr,socklen_t * len)754 rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
755 {
756     int fd2;
757     int retry = 0;
758     struct accept_arg arg;
759 
760     arg.fd = fd;
761     arg.sockaddr = sockaddr;
762     arg.len = len;
763   retry:
764     rsock_maybe_wait_fd(fd);
765     fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
766     if (fd2 < 0) {
767 	int e = errno;
768 	switch (e) {
769 	  case EMFILE:
770 	  case ENFILE:
771 	  case ENOMEM:
772 	    if (retry) break;
773 	    rb_gc();
774 	    retry = 1;
775 	    goto retry;
776 	  default:
777 	    if (!rb_io_wait_readable(fd)) break;
778 	    retry = 0;
779 	    goto retry;
780 	}
781 	rb_syserr_fail(e, "accept(2)");
782     }
783     rb_update_max_fd(fd2);
784     if (!klass) return INT2NUM(fd2);
785     return rsock_init_sock(rb_obj_alloc(klass), fd2);
786 }
787 
788 int
rsock_getfamily(rb_io_t * fptr)789 rsock_getfamily(rb_io_t *fptr)
790 {
791     union_sockaddr ss;
792     socklen_t sslen = (socklen_t)sizeof(ss);
793     int cached = fptr->mode & FMODE_SOCK;
794 
795     if (cached) {
796         switch (cached) {
797 #ifdef AF_UNIX
798 	    case FMODE_UNIX: return AF_UNIX;
799 #endif
800 	    case FMODE_INET: return AF_INET;
801 	    case FMODE_INET6: return AF_INET6;
802 	}
803     }
804 
805     ss.addr.sa_family = AF_UNSPEC;
806     if (getsockname(fptr->fd, &ss.addr, &sslen) < 0)
807         return AF_UNSPEC;
808 
809     switch (ss.addr.sa_family) {
810 #ifdef AF_UNIX
811       case AF_UNIX: fptr->mode |= FMODE_UNIX; break;
812 #endif
813       case AF_INET: fptr->mode |= FMODE_INET; break;
814       case AF_INET6: fptr->mode |= FMODE_INET6; break;
815     }
816 
817     return ss.addr.sa_family;
818 }
819 
820 void
rsock_init_socket_init(void)821 rsock_init_socket_init(void)
822 {
823     /*
824      * SocketError is the error class for socket.
825      */
826     rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
827     rsock_init_ipsocket();
828     rsock_init_tcpsocket();
829     rsock_init_tcpserver();
830     rsock_init_sockssocket();
831     rsock_init_udpsocket();
832     rsock_init_unixsocket();
833     rsock_init_unixserver();
834     rsock_init_sockopt();
835     rsock_init_ancdata();
836     rsock_init_addrinfo();
837     rsock_init_sockifaddr();
838     rsock_init_socket_constants();
839 
840 #undef rb_intern
841     sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
842 
843 #if MSG_DONTWAIT_RELIABLE
844     sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
845 #endif
846 }
847