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