* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ext / socket / socket.c
blob19f9d2a38d2a498c00e3516514de190a383d5434
1 /************************************************
3 socket.c -
5 $Author$
6 created at: Thu Mar 31 12:21:29 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 ************************************************/
12 #include "ruby/ruby.h"
13 #include "ruby/io.h"
14 #include "ruby/signal.h"
15 #include "ruby/util.h"
16 #include <stdio.h>
17 #include <sys/types.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
23 #ifdef HAVE_SYS_UIO_H
24 #include <sys/uio.h>
25 #endif
27 #ifdef HAVE_XTI_H
28 #include <xti.h>
29 #endif
31 #ifndef _WIN32
32 #if defined(__BEOS__) && !defined(__HAIKU__)
33 # include <net/socket.h>
34 #else
35 # include <sys/socket.h>
36 #endif
37 #include <netinet/in.h>
38 #ifdef HAVE_NETINET_IN_SYSTM_H
39 # include <netinet/in_systm.h>
40 #endif
41 #ifdef HAVE_NETINET_TCP_H
42 # include <netinet/tcp.h>
43 #endif
44 #ifdef HAVE_NETINET_UDP_H
45 # include <netinet/udp.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 # include <arpa/inet.h>
49 #endif
50 #include <netdb.h>
51 #endif
52 #include <errno.h>
53 #ifdef HAVE_SYS_UN_H
54 #include <sys/un.h>
55 #endif
57 #if defined(HAVE_FCNTL)
58 #ifdef HAVE_SYS_SELECT_H
59 #include <sys/select.h>
60 #endif
61 #ifdef HAVE_SYS_TYPES_H
62 #include <sys/types.h>
63 #endif
64 #ifdef HAVE_SYS_TIME_H
65 #include <sys/time.h>
66 #endif
67 #ifdef HAVE_FCNTL_H
68 #include <fcntl.h>
69 #endif
70 #endif
71 #ifndef EWOULDBLOCK
72 #define EWOULDBLOCK EAGAIN
73 #endif
74 #ifndef HAVE_GETADDRINFO
75 # include "addrinfo.h"
76 #endif
77 #include "sockport.h"
79 static int do_not_reverse_lookup = 0;
80 #define FMODE_NOREVLOOKUP 0x100
82 VALUE rb_cBasicSocket;
83 VALUE rb_cIPSocket;
84 VALUE rb_cTCPSocket;
85 VALUE rb_cTCPServer;
86 VALUE rb_cUDPSocket;
87 #ifdef AF_UNIX
88 VALUE rb_cUNIXSocket;
89 VALUE rb_cUNIXServer;
90 #endif
91 VALUE rb_cSocket;
93 static VALUE rb_eSocket;
95 #ifdef SOCKS
96 VALUE rb_cSOCKSSocket;
97 #ifdef SOCKS5
98 #include <socks.h>
99 #else
100 void SOCKSinit();
101 int Rconnect();
102 #endif
103 #endif
105 #define BLOCKING_REGION(func, arg) (long)rb_thread_blocking_region((func), (arg), RB_UBF_DFL, 0)
107 #define INET_CLIENT 0
108 #define INET_SERVER 1
109 #define INET_SOCKS 2
111 #ifndef HAVE_SOCKADDR_STORAGE
113 * RFC 2553: protocol-independent placeholder for socket addresses
115 #define _SS_MAXSIZE 128
116 #define _SS_ALIGNSIZE (sizeof(double))
117 #define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2)
118 #define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \
119 _SS_PAD1SIZE - _SS_ALIGNSIZE)
121 struct sockaddr_storage {
122 #ifdef HAVE_SA_LEN
123 unsigned char ss_len; /* address length */
124 unsigned char ss_family; /* address family */
125 #else
126 unsigned short ss_family;
127 #endif
128 char __ss_pad1[_SS_PAD1SIZE];
129 double __ss_align; /* force desired structure storage alignment */
130 char __ss_pad2[_SS_PAD2SIZE];
132 #endif
134 #if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
135 #define LOOKUP_ORDERS 3
136 static int lookup_order_table[LOOKUP_ORDERS] = {
137 #if defined(LOOKUP_ORDER_HACK_INET)
138 PF_INET, PF_INET6, PF_UNSPEC,
139 #elif defined(LOOKUP_ORDER_HACK_INET6)
140 PF_INET6, PF_INET, PF_UNSPEC,
141 #else
142 /* should not happen */
143 #endif
146 static int
147 ruby_getaddrinfo(char *nodename, char *servname,
148 struct addrinfo *hints, struct addrinfo **res)
150 struct addrinfo tmp_hints;
151 int i, af, error;
153 if (hints->ai_family != PF_UNSPEC) {
154 return getaddrinfo(nodename, servname, hints, res);
157 for (i = 0; i < LOOKUP_ORDERS; i++) {
158 af = lookup_order_table[i];
159 MEMCPY(&tmp_hints, hints, struct addrinfo, 1);
160 tmp_hints.ai_family = af;
161 error = getaddrinfo(nodename, servname, &tmp_hints, res);
162 if (error) {
163 if (tmp_hints.ai_family == PF_UNSPEC) {
164 break;
167 else {
168 break;
172 return error;
174 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res))
175 #endif
177 #if defined(_AIX)
178 static int
179 ruby_getaddrinfo__aix(char *nodename, char *servname,
180 struct addrinfo *hints, struct addrinfo **res)
182 int error = getaddrinfo(nodename, servname, hints, res);
183 struct addrinfo *r;
184 if (error)
185 return error;
186 for (r = *res; r != NULL; r = r->ai_next) {
187 if (r->ai_addr->sa_family == 0)
188 r->ai_addr->sa_family = r->ai_family;
189 if (r->ai_addr->sa_len == 0)
190 r->ai_addr->sa_len = r->ai_addrlen;
192 return 0;
194 #undef getaddrinfo
195 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res))
196 static int
197 ruby_getnameinfo__aix(sa, salen, host, hostlen, serv, servlen, flags)
198 const struct sockaddr *sa;
199 size_t salen;
200 char *host;
201 size_t hostlen;
202 char *serv;
203 size_t servlen;
204 int flags;
206 struct sockaddr_in6 *sa6;
207 u_int32_t *a6;
209 if (sa->sa_family == AF_INET6) {
210 sa6 = (struct sockaddr_in6 *)sa;
211 a6 = sa6->sin6_addr.u6_addr.u6_addr32;
213 if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
214 strncpy(host, "::", hostlen);
215 snprintf(serv, servlen, "%d", sa6->sin6_port);
216 return 0;
219 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
221 #undef getnameinfo
222 #define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
223 ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags))
224 #ifndef CMSG_SPACE
225 # define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
226 #endif
227 #ifndef CMSG_LEN
228 # define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
229 #endif
230 #endif
232 #ifdef __BEOS__
233 #undef close
234 #define close closesocket
235 #endif
237 static VALUE
238 init_sock(VALUE sock, int fd)
240 rb_io_t *fp;
242 MakeOpenFile(sock, fp);
243 fp->fd = fd;
244 fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
245 #if defined(_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__EMX__)
246 fp->mode |= FMODE_BINMODE;
247 #endif
248 if (do_not_reverse_lookup) {
249 fp->mode |= FMODE_NOREVLOOKUP;
251 rb_io_synchronized(fp);
253 return sock;
256 static VALUE
257 bsock_s_for_fd(VALUE klass, VALUE fd)
259 rb_io_t *fptr;
260 VALUE sock = init_sock(rb_obj_alloc(klass), NUM2INT(fd));
262 GetOpenFile(sock, fptr);
264 return sock;
267 static VALUE
268 bsock_shutdown(int argc, VALUE *argv, VALUE sock)
270 VALUE howto;
271 int how;
272 rb_io_t *fptr;
274 if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
275 rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket");
277 rb_scan_args(argc, argv, "01", &howto);
278 if (howto == Qnil)
279 how = 2;
280 else {
281 how = NUM2INT(howto);
282 if (how < 0 || 2 < how) {
283 rb_raise(rb_eArgError, "`how' should be either 0, 1, 2");
286 GetOpenFile(sock, fptr);
287 if (shutdown(fptr->fd, how) == -1)
288 rb_sys_fail(0);
290 return INT2FIX(0);
293 static VALUE
294 bsock_close_read(VALUE sock)
296 rb_io_t *fptr;
298 if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
299 rb_raise(rb_eSecurityError, "Insecure: can't close socket");
301 GetOpenFile(sock, fptr);
302 shutdown(fptr->fd, 0);
303 if (!(fptr->mode & FMODE_WRITABLE)) {
304 return rb_io_close(sock);
306 fptr->mode &= ~FMODE_READABLE;
308 return Qnil;
311 static VALUE
312 bsock_close_write(VALUE sock)
314 rb_io_t *fptr;
316 if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
317 rb_raise(rb_eSecurityError, "Insecure: can't close socket");
319 GetOpenFile(sock, fptr);
320 if (!(fptr->mode & FMODE_READABLE)) {
321 return rb_io_close(sock);
323 shutdown(fptr->fd, 1);
324 fptr->mode &= ~FMODE_WRITABLE;
326 return Qnil;
330 * Document-method: setsockopt
331 * call-seq: setsockopt(level, optname, optval)
333 * Sets a socket option. These are protocol and system specific, see your
334 * local sytem documentation for details.
336 * === Parameters
337 * * +level+ is an integer, usually one of the SOL_ constants such as
338 * Socket::SOL_SOCKET, or a protocol level.
339 * * +optname+ is an integer, usually one of the SO_ constants, such
340 * as Socket::SO_REUSEADDR.
341 * * +optval+ is the value of the option, it is passed to the underlying
342 * setsockopt() as a pointer to a certain number of bytes. How this is
343 * done depends on the type:
344 * - Fixnum: value is assigned to an int, and a pointer to the int is
345 * passed, with length of sizeof(int).
346 * - true or false: 1 or 0 (respectively) is assigned to an int, and the
347 * int is passed as for a Fixnum. Note that +false+ must be passed,
348 * not +nil+.
349 * - String: the string's data and length is passed to the socket.
351 * === Examples
353 * Some socket options are integers with boolean values, in this case
354 * #setsockopt could be called like this:
355 * sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
357 * Some socket options are integers with numeric values, in this case
358 * #setsockopt could be called like this:
359 * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
361 * Option values may be structs. Passing them can be complex as it involves
362 * examining your system headers to determine the correct definition. An
363 * example is an +ip_mreq+, which may be defined in your system headers as:
364 * struct ip_mreq {
365 * struct in_addr imr_multiaddr;
366 * struct in_addr imr_interface;
367 * };
369 * In this case #setsockopt could be called like this:
370 * optval = IPAddr.new("224.0.0.251") + Socket::INADDR_ANY
371 * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)
374 static VALUE
375 bsock_setsockopt(VALUE sock, VALUE lev, VALUE optname, VALUE val)
377 int level, option;
378 rb_io_t *fptr;
379 int i;
380 char *v;
381 int vlen;
383 rb_secure(2);
384 level = NUM2INT(lev);
385 option = NUM2INT(optname);
387 switch (TYPE(val)) {
388 case T_FIXNUM:
389 i = FIX2INT(val);
390 goto numval;
391 case T_FALSE:
392 i = 0;
393 goto numval;
394 case T_TRUE:
395 i = 1;
396 numval:
397 v = (char*)&i; vlen = sizeof(i);
398 break;
399 default:
400 StringValue(val);
401 v = RSTRING_PTR(val);
402 vlen = RSTRING_LEN(val);
403 break;
406 GetOpenFile(sock, fptr);
407 if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
408 rb_sys_fail(fptr->path);
410 return INT2FIX(0);
414 * Document-method: getsockopt
415 * call-seq: getsockopt(level, optname)
417 * Gets a socket option. These are protocol and system specific, see your
418 * local sytem documentation for details. The option is returned as
419 * a String with the data being the binary value of the socket option.
421 * === Parameters
422 * * +level+ is an integer, usually one of the SOL_ constants such as
423 * Socket::SOL_SOCKET, or a protocol level.
424 * * +optname+ is an integer, usually one of the SO_ constants, such
425 * as Socket::SO_REUSEADDR.
427 * === Examples
429 * Some socket options are integers with boolean values, in this case
430 * #getsockopt could be called like this:
431 * optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
432 * optval = optval.unpack "i"
433 * reuseaddr = optval[0] == 0 ? false : true
435 * Some socket options are integers with numeric values, in this case
436 * #getsockopt could be called like this:
437 * optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
438 * ipttl = optval.unpack("i")[0]
440 * Option values may be structs. Decoding them can be complex as it involves
441 * examining your system headers to determine the correct definition. An
442 * example is a +struct linger+, which may be defined in your system headers
443 * as:
444 * struct linger {
445 * int l_onoff;
446 * int l_linger;
447 * };
449 * In this case #getsockopt could be called like this:
450 * optval = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
451 * onoff, linger = optval.unpack "ii"
453 static VALUE
454 bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
456 #if !defined(__BEOS__)
457 int level, option;
458 socklen_t len;
459 char *buf;
460 rb_io_t *fptr;
462 level = NUM2INT(lev);
463 option = NUM2INT(optname);
464 len = 256;
465 buf = ALLOCA_N(char,len);
467 GetOpenFile(sock, fptr);
468 if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
469 rb_sys_fail(fptr->path);
471 return rb_str_new(buf, len);
472 #else
473 rb_notimplement();
474 #endif
477 static VALUE
478 bsock_getsockname(VALUE sock)
480 char buf[1024];
481 socklen_t len = sizeof buf;
482 rb_io_t *fptr;
484 GetOpenFile(sock, fptr);
485 if (getsockname(fptr->fd, (struct sockaddr*)buf, &len) < 0)
486 rb_sys_fail("getsockname(2)");
487 return rb_str_new(buf, len);
490 static VALUE
491 bsock_getpeername(VALUE sock)
493 char buf[1024];
494 socklen_t len = sizeof buf;
495 rb_io_t *fptr;
497 GetOpenFile(sock, fptr);
498 if (getpeername(fptr->fd, (struct sockaddr*)buf, &len) < 0)
499 rb_sys_fail("getpeername(2)");
500 return rb_str_new(buf, len);
503 struct send_arg {
504 int fd, flags;
505 VALUE mesg;
506 struct sockaddr *to;
507 socklen_t tolen;
510 static VALUE
511 sendto_blocking(void *data)
513 struct send_arg *arg = data;
514 VALUE mesg = arg->mesg;
515 return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
516 arg->flags, arg->to, arg->tolen);
519 static VALUE
520 send_blocking(void *data)
522 struct send_arg *arg = data;
523 VALUE mesg = arg->mesg;
524 return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
525 arg->flags);
528 static VALUE
529 bsock_send(int argc, VALUE *argv, VALUE sock)
531 struct send_arg arg;
532 VALUE flags, to;
533 rb_io_t *fptr;
534 int n;
535 rb_blocking_function_t *func;
537 rb_secure(4);
538 rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
540 StringValue(arg.mesg);
541 if (!NIL_P(to)) {
542 StringValue(to);
543 to = rb_str_new4(to);
544 arg.to = (struct sockaddr *)RSTRING_PTR(to);
545 arg.tolen = RSTRING_LEN(to);
546 func = sendto_blocking;
548 else {
549 func = send_blocking;
551 GetOpenFile(sock, fptr);
552 arg.fd = fptr->fd;
553 arg.flags = NUM2INT(flags);
554 while (rb_thread_fd_writable(arg.fd),
555 (n = (int)BLOCKING_REGION(func, &arg)) < 0) {
556 if (rb_io_wait_writable(arg.fd)) {
557 continue;
559 rb_sys_fail("send(2)");
561 return INT2FIX(n);
564 static VALUE
565 bsock_do_not_reverse_lookup(VALUE sock)
567 rb_io_t *fptr;
569 GetOpenFile(sock, fptr);
570 return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
573 static VALUE
574 bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
576 rb_io_t *fptr;
578 rb_secure(4);
579 GetOpenFile(sock, fptr);
580 if (RTEST(state)) {
581 fptr->mode |= FMODE_NOREVLOOKUP;
583 else {
584 fptr->mode &= ~FMODE_NOREVLOOKUP;
586 return sock;
589 static VALUE ipaddr(struct sockaddr*, int);
590 #ifdef HAVE_SYS_UN_H
591 static VALUE unixaddr(struct sockaddr_un*, socklen_t);
592 #endif
594 enum sock_recv_type {
595 RECV_RECV, /* BasicSocket#recv(no from) */
596 RECV_IP, /* IPSocket#recvfrom */
597 RECV_UNIX, /* UNIXSocket#recvfrom */
598 RECV_SOCKET /* Socket#recvfrom */
601 struct recvfrom_arg {
602 int fd, flags;
603 VALUE str;
604 socklen_t alen;
605 char buf[1024];
608 static VALUE
609 recvfrom_blocking(void *data)
611 struct recvfrom_arg *arg = data;
612 return (VALUE)recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
613 arg->flags, (struct sockaddr*)arg->buf, &arg->alen);
616 static VALUE
617 s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
619 rb_io_t *fptr;
620 VALUE str, klass;
621 struct recvfrom_arg arg;
622 VALUE len, flg;
623 long buflen;
624 long slen;
626 rb_scan_args(argc, argv, "11", &len, &flg);
628 if (flg == Qnil) arg.flags = 0;
629 else arg.flags = NUM2INT(flg);
630 buflen = NUM2INT(len);
632 GetOpenFile(sock, fptr);
633 if (rb_io_read_pending(fptr)) {
634 rb_raise(rb_eIOError, "recv for buffered IO");
636 arg.fd = fptr->fd;
637 arg.alen = sizeof(arg.buf);
639 arg.str = str = rb_tainted_str_new(0, buflen);
640 klass = RBASIC(str)->klass;
641 RBASIC(str)->klass = 0;
643 while (rb_io_check_closed(fptr),
644 rb_thread_wait_fd(arg.fd),
645 (slen = BLOCKING_REGION(recvfrom_blocking, &arg)) < 0) {
646 if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
647 rb_raise(rb_eRuntimeError, "buffer string modified");
651 RBASIC(str)->klass = klass;
652 if (slen < RSTRING_LEN(str)) {
653 rb_str_set_len(str, slen);
655 rb_obj_taint(str);
656 switch (from) {
657 case RECV_RECV:
658 return str;
659 case RECV_IP:
660 #if 0
661 if (arg.alen != sizeof(struct sockaddr_in)) {
662 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
664 #endif
665 if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
666 return rb_assoc_new(str, ipaddr((struct sockaddr*)arg.buf, fptr->mode & FMODE_NOREVLOOKUP));
667 else
668 return rb_assoc_new(str, Qnil);
670 #ifdef HAVE_SYS_UN_H
671 case RECV_UNIX:
672 return rb_assoc_new(str, unixaddr((struct sockaddr_un*)arg.buf, arg.alen));
673 #endif
674 case RECV_SOCKET:
675 return rb_assoc_new(str, rb_str_new(arg.buf, arg.alen));
676 default:
677 rb_bug("s_recvfrom called with bad value");
681 static VALUE
682 s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
684 rb_io_t *fptr;
685 VALUE str;
686 char buf[1024];
687 socklen_t alen = sizeof buf;
688 VALUE len, flg;
689 long buflen;
690 long slen;
691 int fd, flags;
692 VALUE addr = Qnil;
694 rb_scan_args(argc, argv, "11", &len, &flg);
696 if (flg == Qnil) flags = 0;
697 else flags = NUM2INT(flg);
698 buflen = NUM2INT(len);
700 #ifdef MSG_DONTWAIT
701 /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
702 It is not portable, though. */
703 flags |= MSG_DONTWAIT;
704 #endif
706 GetOpenFile(sock, fptr);
707 if (rb_io_read_pending(fptr)) {
708 rb_raise(rb_eIOError, "recvfrom for buffered IO");
710 fd = fptr->fd;
712 str = rb_tainted_str_new(0, buflen);
714 rb_io_check_closed(fptr);
715 rb_io_set_nonblock(fptr);
716 slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, (struct sockaddr*)buf, &alen);
718 if (slen < 0) {
719 rb_sys_fail("recvfrom(2)");
721 if (slen < RSTRING_LEN(str)) {
722 rb_str_set_len(str, slen);
724 rb_obj_taint(str);
725 switch (from) {
726 case RECV_RECV:
727 return str;
729 case RECV_IP:
730 if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
731 addr = ipaddr((struct sockaddr*)buf, fptr->mode & FMODE_NOREVLOOKUP);
732 break;
734 case RECV_SOCKET:
735 addr = rb_str_new(buf, alen);
736 break;
738 default:
739 rb_bug("s_recvfrom_nonblock called with bad value");
741 return rb_assoc_new(str, addr);
744 static VALUE
745 bsock_recv(int argc, VALUE *argv, VALUE sock)
747 return s_recvfrom(sock, argc, argv, RECV_RECV);
751 * call-seq:
752 * basicsocket.recv_nonblock(maxlen) => mesg
753 * basicsocket.recv_nonblock(maxlen, flags) => mesg
755 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
756 * O_NONBLOCK is set for the underlying file descriptor.
757 * _flags_ is zero or more of the +MSG_+ options.
758 * The result, _mesg_, is the data received.
760 * When recvfrom(2) returns 0, Socket#recv_nonblock returns
761 * an empty string as data.
762 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
764 * === Parameters
765 * * +maxlen+ - the number of bytes to receive from the socket
766 * * +flags+ - zero or more of the +MSG_+ options
768 * === Example
769 * serv = TCPServer.new("127.0.0.1", 0)
770 * af, port, host, addr = serv.addr
771 * c = TCPSocket.new(addr, port)
772 * s = serv.accept
773 * c.send "aaa", 0
774 * IO.select([s])
775 * p s.recv_nonblock(10) #=> "aaa"
777 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
778 * to _recv_nonblock_ fails.
780 * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
781 * including Errno::EWOULDBLOCK.
783 * === See
784 * * Socket#recvfrom
787 static VALUE
788 bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
790 return s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
793 static VALUE
794 bsock_do_not_rev_lookup(void)
796 return do_not_reverse_lookup?Qtrue:Qfalse;
799 static VALUE
800 bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
802 rb_secure(4);
803 do_not_reverse_lookup = RTEST(val);
804 return val;
807 NORETURN(static void raise_socket_error(const char *, int));
808 static void
809 raise_socket_error(const char *reason, int error)
811 #ifdef EAI_SYSTEM
812 if (error == EAI_SYSTEM) rb_sys_fail(reason);
813 #endif
814 rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
817 static void
818 make_ipaddr0(struct sockaddr *addr, char *buf, size_t len)
820 int error;
822 error = getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST);
823 if (error) {
824 raise_socket_error("getnameinfo", error);
828 static VALUE
829 make_ipaddr(struct sockaddr *addr)
831 char buf[1024];
833 make_ipaddr0(addr, buf, sizeof(buf));
834 return rb_str_new2(buf);
837 static void
838 make_inetaddr(long host, char *buf, size_t len)
840 struct sockaddr_in sin;
842 MEMZERO(&sin, struct sockaddr_in, 1);
843 sin.sin_family = AF_INET;
844 SET_SIN_LEN(&sin, sizeof(sin));
845 sin.sin_addr.s_addr = host;
846 make_ipaddr0((struct sockaddr*)&sin, buf, len);
849 static int
850 str_isnumber(const char *p)
852 char *ep;
854 if (!p || *p == '\0')
855 return 0;
856 ep = NULL;
857 (void)STRTOUL(p, &ep, 10);
858 if (ep && *ep == '\0')
859 return 1;
860 else
861 return 0;
864 static char*
865 host_str(VALUE host, char *hbuf, size_t len)
867 if (NIL_P(host)) {
868 return NULL;
870 else if (rb_obj_is_kind_of(host, rb_cInteger)) {
871 long i = NUM2LONG(host);
873 make_inetaddr(htonl(i), hbuf, len);
874 return hbuf;
876 else {
877 char *name;
879 SafeStringValue(host);
880 name = RSTRING_PTR(host);
881 if (!name || *name == 0 || (name[0] == '<' && strcmp(name, "<any>") == 0)) {
882 make_inetaddr(INADDR_ANY, hbuf, len);
884 else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
885 make_inetaddr(INADDR_BROADCAST, hbuf, len);
887 else if (strlen(name) >= len) {
888 rb_raise(rb_eArgError, "hostname too long (%"PRIuSIZE")",
889 strlen(name));
891 else {
892 strcpy(hbuf, name);
894 return hbuf;
898 static char*
899 port_str(VALUE port, char *pbuf, size_t len)
901 if (NIL_P(port)) {
902 return 0;
904 else if (FIXNUM_P(port)) {
905 snprintf(pbuf, len, "%ld", FIX2LONG(port));
906 return pbuf;
908 else {
909 char *serv;
911 SafeStringValue(port);
912 serv = RSTRING_PTR(port);
913 if (strlen(serv) >= len) {
914 rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
915 strlen(serv));
917 strcpy(pbuf, serv);
918 return pbuf;
922 #ifndef NI_MAXHOST
923 # define NI_MAXHOST 1025
924 #endif
925 #ifndef NI_MAXSERV
926 # define NI_MAXSERV 32
927 #endif
929 static struct addrinfo*
930 sock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
932 struct addrinfo hints;
933 struct addrinfo* res = NULL;
934 char *hostp, *portp;
935 int error;
936 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
938 hostp = host_str(host, hbuf, sizeof(hbuf));
939 portp = port_str(port, pbuf, sizeof(pbuf));
941 if (socktype == 0 && flags == 0 && str_isnumber(portp)) {
942 socktype = SOCK_DGRAM;
945 MEMZERO(&hints, struct addrinfo, 1);
946 hints.ai_family = AF_UNSPEC;
947 hints.ai_socktype = socktype;
948 hints.ai_flags = flags;
949 error = getaddrinfo(hostp, portp, &hints, &res);
950 if (error) {
951 if (hostp && hostp[strlen(hostp)-1] == '\n') {
952 rb_raise(rb_eSocket, "newline at the end of hostname");
954 raise_socket_error("getaddrinfo", error);
957 #if defined(__APPLE__) && defined(__MACH__)
959 struct addrinfo *r;
960 r = res;
961 while (r) {
962 if (! r->ai_socktype) r->ai_socktype = hints.ai_socktype;
963 if (! r->ai_protocol) {
964 if (r->ai_socktype == SOCK_DGRAM) {
965 r->ai_protocol = IPPROTO_UDP;
967 else if (r->ai_socktype == SOCK_STREAM) {
968 r->ai_protocol = IPPROTO_TCP;
971 r = r->ai_next;
974 #endif
975 return res;
978 static VALUE
979 ipaddr(struct sockaddr *sockaddr, int norevlookup)
981 VALUE family, port, addr1, addr2;
982 VALUE ary;
983 int error;
984 char hbuf[1024], pbuf[1024];
986 switch (sockaddr->sa_family) {
987 case AF_UNSPEC:
988 family = rb_str_new2("AF_UNSPEC");
989 break;
990 case AF_INET:
991 family = rb_str_new2("AF_INET");
992 break;
993 #ifdef INET6
994 case AF_INET6:
995 family = rb_str_new2("AF_INET6");
996 break;
997 #endif
998 #ifdef AF_LOCAL
999 case AF_LOCAL:
1000 family = rb_str_new2("AF_LOCAL");
1001 break;
1002 #elif AF_UNIX
1003 case AF_UNIX:
1004 family = rb_str_new2("AF_UNIX");
1005 break;
1006 #endif
1007 default:
1008 sprintf(pbuf, "unknown:%d", sockaddr->sa_family);
1009 family = rb_str_new2(pbuf);
1010 break;
1013 addr1 = Qnil;
1014 if (!norevlookup) {
1015 error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
1016 NULL, 0, 0);
1017 if (! error) {
1018 addr1 = rb_str_new2(hbuf);
1021 error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
1022 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1023 if (error) {
1024 raise_socket_error("getnameinfo", error);
1026 addr2 = rb_str_new2(hbuf);
1027 if (addr1 == Qnil) {
1028 addr1 = addr2;
1030 port = INT2FIX(atoi(pbuf));
1031 ary = rb_ary_new3(4, family, port, addr1, addr2);
1033 return ary;
1036 static int
1037 ruby_socket(int domain, int type, int proto)
1039 int fd;
1041 fd = socket(domain, type, proto);
1042 if (fd < 0) {
1043 if (errno == EMFILE || errno == ENFILE) {
1044 rb_gc();
1045 fd = socket(domain, type, proto);
1048 return fd;
1051 static int
1052 wait_connectable0(int fd, rb_fdset_t *fds_w, rb_fdset_t *fds_e)
1054 int sockerr;
1055 socklen_t sockerrlen;
1057 for (;;) {
1058 rb_fd_zero(fds_w);
1059 rb_fd_zero(fds_e);
1061 rb_fd_set(fd, fds_w);
1062 rb_fd_set(fd, fds_e);
1064 rb_thread_select(fd+1, 0, rb_fd_ptr(fds_w), rb_fd_ptr(fds_e), 0);
1066 if (rb_fd_isset(fd, fds_w)) {
1067 return 0;
1069 else if (rb_fd_isset(fd, fds_e)) {
1070 sockerrlen = sizeof(sockerr);
1071 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr,
1072 &sockerrlen) == 0) {
1073 if (sockerr == 0)
1074 continue; /* workaround for winsock */
1075 errno = sockerr;
1077 return -1;
1081 return 0;
1084 struct wait_connectable_arg {
1085 int fd;
1086 rb_fdset_t fds_w;
1087 rb_fdset_t fds_e;
1090 #ifdef HAVE_RB_FD_INIT
1091 static VALUE
1092 try_wait_connectable(VALUE arg)
1094 struct wait_connectable_arg *p = (struct wait_connectable_arg *)arg;
1095 return (VALUE)wait_connectable0(p->fd, &p->fds_w, &p->fds_e);
1098 static VALUE
1099 wait_connectable_ensure(VALUE arg)
1101 struct wait_connectable_arg *p = (struct wait_connectable_arg *)arg;
1102 rb_fd_term(&p->fds_w);
1103 rb_fd_term(&p->fds_e);
1104 return Qnil;
1106 #endif
1108 static int
1109 wait_connectable(int fd)
1111 struct wait_connectable_arg arg;
1113 rb_fd_init(&arg.fds_w);
1114 rb_fd_init(&arg.fds_e);
1115 #ifdef HAVE_RB_FD_INIT
1116 arg.fd = fd;
1117 return (int)rb_ensure(try_wait_connectable, (VALUE)&arg,
1118 wait_connectable_ensure,(VALUE)&arg);
1119 #else
1120 return wait_connectable0(fd, &arg.fds_w, &arg.fds_e);
1121 #endif
1124 #ifdef __CYGWIN__
1125 #define WAIT_IN_PROGRESS 10
1126 #endif
1127 #ifdef __APPLE__
1128 #define WAIT_IN_PROGRESS 10
1129 #endif
1130 #ifdef __linux__
1131 /* returns correct error */
1132 #define WAIT_IN_PROGRESS 0
1133 #endif
1134 #ifndef WAIT_IN_PROGRESS
1135 /* BSD origin code apparently has a problem */
1136 #define WAIT_IN_PROGRESS 1
1137 #endif
1139 struct connect_arg {
1140 int fd;
1141 const struct sockaddr *sockaddr;
1142 socklen_t len;
1145 static VALUE
1146 connect_blocking(void *data)
1148 struct connect_arg *arg = data;
1149 return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
1152 #if defined(SOCKS) && !defined(SOCKS5)
1153 static VALUE
1154 socks_connect_blocking(void *data)
1156 struct connect_arg *arg = data;
1157 return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
1159 #endif
1161 static int
1162 ruby_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
1164 int status;
1165 rb_blocking_function_t *func = connect_blocking;
1166 struct connect_arg arg;
1167 #if WAIT_IN_PROGRESS > 0
1168 int wait_in_progress = -1;
1169 int sockerr;
1170 socklen_t sockerrlen;
1171 #endif
1173 arg.fd = fd;
1174 arg.sockaddr = sockaddr;
1175 arg.len = len;
1176 #if defined(SOCKS) && !defined(SOCKS5)
1177 if (socks) func = socks_connect_blocking;
1178 #endif
1179 for (;;) {
1180 status = (int)BLOCKING_REGION(func, &arg);
1181 if (status < 0) {
1182 switch (errno) {
1183 case EAGAIN:
1184 #ifdef EINPROGRESS
1185 case EINPROGRESS:
1186 #endif
1187 #if WAIT_IN_PROGRESS > 0
1188 sockerrlen = sizeof(sockerr);
1189 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
1190 if (status) break;
1191 if (sockerr) {
1192 status = -1;
1193 errno = sockerr;
1194 break;
1196 #endif
1197 #ifdef EALREADY
1198 case EALREADY:
1199 #endif
1200 #if WAIT_IN_PROGRESS > 0
1201 wait_in_progress = WAIT_IN_PROGRESS;
1202 #endif
1203 status = wait_connectable(fd);
1204 if (status) {
1205 break;
1207 errno = 0;
1208 continue;
1210 #if WAIT_IN_PROGRESS > 0
1211 case EINVAL:
1212 if (wait_in_progress-- > 0) {
1214 * connect() after EINPROGRESS returns EINVAL on
1215 * some platforms, need to check true error
1216 * status.
1218 sockerrlen = sizeof(sockerr);
1219 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
1220 if (!status && !sockerr) {
1221 struct timeval tv = {0, 100000};
1222 rb_thread_wait_for(tv);
1223 continue;
1225 status = -1;
1226 errno = sockerr;
1228 break;
1229 #endif
1231 #ifdef EISCONN
1232 case EISCONN:
1233 status = 0;
1234 errno = 0;
1235 break;
1236 #endif
1237 default:
1238 break;
1241 return status;
1245 struct inetsock_arg
1247 VALUE sock;
1248 struct {
1249 VALUE host, serv;
1250 struct addrinfo *res;
1251 } remote, local;
1252 int type;
1253 int fd;
1256 static VALUE
1257 inetsock_cleanup(struct inetsock_arg *arg)
1259 if (arg->remote.res) {
1260 freeaddrinfo(arg->remote.res);
1261 arg->remote.res = 0;
1263 if (arg->local.res) {
1264 freeaddrinfo(arg->local.res);
1265 arg->local.res = 0;
1267 if (arg->fd >= 0) {
1268 close(arg->fd);
1270 return Qnil;
1273 static VALUE
1274 init_inetsock_internal(struct inetsock_arg *arg)
1276 int type = arg->type;
1277 struct addrinfo *res;
1278 int fd, status = 0;
1279 const char *syscall = 0;
1281 arg->remote.res = sock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM,
1282 (type == INET_SERVER) ? AI_PASSIVE : 0);
1284 * Maybe also accept a local address
1287 if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
1288 arg->local.res = sock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0);
1291 arg->fd = fd = -1;
1292 for (res = arg->remote.res; res; res = res->ai_next) {
1293 status = ruby_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
1294 syscall = "socket(2)";
1295 fd = status;
1296 if (fd < 0) {
1297 continue;
1299 arg->fd = fd;
1300 if (type == INET_SERVER) {
1301 #if !defined(_WIN32) && !defined(__CYGWIN__)
1302 status = 1;
1303 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1304 (char*)&status, sizeof(status));
1305 #endif
1306 status = bind(fd, res->ai_addr, res->ai_addrlen);
1307 syscall = "bind(2)";
1309 else {
1310 if (arg->local.res) {
1311 status = bind(fd, arg->local.res->ai_addr, arg->local.res->ai_addrlen);
1312 syscall = "bind(2)";
1315 if (status >= 0) {
1316 status = ruby_connect(fd, res->ai_addr, res->ai_addrlen,
1317 (type == INET_SOCKS));
1318 syscall = "connect(2)";
1322 if (status < 0) {
1323 close(fd);
1324 arg->fd = fd = -1;
1325 continue;
1326 } else
1327 break;
1329 if (status < 0) {
1330 rb_sys_fail(syscall);
1333 arg->fd = -1;
1335 if (type == INET_SERVER)
1336 listen(fd, 5);
1338 /* create new instance */
1339 return init_sock(arg->sock, fd);
1342 static VALUE
1343 init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
1344 VALUE local_host, VALUE local_serv, int type)
1346 struct inetsock_arg arg;
1347 arg.sock = sock;
1348 arg.remote.host = remote_host;
1349 arg.remote.serv = remote_serv;
1350 arg.remote.res = 0;
1351 arg.local.host = local_host;
1352 arg.local.serv = local_serv;
1353 arg.local.res = 0;
1354 arg.type = type;
1355 arg.fd = -1;
1356 return rb_ensure(init_inetsock_internal, (VALUE)&arg,
1357 inetsock_cleanup, (VALUE)&arg);
1361 * call-seq:
1362 * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil)
1364 * Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
1365 * and +local_port+ are specified, then those parameters are used on the local
1366 * end to establish the connection.
1368 static VALUE
1369 tcp_init(int argc, VALUE *argv, VALUE sock)
1371 VALUE remote_host, remote_serv;
1372 VALUE local_host, local_serv;
1374 rb_scan_args(argc, argv, "22", &remote_host, &remote_serv,
1375 &local_host, &local_serv);
1377 return init_inetsock(sock, remote_host, remote_serv,
1378 local_host, local_serv, INET_CLIENT);
1381 #ifdef SOCKS
1382 static VALUE
1383 socks_init(VALUE sock, VALUE host, VALUE serv)
1385 static init = 0;
1387 if (init == 0) {
1388 SOCKSinit("ruby");
1389 init = 1;
1392 return init_inetsock(sock, host, serv, Qnil, Qnil, INET_SOCKS);
1395 #ifdef SOCKS5
1396 static VALUE
1397 socks_s_close(VALUE sock)
1399 rb_io_t *fptr;
1401 if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
1402 rb_raise(rb_eSecurityError, "Insecure: can't close socket");
1404 GetOpenFile(sock, fptr);
1405 shutdown(fptr->fd, 2);
1406 return rb_io_close(sock);
1408 #endif
1409 #endif
1411 struct hostent_arg {
1412 VALUE host;
1413 struct addrinfo* addr;
1414 VALUE (*ipaddr)(struct sockaddr*, size_t);
1417 static VALUE
1418 make_hostent_internal(struct hostent_arg *arg)
1420 VALUE host = arg->host;
1421 struct addrinfo* addr = arg->addr;
1422 VALUE (*ipaddr)(struct sockaddr*, size_t) = arg->ipaddr;
1424 struct addrinfo *ai;
1425 struct hostent *h;
1426 VALUE ary, names;
1427 char **pch;
1428 const char* hostp;
1429 char hbuf[NI_MAXHOST];
1431 ary = rb_ary_new();
1432 if (addr->ai_canonname) {
1433 hostp = addr->ai_canonname;
1435 else {
1436 hostp = host_str(host, hbuf, sizeof(hbuf));
1438 rb_ary_push(ary, rb_str_new2(hostp));
1440 if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) {
1441 names = rb_ary_new();
1442 if (h->h_aliases != NULL) {
1443 for (pch = h->h_aliases; *pch; pch++) {
1444 rb_ary_push(names, rb_str_new2(*pch));
1448 else {
1449 names = rb_ary_new2(0);
1451 rb_ary_push(ary, names);
1452 rb_ary_push(ary, INT2NUM(addr->ai_family));
1453 for (ai = addr; ai; ai = ai->ai_next) {
1454 rb_ary_push(ary, (*ipaddr)(ai->ai_addr, ai->ai_addrlen));
1457 return ary;
1460 static VALUE
1461 make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, size_t))
1463 struct hostent_arg arg;
1465 arg.host = host;
1466 arg.addr = addr;
1467 arg.ipaddr = ipaddr;
1468 return rb_ensure(make_hostent_internal, (VALUE)&arg,
1469 RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)addr);
1472 static VALUE
1473 tcp_sockaddr(struct sockaddr *addr, size_t len)
1475 return make_ipaddr(addr);
1478 static VALUE
1479 tcp_s_gethostbyname(VALUE obj, VALUE host)
1481 rb_secure(3);
1482 return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME),
1483 tcp_sockaddr);
1486 static VALUE
1487 tcp_svr_init(int argc, VALUE *argv, VALUE sock)
1489 VALUE arg1, arg2;
1491 if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2)
1492 return init_inetsock(sock, arg1, arg2, Qnil, Qnil, INET_SERVER);
1493 else
1494 return init_inetsock(sock, Qnil, arg1, Qnil, Qnil, INET_SERVER);
1497 static void
1498 make_fd_nonblock(int fd)
1500 int flags;
1501 #ifdef F_GETFL
1502 flags = fcntl(fd, F_GETFL);
1503 if (flags == -1) {
1504 rb_sys_fail(0);
1506 #else
1507 flags = 0;
1508 #endif
1509 flags |= O_NONBLOCK;
1510 if (fcntl(fd, F_SETFL, flags) == -1) {
1511 rb_sys_fail(0);
1515 static VALUE
1516 s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
1518 int fd2;
1520 rb_secure(3);
1521 rb_io_set_nonblock(fptr);
1522 fd2 = accept(fptr->fd, (struct sockaddr*)sockaddr, len);
1523 if (fd2 < 0) {
1524 rb_sys_fail("accept(2)");
1526 make_fd_nonblock(fd2);
1527 return init_sock(rb_obj_alloc(klass), fd2);
1530 struct accept_arg {
1531 int fd;
1532 struct sockaddr *sockaddr;
1533 socklen_t *len;
1536 static VALUE
1537 accept_blocking(void *data)
1539 struct accept_arg *arg = data;
1540 return (VALUE)accept(arg->fd, arg->sockaddr, arg->len);
1543 static VALUE
1544 s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
1546 int fd2;
1547 int retry = 0;
1548 struct accept_arg arg;
1550 rb_secure(3);
1551 arg.fd = fd;
1552 arg.sockaddr = sockaddr;
1553 arg.len = len;
1554 retry:
1555 rb_thread_wait_fd(fd);
1556 fd2 = BLOCKING_REGION(accept_blocking, &arg);
1557 if (fd2 < 0) {
1558 switch (errno) {
1559 case EMFILE:
1560 case ENFILE:
1561 if (retry) break;
1562 rb_gc();
1563 retry = 1;
1564 goto retry;
1565 default:
1566 if (!rb_io_wait_readable(fd)) break;
1567 retry = 0;
1568 goto retry;
1570 rb_sys_fail(0);
1572 if (!klass) return INT2NUM(fd2);
1573 return init_sock(rb_obj_alloc(klass), fd2);
1576 static VALUE
1577 tcp_accept(VALUE sock)
1579 rb_io_t *fptr;
1580 struct sockaddr_storage from;
1581 socklen_t fromlen;
1583 GetOpenFile(sock, fptr);
1584 fromlen = sizeof(from);
1585 return s_accept(rb_cTCPSocket, fptr->fd,
1586 (struct sockaddr*)&from, &fromlen);
1590 * call-seq:
1591 * tcpserver.accept_nonblock => tcpsocket
1593 * Accepts an incoming connection using accept(2) after
1594 * O_NONBLOCK is set for the underlying file descriptor.
1595 * It returns an accepted TCPSocket for the incoming connection.
1597 * === Example
1598 * require 'socket'
1599 * serv = TCPServer.new(2202)
1600 * begin
1601 * sock = serv.accept_nonblock
1602 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
1603 * IO.select([serv])
1604 * retry
1605 * end
1606 * # sock is an accepted socket.
1608 * Refer to Socket#accept for the exceptions that may be thrown if the call
1609 * to TCPServer#accept_nonblock fails.
1611 * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
1612 * including Errno::EWOULDBLOCK.
1614 * === See
1615 * * TCPServer#accept
1616 * * Socket#accept
1618 static VALUE
1619 tcp_accept_nonblock(VALUE sock)
1621 rb_io_t *fptr;
1622 struct sockaddr_storage from;
1623 socklen_t fromlen;
1625 GetOpenFile(sock, fptr);
1626 fromlen = sizeof(from);
1627 return s_accept_nonblock(rb_cTCPSocket, fptr,
1628 (struct sockaddr *)&from, &fromlen);
1631 static VALUE
1632 tcp_sysaccept(VALUE sock)
1634 rb_io_t *fptr;
1635 struct sockaddr_storage from;
1636 socklen_t fromlen;
1638 GetOpenFile(sock, fptr);
1639 fromlen = sizeof(from);
1640 return s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
1643 #ifdef HAVE_SYS_UN_H
1644 struct unixsock_arg {
1645 struct sockaddr_un *sockaddr;
1646 int fd;
1649 static VALUE
1650 unixsock_connect_internal(struct unixsock_arg *arg)
1652 return (VALUE)ruby_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
1653 sizeof(*arg->sockaddr), 0);
1656 static VALUE
1657 init_unixsock(VALUE sock, VALUE path, int server)
1659 struct sockaddr_un sockaddr;
1660 int fd, status;
1661 rb_io_t *fptr;
1663 SafeStringValue(path);
1664 fd = ruby_socket(AF_UNIX, SOCK_STREAM, 0);
1665 if (fd < 0) {
1666 rb_sys_fail("socket(2)");
1669 MEMZERO(&sockaddr, struct sockaddr_un, 1);
1670 sockaddr.sun_family = AF_UNIX;
1671 if (sizeof(sockaddr.sun_path) <= RSTRING_LEN(path)) {
1672 rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)",
1673 (int)sizeof(sockaddr.sun_path)-1);
1675 memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
1677 if (server) {
1678 status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
1680 else {
1681 int prot;
1682 struct unixsock_arg arg;
1683 arg.sockaddr = &sockaddr;
1684 arg.fd = fd;
1685 status = rb_protect((VALUE(*)(VALUE))unixsock_connect_internal,
1686 (VALUE)&arg, &prot);
1687 if (prot) {
1688 close(fd);
1689 rb_jump_tag(prot);
1693 if (status < 0) {
1694 close(fd);
1695 rb_sys_fail(sockaddr.sun_path);
1698 if (server) listen(fd, 5);
1700 init_sock(sock, fd);
1701 if (server) {
1702 GetOpenFile(sock, fptr);
1703 fptr->path = strdup(RSTRING_PTR(path));
1706 return sock;
1708 #endif
1710 static VALUE
1711 ip_addr(VALUE sock)
1713 rb_io_t *fptr;
1714 struct sockaddr_storage addr;
1715 socklen_t len = sizeof addr;
1717 GetOpenFile(sock, fptr);
1719 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
1720 rb_sys_fail("getsockname(2)");
1721 return ipaddr((struct sockaddr*)&addr, fptr->mode & FMODE_NOREVLOOKUP);
1724 static VALUE
1725 ip_peeraddr(VALUE sock)
1727 rb_io_t *fptr;
1728 struct sockaddr_storage addr;
1729 socklen_t len = sizeof addr;
1731 GetOpenFile(sock, fptr);
1733 if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
1734 rb_sys_fail("getpeername(2)");
1735 return ipaddr((struct sockaddr*)&addr, fptr->mode & FMODE_NOREVLOOKUP);
1738 static VALUE
1739 ip_recvfrom(int argc, VALUE *argv, VALUE sock)
1741 return s_recvfrom(sock, argc, argv, RECV_IP);
1744 static VALUE
1745 ip_s_getaddress(VALUE obj, VALUE host)
1747 struct sockaddr_storage addr;
1748 struct addrinfo *res = sock_addrinfo(host, Qnil, SOCK_STREAM, 0);
1750 /* just take the first one */
1751 memcpy(&addr, res->ai_addr, res->ai_addrlen);
1752 freeaddrinfo(res);
1754 return make_ipaddr((struct sockaddr*)&addr);
1757 static VALUE
1758 udp_init(int argc, VALUE *argv, VALUE sock)
1760 VALUE arg;
1761 int socktype = AF_INET;
1762 int fd;
1764 rb_secure(3);
1765 if (rb_scan_args(argc, argv, "01", &arg) == 1) {
1766 socktype = NUM2INT(arg);
1768 fd = ruby_socket(socktype, SOCK_DGRAM, 0);
1769 if (fd < 0) {
1770 rb_sys_fail("socket(2) - udp");
1773 return init_sock(sock, fd);
1776 struct udp_arg
1778 struct addrinfo *res;
1779 int fd;
1782 static VALUE
1783 udp_connect_internal(struct udp_arg *arg)
1785 int fd = arg->fd;
1786 struct addrinfo *res;
1788 for (res = arg->res; res; res = res->ai_next) {
1789 if (ruby_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
1790 return Qtrue;
1793 return Qfalse;
1796 static VALUE
1797 udp_connect(VALUE sock, VALUE host, VALUE port)
1799 rb_io_t *fptr;
1800 struct udp_arg arg;
1801 VALUE ret;
1803 rb_secure(3);
1804 arg.res = sock_addrinfo(host, port, SOCK_DGRAM, 0);
1805 GetOpenFile(sock, fptr);
1806 arg.fd = fptr->fd;
1807 ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
1808 RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)arg.res);
1809 if (!ret) rb_sys_fail("connect(2)");
1810 return INT2FIX(0);
1813 static VALUE
1814 udp_bind(VALUE sock, VALUE host, VALUE port)
1816 rb_io_t *fptr;
1817 struct addrinfo *res0, *res;
1819 rb_secure(3);
1820 res0 = sock_addrinfo(host, port, SOCK_DGRAM, 0);
1821 GetOpenFile(sock, fptr);
1822 for (res = res0; res; res = res->ai_next) {
1823 if (bind(fptr->fd, res->ai_addr, res->ai_addrlen) < 0) {
1824 continue;
1826 freeaddrinfo(res0);
1827 return INT2FIX(0);
1829 freeaddrinfo(res0);
1830 rb_sys_fail("bind(2)");
1831 return INT2FIX(0);
1834 static VALUE
1835 udp_send(int argc, VALUE *argv, VALUE sock)
1837 VALUE flags, host, port;
1838 rb_io_t *fptr;
1839 int n;
1840 struct addrinfo *res0, *res;
1841 struct send_arg arg;
1843 if (argc == 2 || argc == 3) {
1844 return bsock_send(argc, argv, sock);
1846 rb_secure(4);
1847 rb_scan_args(argc, argv, "4", &arg.mesg, &flags, &host, &port);
1849 StringValue(arg.mesg);
1850 res0 = sock_addrinfo(host, port, SOCK_DGRAM, 0);
1851 GetOpenFile(sock, fptr);
1852 arg.fd = fptr->fd;
1853 arg.flags = NUM2INT(flags);
1854 for (res = res0; res; res = res->ai_next) {
1855 retry:
1856 arg.to = res->ai_addr;
1857 arg.tolen = res->ai_addrlen;
1858 rb_thread_fd_writable(arg.fd);
1859 n = (int)BLOCKING_REGION(sendto_blocking, &arg);
1860 if (n >= 0) {
1861 freeaddrinfo(res0);
1862 return INT2FIX(n);
1864 if (rb_io_wait_writable(fptr->fd)) {
1865 goto retry;
1868 freeaddrinfo(res0);
1869 rb_sys_fail("sendto(2)");
1870 return INT2FIX(n);
1874 * call-seq:
1875 * udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr]
1876 * udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr]
1878 * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
1879 * O_NONBLOCK is set for the underlying file descriptor.
1880 * _flags_ is zero or more of the +MSG_+ options.
1881 * The first element of the results, _mesg_, is the data received.
1882 * The second element, _sender_inet_addr_, is an array to represent the sender address.
1884 * When recvfrom(2) returns 0,
1885 * Socket#recvfrom_nonblock returns an empty string as data.
1886 * It means an empty packet.
1888 * === Parameters
1889 * * +maxlen+ - the number of bytes to receive from the socket
1890 * * +flags+ - zero or more of the +MSG_+ options
1892 * === Example
1893 * require 'socket'
1894 * s1 = UDPSocket.new
1895 * s1.bind("127.0.0.1", 0)
1896 * s2 = UDPSocket.new
1897 * s2.bind("127.0.0.1", 0)
1898 * s2.connect(*s1.addr.values_at(3,1))
1899 * s1.connect(*s2.addr.values_at(3,1))
1900 * s1.send "aaa", 0
1901 * IO.select([s2])
1902 * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
1904 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
1905 * to _recvfrom_nonblock_ fails.
1907 * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
1908 * including Errno::EWOULDBLOCK.
1910 * === See
1911 * * Socket#recvfrom
1913 static VALUE
1914 udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
1916 return s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
1919 #ifdef HAVE_SYS_UN_H
1920 static VALUE
1921 unix_init(VALUE sock, VALUE path)
1923 return init_unixsock(sock, path, 0);
1926 static const char*
1927 unixpath(struct sockaddr_un *sockaddr, socklen_t len)
1929 if (sockaddr->sun_path < (char*)sockaddr + len)
1930 return sockaddr->sun_path;
1931 else
1932 return "";
1935 static VALUE
1936 unix_path(VALUE sock)
1938 rb_io_t *fptr;
1940 GetOpenFile(sock, fptr);
1941 if (fptr->path == 0) {
1942 struct sockaddr_un addr;
1943 socklen_t len = sizeof(addr);
1944 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
1945 rb_sys_fail(0);
1946 fptr->path = strdup(unixpath(&addr, len));
1948 return rb_str_new2(fptr->path);
1951 static VALUE
1952 unix_svr_init(VALUE sock, VALUE path)
1954 return init_unixsock(sock, path, 1);
1957 static VALUE
1958 unix_recvfrom(int argc, VALUE *argv, VALUE sock)
1960 return s_recvfrom(sock, argc, argv, RECV_UNIX);
1963 #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS)
1964 #define FD_PASSING_BY_MSG_CONTROL 1
1965 #else
1966 #define FD_PASSING_BY_MSG_CONTROL 0
1967 #endif
1969 #if defined(HAVE_ST_MSG_ACCRIGHTS)
1970 #define FD_PASSING_BY_MSG_ACCRIGHTS 1
1971 #else
1972 #define FD_PASSING_BY_MSG_ACCRIGHTS 0
1973 #endif
1975 struct iomsg_arg {
1976 int fd;
1977 struct msghdr msg;
1980 static VALUE
1981 sendmsg_blocking(void *data)
1983 struct iomsg_arg *arg = data;
1984 return sendmsg(arg->fd, &arg->msg, 0);
1987 static VALUE
1988 unix_send_io(VALUE sock, VALUE val)
1990 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
1991 int fd;
1992 rb_io_t *fptr;
1993 struct iomsg_arg arg;
1994 struct iovec vec[1];
1995 char buf[1];
1997 #if FD_PASSING_BY_MSG_CONTROL
1998 struct {
1999 struct cmsghdr hdr;
2000 char pad[8+sizeof(int)+8];
2001 } cmsg;
2002 #endif
2004 if (rb_obj_is_kind_of(val, rb_cIO)) {
2005 rb_io_t *valfptr;
2006 GetOpenFile(val, valfptr);
2007 fd = valfptr->fd;
2009 else if (FIXNUM_P(val)) {
2010 fd = FIX2INT(val);
2012 else {
2013 rb_raise(rb_eTypeError, "neither IO nor file descriptor");
2016 GetOpenFile(sock, fptr);
2018 arg.msg.msg_name = NULL;
2019 arg.msg.msg_namelen = 0;
2021 /* Linux and Solaris doesn't work if msg_iov is NULL. */
2022 buf[0] = '\0';
2023 vec[0].iov_base = buf;
2024 vec[0].iov_len = 1;
2025 arg.msg.msg_iov = vec;
2026 arg.msg.msg_iovlen = 1;
2028 #if FD_PASSING_BY_MSG_CONTROL
2029 arg.msg.msg_control = (caddr_t)&cmsg;
2030 arg.msg.msg_controllen = CMSG_LEN(sizeof(int));
2031 arg.msg.msg_flags = 0;
2032 MEMZERO((char*)&cmsg, char, sizeof(cmsg));
2033 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
2034 cmsg.hdr.cmsg_level = SOL_SOCKET;
2035 cmsg.hdr.cmsg_type = SCM_RIGHTS;
2036 *(int *)CMSG_DATA(&cmsg.hdr) = fd;
2037 #else
2038 arg.msg.msg_accrights = (caddr_t)&fd;
2039 arg.msg.msg_accrightslen = sizeof(fd);
2040 #endif
2042 arg.fd = fptr->fd;
2043 rb_thread_fd_writable(arg.fd);
2044 if ((int)BLOCKING_REGION(sendmsg_blocking, &arg) == -1)
2045 rb_sys_fail("sendmsg(2)");
2047 return Qnil;
2048 #else
2049 rb_notimplement();
2050 return Qnil; /* not reached */
2051 #endif
2054 static VALUE
2055 recvmsg_blocking(void *data)
2057 struct iomsg_arg *arg = data;
2058 return recvmsg(arg->fd, &arg->msg, 0);
2061 static VALUE
2062 unix_recv_io(int argc, VALUE *argv, VALUE sock)
2064 #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
2065 VALUE klass, mode;
2066 rb_io_t *fptr;
2067 struct iomsg_arg arg;
2068 struct iovec vec[2];
2069 char buf[1];
2071 int fd;
2072 #if FD_PASSING_BY_MSG_CONTROL
2073 struct {
2074 struct cmsghdr hdr;
2075 char pad[8+sizeof(int)+8];
2076 } cmsg;
2077 #endif
2079 rb_scan_args(argc, argv, "02", &klass, &mode);
2080 if (argc == 0)
2081 klass = rb_cIO;
2082 if (argc <= 1)
2083 mode = Qnil;
2085 GetOpenFile(sock, fptr);
2087 arg.msg.msg_name = NULL;
2088 arg.msg.msg_namelen = 0;
2090 vec[0].iov_base = buf;
2091 vec[0].iov_len = sizeof(buf);
2092 arg.msg.msg_iov = vec;
2093 arg.msg.msg_iovlen = 1;
2095 #if FD_PASSING_BY_MSG_CONTROL
2096 arg.msg.msg_control = (caddr_t)&cmsg;
2097 arg.msg.msg_controllen = CMSG_SPACE(sizeof(int));
2098 arg.msg.msg_flags = 0;
2099 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
2100 cmsg.hdr.cmsg_level = SOL_SOCKET;
2101 cmsg.hdr.cmsg_type = SCM_RIGHTS;
2102 *(int *)CMSG_DATA(&cmsg.hdr) = -1;
2103 #else
2104 arg.msg.msg_accrights = (caddr_t)&fd;
2105 arg.msg.msg_accrightslen = sizeof(fd);
2106 fd = -1;
2107 #endif
2109 arg.fd = fptr->fd;
2110 rb_thread_wait_fd(arg.fd);
2111 if ((int)BLOCKING_REGION(recvmsg_blocking, &arg) == -1)
2112 rb_sys_fail("recvmsg(2)");
2114 #if FD_PASSING_BY_MSG_CONTROL
2115 if (arg.msg.msg_controllen != CMSG_SPACE(sizeof(int))) {
2116 rb_raise(rb_eSocket,
2117 "file descriptor was not passed (msg_controllen=%d, %d expected)",
2118 (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
2120 if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
2121 rb_raise(rb_eSocket,
2122 "file descriptor was not passed (cmsg_len=%d, %d expected)",
2123 (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
2125 if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
2126 rb_raise(rb_eSocket,
2127 "file descriptor was not passed (cmsg_level=%d, %d expected)",
2128 cmsg.hdr.cmsg_level, SOL_SOCKET);
2130 if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
2131 rb_raise(rb_eSocket,
2132 "file descriptor was not passed (cmsg_type=%d, %d expected)",
2133 cmsg.hdr.cmsg_type, SCM_RIGHTS);
2135 #else
2136 if (arg.msg.msg_accrightslen != sizeof(fd)) {
2137 rb_raise(rb_eSocket,
2138 "file descriptor was not passed (accrightslen) : %d != %d",
2139 arg.msg.msg_accrightslen, (int)sizeof(fd));
2141 #endif
2143 #if FD_PASSING_BY_MSG_CONTROL
2144 fd = *(int *)CMSG_DATA(&cmsg.hdr);
2145 #endif
2147 if (klass == Qnil)
2148 return INT2FIX(fd);
2149 else {
2150 static ID for_fd = 0;
2151 int ff_argc;
2152 VALUE ff_argv[2];
2153 if (!for_fd)
2154 for_fd = rb_intern("for_fd");
2155 ff_argc = mode == Qnil ? 1 : 2;
2156 ff_argv[0] = INT2FIX(fd);
2157 ff_argv[1] = mode;
2158 return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
2160 #else
2161 rb_notimplement();
2162 return Qnil; /* not reached */
2163 #endif
2166 static VALUE
2167 unix_accept(VALUE sock)
2169 rb_io_t *fptr;
2170 struct sockaddr_un from;
2171 socklen_t fromlen;
2173 GetOpenFile(sock, fptr);
2174 fromlen = sizeof(struct sockaddr_un);
2175 return s_accept(rb_cUNIXSocket, fptr->fd,
2176 (struct sockaddr*)&from, &fromlen);
2180 * call-seq:
2181 * unixserver.accept_nonblock => unixsocket
2183 * Accepts an incoming connection using accept(2) after
2184 * O_NONBLOCK is set for the underlying file descriptor.
2185 * It returns an accepted UNIXSocket for the incoming connection.
2187 * === Example
2188 * require 'socket'
2189 * serv = UNIXServer.new("/tmp/sock")
2190 * begin
2191 * sock = serv.accept_nonblock
2192 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
2193 * IO.select([serv])
2194 * retry
2195 * end
2196 * # sock is an accepted socket.
2198 * Refer to Socket#accept for the exceptions that may be thrown if the call
2199 * to UNIXServer#accept_nonblock fails.
2201 * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
2202 * including Errno::EWOULDBLOCK.
2204 * === See
2205 * * UNIXServer#accept
2206 * * Socket#accept
2208 static VALUE
2209 unix_accept_nonblock(VALUE sock)
2211 rb_io_t *fptr;
2212 struct sockaddr_un from;
2213 socklen_t fromlen;
2215 GetOpenFile(sock, fptr);
2216 fromlen = sizeof(from);
2217 return s_accept_nonblock(rb_cUNIXSocket, fptr,
2218 (struct sockaddr *)&from, &fromlen);
2221 static VALUE
2222 unix_sysaccept(VALUE sock)
2224 rb_io_t *fptr;
2225 struct sockaddr_un from;
2226 socklen_t fromlen;
2228 GetOpenFile(sock, fptr);
2229 fromlen = sizeof(struct sockaddr_un);
2230 return s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
2233 #ifdef HAVE_SYS_UN_H
2234 static VALUE
2235 unixaddr(struct sockaddr_un *sockaddr, socklen_t len)
2237 return rb_assoc_new(rb_str_new2("AF_UNIX"),
2238 rb_str_new2(unixpath(sockaddr, len)));
2240 #endif
2242 static VALUE
2243 unix_addr(VALUE sock)
2245 rb_io_t *fptr;
2246 struct sockaddr_un addr;
2247 socklen_t len = sizeof addr;
2249 GetOpenFile(sock, fptr);
2251 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
2252 rb_sys_fail("getsockname(2)");
2253 return unixaddr(&addr, len);
2256 static VALUE
2257 unix_peeraddr(VALUE sock)
2259 rb_io_t *fptr;
2260 struct sockaddr_un addr;
2261 socklen_t len = sizeof addr;
2263 GetOpenFile(sock, fptr);
2265 if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
2266 rb_sys_fail("getpeername(2)");
2267 return unixaddr(&addr, len);
2269 #endif
2271 static void
2272 setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv)
2274 VALUE tmp;
2275 char *ptr;
2277 tmp = rb_check_string_type(domain);
2278 if (!NIL_P(tmp)) {
2279 domain = tmp;
2280 rb_check_safe_obj(domain);
2281 ptr = RSTRING_PTR(domain);
2282 if (strcmp(ptr, "AF_INET") == 0)
2283 *dv = AF_INET;
2284 #ifdef AF_UNIX
2285 else if (strcmp(ptr, "AF_UNIX") == 0)
2286 *dv = AF_UNIX;
2287 #endif
2288 #ifdef AF_ISO
2289 else if (strcmp(ptr, "AF_ISO") == 0)
2290 *dv = AF_ISO;
2291 #endif
2292 #ifdef AF_NS
2293 else if (strcmp(ptr, "AF_NS") == 0)
2294 *dv = AF_NS;
2295 #endif
2296 #ifdef AF_IMPLINK
2297 else if (strcmp(ptr, "AF_IMPLINK") == 0)
2298 *dv = AF_IMPLINK;
2299 #endif
2300 #ifdef PF_INET
2301 else if (strcmp(ptr, "PF_INET") == 0)
2302 *dv = PF_INET;
2303 #endif
2304 #ifdef PF_UNIX
2305 else if (strcmp(ptr, "PF_UNIX") == 0)
2306 *dv = PF_UNIX;
2307 #endif
2308 #ifdef PF_IMPLINK
2309 else if (strcmp(ptr, "PF_IMPLINK") == 0)
2310 *dv = PF_IMPLINK;
2311 else if (strcmp(ptr, "AF_IMPLINK") == 0)
2312 *dv = AF_IMPLINK;
2313 #endif
2314 #ifdef PF_AX25
2315 else if (strcmp(ptr, "PF_AX25") == 0)
2316 *dv = PF_AX25;
2317 #endif
2318 #ifdef PF_IPX
2319 else if (strcmp(ptr, "PF_IPX") == 0)
2320 *dv = PF_IPX;
2321 #endif
2322 else
2323 rb_raise(rb_eSocket, "unknown socket domain %s", ptr);
2325 else {
2326 *dv = NUM2INT(domain);
2328 tmp = rb_check_string_type(type);
2329 if (!NIL_P(tmp)) {
2330 type = tmp;
2331 rb_check_safe_obj(type);
2332 ptr = RSTRING_PTR(type);
2333 if (strcmp(ptr, "SOCK_STREAM") == 0)
2334 *tv = SOCK_STREAM;
2335 else if (strcmp(ptr, "SOCK_DGRAM") == 0)
2336 *tv = SOCK_DGRAM;
2337 #ifdef SOCK_RAW
2338 else if (strcmp(ptr, "SOCK_RAW") == 0)
2339 *tv = SOCK_RAW;
2340 #endif
2341 #ifdef SOCK_SEQPACKET
2342 else if (strcmp(ptr, "SOCK_SEQPACKET") == 0)
2343 *tv = SOCK_SEQPACKET;
2344 #endif
2345 #ifdef SOCK_RDM
2346 else if (strcmp(ptr, "SOCK_RDM") == 0)
2347 *tv = SOCK_RDM;
2348 #endif
2349 #ifdef SOCK_PACKET
2350 else if (strcmp(ptr, "SOCK_PACKET") == 0)
2351 *tv = SOCK_PACKET;
2352 #endif
2353 else
2354 rb_raise(rb_eSocket, "unknown socket type %s", ptr);
2356 else {
2357 *tv = NUM2INT(type);
2361 static VALUE
2362 sock_initialize(VALUE sock, VALUE domain, VALUE type, VALUE protocol)
2364 int fd;
2365 int d, t;
2367 rb_secure(3);
2368 setup_domain_and_type(domain, &d, type, &t);
2369 fd = ruby_socket(d, t, NUM2INT(protocol));
2370 if (fd < 0) rb_sys_fail("socket(2)");
2372 return init_sock(sock, fd);
2375 static VALUE
2376 sock_s_socketpair(VALUE klass, VALUE domain, VALUE type, VALUE protocol)
2378 #if defined HAVE_SOCKETPAIR
2379 int d, t, p, sp[2];
2380 int ret;
2382 setup_domain_and_type(domain, &d, type, &t);
2383 p = NUM2INT(protocol);
2384 ret = socketpair(d, t, p, sp);
2385 if (ret < 0 && (errno == EMFILE || errno == ENFILE)) {
2386 rb_gc();
2387 ret = socketpair(d, t, p, sp);
2389 if (ret < 0) {
2390 rb_sys_fail("socketpair(2)");
2393 return rb_assoc_new(init_sock(rb_obj_alloc(klass), sp[0]),
2394 init_sock(rb_obj_alloc(klass), sp[1]));
2395 #else
2396 rb_notimplement();
2397 #endif
2400 #ifdef HAVE_SYS_UN_H
2401 static VALUE
2402 unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
2404 VALUE domain, type, protocol;
2405 domain = INT2FIX(PF_UNIX);
2407 rb_scan_args(argc, argv, "02", &type, &protocol);
2408 if (argc == 0)
2409 type = INT2FIX(SOCK_STREAM);
2410 if (argc <= 1)
2411 protocol = INT2FIX(0);
2413 return sock_s_socketpair(klass, domain, type, protocol);
2415 #endif
2418 * call-seq:
2419 * socket.connect(server_sockaddr) => 0
2421 * Requests a connection to be made on the given +server_sockaddr+. Returns 0 if
2422 * successful, otherwise an exception is raised.
2424 * === Parameter
2425 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
2427 * === Example:
2428 * # Pull down Google's web page
2429 * require 'socket'
2430 * include Socket::Constants
2431 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2432 * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
2433 * socket.connect( sockaddr )
2434 * socket.write( "GET / HTTP/1.0\r\n\r\n" )
2435 * results = socket.read
2437 * === Unix-based Exceptions
2438 * On unix-based systems the following system exceptions may be raised if
2439 * the call to _connect_ fails:
2440 * * Errno::EACCES - search permission is denied for a component of the prefix
2441 * path or write access to the +socket+ is denided
2442 * * Errno::EADDRINUSE - the _sockaddr_ is already in use
2443 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
2444 * local machine
2445 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
2446 * the address family of the specified +socket+
2447 * * Errno::EALREADY - a connection is already in progress for the specified
2448 * socket
2449 * * Errno::EBADF - the +socket+ is not a valid file descriptor
2450 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
2451 * refused the connection request
2452 * * Errno::ECONNRESET - the remote host reset the connection request
2453 * * Errno::EFAULT - the _sockaddr_ cannot be accessed
2454 * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably
2455 * because the host is down or a remote router cannot reach it)
2456 * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the
2457 * connection cnanot be immediately established; the connection will be
2458 * established asynchronously
2459 * * Errno::EINTR - the attempt to establish the connection was interrupted by
2460 * delivery of a signal that was caught; the connection will be established
2461 * asynchronously
2462 * * Errno::EISCONN - the specified +socket+ is already connected
2463 * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid
2464 * length for the address family or there is an invalid family in _sockaddr_
2465 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
2466 * PATH_MAX
2467 * * Errno::ENETDOWN - the local interface used to reach the destination is down
2468 * * Errno::ENETUNREACH - no route to the network is present
2469 * * Errno::ENOBUFS - no buffer space is available
2470 * * Errno::ENOSR - there were insufficient STREAMS resources available to
2471 * complete the operation
2472 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
2473 * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected
2474 * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket
2475 * bound to the specified peer address
2476 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
2477 * was made.
2479 * On unix-based systems if the address family of the calling +socket+ is
2480 * AF_UNIX the follow exceptions may be raised if the call to _connect_
2481 * fails:
2482 * * Errno::EIO - an i/o error occured while reading from or writing to the
2483 * file system
2484 * * Errno::ELOOP - too many symbolic links were encountered in translating
2485 * the pathname in _sockaddr_
2486 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
2487 * characters, or an entired pathname exceeded PATH_MAX characters
2488 * * Errno::ENOENT - a component of the pathname does not name an existing file
2489 * or the pathname is an empty string
2490 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
2491 * is not a directory
2493 * === Windows Exceptions
2494 * On Windows systems the following system exceptions may be raised if
2495 * the call to _connect_ fails:
2496 * * Errno::ENETDOWN - the network is down
2497 * * Errno::EADDRINUSE - the socket's local address is already in use
2498 * * Errno::EINTR - the socket was cancelled
2499 * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider
2500 * is still processing a callback function. Or a nonblocking connect call is
2501 * in progress on the +socket+.
2502 * * Errno::EALREADY - see Errno::EINVAL
2503 * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as
2504 * ADDR_ANY TODO check ADDRANY TO INADDR_ANY
2505 * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with
2506 * with this +socket+
2507 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
2508 * refused the connection request
2509 * * Errno::EFAULT - the socket's internal address or address length parameter
2510 * is too small or is not a valid part of the user space address
2511 * * Errno::EINVAL - the +socket+ is a listening socket
2512 * * Errno::EISCONN - the +socket+ is already connected
2513 * * Errno::ENETUNREACH - the network cannot be reached from this host at this time
2514 * * Errno::EHOSTUNREACH - no route to the network is present
2515 * * Errno::ENOBUFS - no buffer space is available
2516 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
2517 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
2518 * was made.
2519 * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the
2520 * connection cannot be completed immediately
2521 * * Errno::EACCES - the attempt to connect the datagram socket to the
2522 * broadcast address failed
2524 * === See
2525 * * connect manual pages on unix-based systems
2526 * * connect function in Microsoft's Winsock functions reference
2528 static VALUE
2529 sock_connect(VALUE sock, VALUE addr)
2531 rb_io_t *fptr;
2532 int fd, n;
2534 StringValue(addr);
2535 addr = rb_str_new4(addr);
2536 GetOpenFile(sock, fptr);
2537 fd = fptr->fd;
2538 n = ruby_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr), 0);
2539 if (n < 0) {
2540 rb_sys_fail("connect(2)");
2543 return INT2FIX(n);
2547 * call-seq:
2548 * socket.connect_nonblock(server_sockaddr) => 0
2550 * Requests a connection to be made on the given +server_sockaddr+ after
2551 * O_NONBLOCK is set for the underlying file descriptor.
2552 * Returns 0 if successful, otherwise an exception is raised.
2554 * === Parameter
2555 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
2557 * === Example:
2558 * # Pull down Google's web page
2559 * require 'socket'
2560 * include Socket::Constants
2561 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2562 * sockaddr = Socket.sockaddr_in(80, 'www.google.com')
2563 * begin
2564 * socket.connect_nonblock(sockaddr)
2565 * rescue Errno::EINPROGRESS
2566 * IO.select(nil, [socket])
2567 * begin
2568 * socket.connect_nonblock(sockaddr)
2569 * rescue Errno::EISCONN
2570 * end
2571 * end
2572 * socket.write("GET / HTTP/1.0\r\n\r\n")
2573 * results = socket.read
2575 * Refer to Socket#connect for the exceptions that may be thrown if the call
2576 * to _connect_nonblock_ fails.
2578 * Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
2579 * including Errno::EINPROGRESS.
2581 * === See
2582 * * Socket#connect
2584 static VALUE
2585 sock_connect_nonblock(VALUE sock, VALUE addr)
2587 rb_io_t *fptr;
2588 int n;
2590 StringValue(addr);
2591 addr = rb_str_new4(addr);
2592 GetOpenFile(sock, fptr);
2593 rb_io_set_nonblock(fptr);
2594 n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr));
2595 if (n < 0) {
2596 rb_sys_fail("connect(2)");
2599 return INT2FIX(n);
2603 * call-seq:
2604 * socket.bind(server_sockaddr) => 0
2606 * Binds to the given +struct+ sockaddr.
2608 * === Parameter
2609 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
2611 * === Example
2612 * require 'socket'
2613 * include Socket::Constants
2614 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2615 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
2616 * socket.bind( sockaddr )
2618 * === Unix-based Exceptions
2619 * On unix-based based systems the following system exceptions may be raised if
2620 * the call to _bind_ fails:
2621 * * Errno::EACCES - the specified _sockaddr_ is protected and the current
2622 * user does not have permission to bind to it
2623 * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use
2624 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
2625 * local machine
2626 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ isnot a valid address for
2627 * the family of the calling +socket+
2628 * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor
2629 * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed
2630 * * Errno::EINVAL - the +socket+ is already bound to an address, and the
2631 * protocol does not support binding to the new _sockaddr_ or the +socket+
2632 * has been shut down.
2633 * * Errno::EINVAL - the address length is not a valid length for the address
2634 * family
2635 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
2636 * PATH_MAX
2637 * * Errno::ENOBUFS - no buffer space is available
2638 * * Errno::ENOSR - there were insufficient STREAMS resources available to
2639 * complete the operation
2640 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
2641 * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support
2642 * binding to an address
2644 * On unix-based based systems if the address family of the calling +socket+ is
2645 * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_
2646 * fails:
2647 * * Errno::EACCES - search permission is denied for a component of the prefix
2648 * path or write access to the +socket+ is denided
2649 * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer
2650 * * Errno::EISDIR - same as Errno::EDESTADDRREQ
2651 * * Errno::EIO - an i/o error occurred
2652 * * Errno::ELOOP - too many symbolic links were encountered in translating
2653 * the pathname in _sockaddr_
2654 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
2655 * characters, or an entired pathname exceeded PATH_MAX characters
2656 * * Errno::ENOENT - a component of the pathname does not name an existing file
2657 * or the pathname is an empty string
2658 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
2659 * is not a directory
2660 * * Errno::EROFS - the name would reside on a read only filesystem
2662 * === Windows Exceptions
2663 * On Windows systems the following system exceptions may be raised if
2664 * the call to _bind_ fails:
2665 * * Errno::ENETDOWN-- the network is down
2666 * * Errno::EACCES - the attempt to connect the datagram socket to the
2667 * broadcast address failed
2668 * * Errno::EADDRINUSE - the socket's local address is already in use
2669 * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this
2670 * computer
2671 * * Errno::EFAULT - the socket's internal address or address length parameter
2672 * is too small or is not a valid part of the user space addressed
2673 * * Errno::EINVAL - the +socket+ is already bound to an address
2674 * * Errno::ENOBUFS - no buffer space is available
2675 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
2677 * === See
2678 * * bind manual pages on unix-based systems
2679 * * bind function in Microsoft's Winsock functions reference
2681 static VALUE
2682 sock_bind(VALUE sock, VALUE addr)
2684 rb_io_t *fptr;
2686 StringValue(addr);
2687 GetOpenFile(sock, fptr);
2688 if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr)) < 0)
2689 rb_sys_fail("bind(2)");
2691 return INT2FIX(0);
2695 * call-seq:
2696 * socket.listen( int ) => 0
2698 * Listens for connections, using the specified +int+ as the backlog. A call
2699 * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or
2700 * SOCK_SEQPACKET.
2702 * === Parameter
2703 * * +backlog+ - the maximum length of the queue for pending connections.
2705 * === Example 1
2706 * require 'socket'
2707 * include Socket::Constants
2708 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2709 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
2710 * socket.bind( sockaddr )
2711 * socket.listen( 5 )
2713 * === Example 2 (listening on an arbitary port, unix-based systems only):
2714 * require 'socket'
2715 * include Socket::Constants
2716 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2717 * socket.listen( 1 )
2719 * === Unix-based Exceptions
2720 * On unix based systems the above will work because a new +sockaddr+ struct
2721 * is created on the address ADDR_ANY, for an arbitrary port number as handed
2722 * off by the kernel. It will not work on Windows, because Windows requires that
2723 * the +socket+ is bound by calling _bind_ before it can _listen_.
2725 * If the _backlog_ amount exceeds the implementation-dependent maximum
2726 * queue length, the implementation's maximum queue length will be used.
2728 * On unix-based based systems the following system exceptions may be raised if the
2729 * call to _listen_ fails:
2730 * * Errno::EBADF - the _socket_ argument is not a valid file descriptor
2731 * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and
2732 * the protocol does not support listening on an unbound socket
2733 * * Errno::EINVAL - the _socket_ is already connected
2734 * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket
2735 * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen
2736 * * Errno::EACCES - the calling process does not have approriate privileges
2737 * * Errno::EINVAL - the _socket_ has been shut down
2738 * * Errno::ENOBUFS - insufficient resources are available in the system to
2739 * complete the call
2741 * === Windows Exceptions
2742 * On Windows systems the following system exceptions may be raised if
2743 * the call to _listen_ fails:
2744 * * Errno::ENETDOWN - the network is down
2745 * * Errno::EADDRINUSE - the socket's local address is already in use. This
2746 * usually occurs during the execution of _bind_ but could be delayed
2747 * if the call to _bind_ was to a partially wildcard address (involving
2748 * ADDR_ANY) and if a specific address needs to be commmitted at the
2749 * time of the call to _listen_
2750 * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the
2751 * service provider is still processing a callback function
2752 * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_.
2753 * * Errno::EISCONN - the +socket+ is already connected
2754 * * Errno::EMFILE - no more socket descriptors are available
2755 * * Errno::ENOBUFS - no buffer space is available
2756 * * Errno::ENOTSOC - +socket+ is not a socket
2757 * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports
2758 * the _listen_ method
2760 * === See
2761 * * listen manual pages on unix-based systems
2762 * * listen function in Microsoft's Winsock functions reference
2764 static VALUE
2765 sock_listen(VALUE sock, VALUE log)
2767 rb_io_t *fptr;
2768 int backlog;
2770 rb_secure(4);
2771 backlog = NUM2INT(log);
2772 GetOpenFile(sock, fptr);
2773 if (listen(fptr->fd, backlog) < 0)
2774 rb_sys_fail("listen(2)");
2776 return INT2FIX(0);
2780 * call-seq:
2781 * socket.recvfrom(maxlen) => [mesg, sender_sockaddr]
2782 * socket.recvfrom(maxlen, flags) => [mesg, sender_sockaddr]
2784 * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more
2785 * of the +MSG_+ options. The first element of the results, _mesg_, is the data
2786 * received. The second element, _sender_sockaddr_, contains protocol-specific information
2787 * on the sender.
2789 * === Parameters
2790 * * +maxlen+ - the number of bytes to receive from the socket
2791 * * +flags+ - zero or more of the +MSG_+ options
2793 * === Example
2794 * # In one file, start this first
2795 * require 'socket'
2796 * include Socket::Constants
2797 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2798 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
2799 * socket.bind( sockaddr )
2800 * socket.listen( 5 )
2801 * client, client_sockaddr = socket.accept
2802 * data = client.recvfrom( 20 )[0].chomp
2803 * puts "I only received 20 bytes '#{data}'"
2804 * sleep 1
2805 * socket.close
2807 * # In another file, start this second
2808 * require 'socket'
2809 * include Socket::Constants
2810 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
2811 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
2812 * socket.connect( sockaddr )
2813 * socket.puts "Watch this get cut short!"
2814 * socket.close
2816 * === Unix-based Exceptions
2817 * On unix-based based systems the following system exceptions may be raised if the
2818 * call to _recvfrom_ fails:
2819 * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no
2820 * data is waiting to be received; or MSG_OOB is set and no out-of-band data
2821 * is available and either the +socket+ file descriptor is marked as
2822 * O_NONBLOCK or the +socket+ does not support blocking to wait for
2823 * out-of-band-data
2824 * * Errno::EWOULDBLOCK - see Errno::EAGAIN
2825 * * Errno::EBADF - the +socket+ is not a valid file descriptor
2826 * * Errno::ECONNRESET - a connection was forcibly closed by a peer
2827 * * Errno::EFAULT - the socket's internal buffer, address or address length
2828 * cannot be accessed or written
2829 * * Errno::EINTR - a signal interupted _recvfrom_ before any data was available
2830 * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available
2831 * * Errno::EIO - an i/o error occurred while reading from or writing to the
2832 * filesystem
2833 * * Errno::ENOBUFS - insufficient resources were available in the system to
2834 * perform the operation
2835 * * Errno::ENOMEM - insufficient memory was available to fulfill the request
2836 * * Errno::ENOSR - there were insufficient STREAMS resources available to
2837 * complete the operation
2838 * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that
2839 * is not connected
2840 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
2841 * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type
2842 * * Errno::ETIMEDOUT - the connection timed out during connection establishment
2843 * or due to a transmission timeout on an active connection
2845 * === Windows Exceptions
2846 * On Windows systems the following system exceptions may be raised if
2847 * the call to _recvfrom_ fails:
2848 * * Errno::ENETDOWN - the network is down
2849 * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not
2850 * part of the user address space, or the internal fromlen parameter is
2851 * too small to accomodate the peer address
2852 * * Errno::EINTR - the (blocking) call was cancelled by an internal call to
2853 * the WinSock function WSACancelBlockingCall
2854 * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or
2855 * the service provider is still processing a callback function
2856 * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an
2857 * unknown flag was specified, or MSG_OOB was specified for a socket with
2858 * SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal
2859 * len parameter on +socket+ was zero or negative
2860 * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is
2861 * not permitted with a connected socket on a socket that is connetion
2862 * oriented or connectionless.
2863 * * Errno::ENETRESET - the connection has been broken due to the keep-alive
2864 * activity detecting a failure while the operation was in progress.
2865 * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style
2866 * such as type SOCK_STREAM. OOB data is not supported in the communication
2867 * domain associated with +socket+, or +socket+ is unidirectional and
2868 * supports only send operations
2869 * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to
2870 * call _recvfrom_ on a socket after _shutdown_ has been invoked.
2871 * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a call to
2872 * _recvfrom_ would block.
2873 * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer
2874 * and was truncated.
2875 * * Errno::ETIMEDOUT - the connection has been dropped, because of a network
2876 * failure or because the system on the other end went down without
2877 * notice
2878 * * Errno::ECONNRESET - the virtual circuit was reset by the remote side
2879 * executing a hard or abortive close. The application should close the
2880 * socket; it is no longer usable. On a UDP-datagram socket this error
2881 * indicates a previous send operation resulted in an ICMP Port Unreachable
2882 * message.
2884 static VALUE
2885 sock_recvfrom(int argc, VALUE *argv, VALUE sock)
2887 return s_recvfrom(sock, argc, argv, RECV_SOCKET);
2891 * call-seq:
2892 * socket.recvfrom_nonblock(maxlen) => [mesg, sender_sockaddr]
2893 * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_sockaddr]
2895 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
2896 * O_NONBLOCK is set for the underlying file descriptor.
2897 * _flags_ is zero or more of the +MSG_+ options.
2898 * The first element of the results, _mesg_, is the data received.
2899 * The second element, _sender_sockaddr_, contains protocol-specific information
2900 * on the sender.
2902 * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
2903 * an empty string as data.
2904 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
2906 * === Parameters
2907 * * +maxlen+ - the number of bytes to receive from the socket
2908 * * +flags+ - zero or more of the +MSG_+ options
2910 * === Example
2911 * # In one file, start this first
2912 * require 'socket'
2913 * include Socket::Constants
2914 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2915 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
2916 * socket.bind(sockaddr)
2917 * socket.listen(5)
2918 * client, client_sockaddr = socket.accept
2919 * begin
2920 * pair = client.recvfrom_nonblock(20)
2921 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK
2922 * IO.select([client])
2923 * retry
2924 * end
2925 * data = pair[0].chomp
2926 * puts "I only received 20 bytes '#{data}'"
2927 * sleep 1
2928 * socket.close
2930 * # In another file, start this second
2931 * require 'socket'
2932 * include Socket::Constants
2933 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2934 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
2935 * socket.connect(sockaddr)
2936 * socket.puts "Watch this get cut short!"
2937 * socket.close
2939 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
2940 * to _recvfrom_nonblock_ fails.
2942 * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
2943 * including Errno::EWOULDBLOCK.
2945 * === See
2946 * * Socket#recvfrom
2948 static VALUE
2949 sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
2951 return s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
2954 static VALUE
2955 sock_accept(VALUE sock)
2957 rb_io_t *fptr;
2958 VALUE sock2;
2959 char buf[1024];
2960 socklen_t len = sizeof buf;
2962 GetOpenFile(sock, fptr);
2963 sock2 = s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)buf,&len);
2965 return rb_assoc_new(sock2, rb_str_new(buf, len));
2969 * call-seq:
2970 * socket.accept_nonblock => [client_socket, client_sockaddr]
2972 * Accepts an incoming connection using accept(2) after
2973 * O_NONBLOCK is set for the underlying file descriptor.
2974 * It returns an array containg the accpeted socket
2975 * for the incoming connection, _client_socket_,
2976 * and a string that contains the +struct+ sockaddr information
2977 * about the caller, _client_sockaddr_.
2979 * === Example
2980 * # In one script, start this first
2981 * require 'socket'
2982 * include Socket::Constants
2983 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2984 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
2985 * socket.bind(sockaddr)
2986 * socket.listen(5)
2987 * begin
2988 * client_socket, client_sockaddr = socket.accept_nonblock
2989 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
2990 * IO.select([socket])
2991 * retry
2992 * end
2993 * puts "The client said, '#{client_socket.readline.chomp}'"
2994 * client_socket.puts "Hello from script one!"
2995 * socket.close
2997 * # In another script, start this second
2998 * require 'socket'
2999 * include Socket::Constants
3000 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
3001 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
3002 * socket.connect(sockaddr)
3003 * socket.puts "Hello from script 2."
3004 * puts "The server said, '#{socket.readline.chomp}'"
3005 * socket.close
3007 * Refer to Socket#accept for the exceptions that may be thrown if the call
3008 * to _accept_nonblock_ fails.
3010 * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
3011 * including Errno::EWOULDBLOCK.
3013 * === See
3014 * * Socket#accept
3016 static VALUE
3017 sock_accept_nonblock(VALUE sock)
3019 rb_io_t *fptr;
3020 VALUE sock2;
3021 char buf[1024];
3022 socklen_t len = sizeof buf;
3024 GetOpenFile(sock, fptr);
3025 sock2 = s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)buf, &len);
3026 return rb_assoc_new(sock2, rb_str_new(buf, len));
3030 * call-seq:
3031 * socket.sysaccept => [client_socket_fd, client_sockaddr]
3033 * Accepts an incoming connection returnings an array containg the (integer)
3034 * file descriptor for the incoming connection, _client_socket_fd_,
3035 * and a string that contains the +struct+ sockaddr information
3036 * about the caller, _client_sockaddr_.
3038 * === Example
3039 * # In one script, start this first
3040 * require 'socket'
3041 * include Socket::Constants
3042 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
3043 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
3044 * socket.bind( sockaddr )
3045 * socket.listen( 5 )
3046 * client_fd, client_sockaddr = socket.sysaccept
3047 * client_socket = Socket.for_fd( client_fd )
3048 * puts "The client said, '#{client_socket.readline.chomp}'"
3049 * client_socket.puts "Hello from script one!"
3050 * socket.close
3052 * # In another script, start this second
3053 * require 'socket'
3054 * include Socket::Constants
3055 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
3056 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
3057 * socket.connect( sockaddr )
3058 * socket.puts "Hello from script 2."
3059 * puts "The server said, '#{socket.readline.chomp}'"
3060 * socket.close
3062 * Refer to Socket#accept for the exceptions that may be thrown if the call
3063 * to _sysaccept_ fails.
3065 * === See
3066 * * Socket#accept
3068 static VALUE
3069 sock_sysaccept(VALUE sock)
3071 rb_io_t *fptr;
3072 VALUE sock2;
3073 char buf[1024];
3074 socklen_t len = sizeof buf;
3076 GetOpenFile(sock, fptr);
3077 sock2 = s_accept(0,fptr->fd,(struct sockaddr*)buf,&len);
3079 return rb_assoc_new(sock2, rb_str_new(buf, len));
3082 #ifdef HAVE_GETHOSTNAME
3083 static VALUE
3084 sock_gethostname(VALUE obj)
3086 char buf[1024];
3088 rb_secure(3);
3089 if (gethostname(buf, (int)sizeof buf - 1) < 0)
3090 rb_sys_fail("gethostname");
3092 buf[sizeof buf - 1] = '\0';
3093 return rb_str_new2(buf);
3095 #else
3096 #ifdef HAVE_UNAME
3098 #include <sys/utsname.h>
3100 static VALUE
3101 sock_gethostname(VALUE obj)
3103 struct utsname un;
3105 rb_secure(3);
3106 uname(&un);
3107 return rb_str_new2(un.nodename);
3109 #else
3110 static VALUE
3111 sock_gethostname(VALUE obj)
3113 rb_notimplement();
3115 #endif
3116 #endif
3118 static VALUE
3119 make_addrinfo(struct addrinfo *res0)
3121 VALUE base, ary;
3122 struct addrinfo *res;
3124 if (res0 == NULL) {
3125 rb_raise(rb_eSocket, "host not found");
3127 base = rb_ary_new();
3128 for (res = res0; res; res = res->ai_next) {
3129 ary = ipaddr(res->ai_addr, do_not_reverse_lookup);
3130 if (res->ai_canonname) {
3131 RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
3133 rb_ary_push(ary, INT2FIX(res->ai_family));
3134 rb_ary_push(ary, INT2FIX(res->ai_socktype));
3135 rb_ary_push(ary, INT2FIX(res->ai_protocol));
3136 rb_ary_push(base, ary);
3138 return base;
3141 static VALUE
3142 sock_sockaddr(struct sockaddr *addr, size_t len)
3144 char *ptr;
3146 switch (addr->sa_family) {
3147 case AF_INET:
3148 ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
3149 len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
3150 break;
3151 #ifdef INET6
3152 case AF_INET6:
3153 ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
3154 len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
3155 break;
3156 #endif
3157 default:
3158 rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family);
3159 break;
3161 return rb_str_new(ptr, len);
3164 static VALUE
3165 sock_s_gethostbyname(VALUE obj, VALUE host)
3167 rb_secure(3);
3168 return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
3171 static VALUE
3172 sock_s_gethostbyaddr(int argc, VALUE *argv)
3174 VALUE addr, type;
3175 struct hostent *h;
3176 struct sockaddr *sa;
3177 char **pch;
3178 VALUE ary, names;
3179 int t = AF_INET;
3181 rb_scan_args(argc, argv, "11", &addr, &type);
3182 sa = (struct sockaddr*)StringValuePtr(addr);
3183 if (!NIL_P(type)) {
3184 t = NUM2INT(type);
3186 #ifdef INET6
3187 else if (RSTRING_LEN(addr) == 16) {
3188 t = AF_INET6;
3190 #endif
3191 h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LEN(addr), t);
3192 if (h == NULL) {
3193 #ifdef HAVE_HSTRERROR
3194 extern int h_errno;
3195 rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
3196 #else
3197 rb_raise(rb_eSocket, "host not found");
3198 #endif
3200 ary = rb_ary_new();
3201 rb_ary_push(ary, rb_str_new2(h->h_name));
3202 names = rb_ary_new();
3203 rb_ary_push(ary, names);
3204 if (h->h_aliases != NULL) {
3205 for (pch = h->h_aliases; *pch; pch++) {
3206 rb_ary_push(names, rb_str_new2(*pch));
3209 rb_ary_push(ary, INT2NUM(h->h_addrtype));
3210 #ifdef h_addr
3211 for (pch = h->h_addr_list; *pch; pch++) {
3212 rb_ary_push(ary, rb_str_new(*pch, h->h_length));
3214 #else
3215 rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
3216 #endif
3218 return ary;
3221 static VALUE
3222 sock_s_getservbyname(int argc, VALUE *argv)
3224 VALUE service, proto;
3225 struct servent *sp;
3226 int port;
3228 rb_scan_args(argc, argv, "11", &service, &proto);
3229 if (NIL_P(proto)) proto = rb_str_new2("tcp");
3230 StringValue(service);
3231 StringValue(proto);
3233 sp = getservbyname(StringValueCStr(service), StringValueCStr(proto));
3234 if (sp) {
3235 port = ntohs(sp->s_port);
3237 else {
3238 char *s = RSTRING_PTR(service);
3239 char *end;
3241 port = STRTOUL(s, &end, 0);
3242 if (*end != '\0') {
3243 rb_raise(rb_eSocket, "no such service %s/%s", s, RSTRING_PTR(proto));
3246 return INT2FIX(port);
3249 static VALUE
3250 sock_s_getservbyport(int argc, VALUE *argv)
3252 VALUE port, proto;
3253 struct servent *sp;
3255 rb_scan_args(argc, argv, "11", &port, &proto);
3256 if (NIL_P(proto)) proto = rb_str_new2("tcp");
3257 StringValue(proto);
3259 sp = getservbyport(NUM2INT(port), StringValueCStr(proto));
3260 if (!sp) {
3261 rb_raise(rb_eSocket, "no such service for port %d/%s", NUM2INT(port), RSTRING_PTR(proto));
3263 return rb_tainted_str_new2(sp->s_name);
3266 static VALUE
3267 sock_s_getaddrinfo(int argc, VALUE *argv)
3269 VALUE host, port, family, socktype, protocol, flags, ret;
3270 char hbuf[1024], pbuf[1024];
3271 char *hptr, *pptr, *ap;
3272 struct addrinfo hints, *res;
3273 int error;
3275 host = port = family = socktype = protocol = flags = Qnil;
3276 rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol, &flags);
3277 if (NIL_P(host)) {
3278 hptr = NULL;
3280 else {
3281 strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
3282 hbuf[sizeof(hbuf) - 1] = '\0';
3283 hptr = hbuf;
3285 if (NIL_P(port)) {
3286 pptr = NULL;
3288 else if (FIXNUM_P(port)) {
3289 snprintf(pbuf, sizeof(pbuf), "%ld", FIX2LONG(port));
3290 pptr = pbuf;
3292 else {
3293 strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
3294 pbuf[sizeof(pbuf) - 1] = '\0';
3295 pptr = pbuf;
3298 MEMZERO(&hints, struct addrinfo, 1);
3299 if (NIL_P(family)) {
3300 hints.ai_family = PF_UNSPEC;
3302 else if (FIXNUM_P(family)) {
3303 hints.ai_family = FIX2INT(family);
3305 else if ((ap = StringValuePtr(family)) != 0) {
3306 if (strcmp(ap, "AF_INET") == 0) {
3307 hints.ai_family = PF_INET;
3309 #ifdef INET6
3310 else if (strcmp(ap, "AF_INET6") == 0) {
3311 hints.ai_family = PF_INET6;
3313 #endif
3316 if (!NIL_P(socktype)) {
3317 hints.ai_socktype = NUM2INT(socktype);
3319 if (!NIL_P(protocol)) {
3320 hints.ai_protocol = NUM2INT(protocol);
3322 if (!NIL_P(flags)) {
3323 hints.ai_flags = NUM2INT(flags);
3325 error = getaddrinfo(hptr, pptr, &hints, &res);
3326 if (error) {
3327 raise_socket_error("getaddrinfo", error);
3330 ret = make_addrinfo(res);
3331 freeaddrinfo(res);
3332 return ret;
3335 static VALUE
3336 sock_s_getnameinfo(int argc, VALUE *argv)
3338 VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
3339 char *hptr, *pptr;
3340 char hbuf[1024], pbuf[1024];
3341 int fl;
3342 struct addrinfo hints, *res = NULL, *r;
3343 int error;
3344 struct sockaddr_storage ss;
3345 struct sockaddr *sap;
3346 char *ap;
3348 sa = flags = Qnil;
3349 rb_scan_args(argc, argv, "11", &sa, &flags);
3351 fl = 0;
3352 if (!NIL_P(flags)) {
3353 fl = NUM2INT(flags);
3355 tmp = rb_check_string_type(sa);
3356 if (!NIL_P(tmp)) {
3357 sa = tmp;
3358 if (sizeof(ss) < RSTRING_LEN(sa)) {
3359 rb_raise(rb_eTypeError, "sockaddr length too big");
3361 memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
3362 if (RSTRING_LEN(sa) != SA_LEN((struct sockaddr*)&ss)) {
3363 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
3365 sap = (struct sockaddr*)&ss;
3366 goto call_nameinfo;
3368 tmp = rb_check_array_type(sa);
3369 if (!NIL_P(tmp)) {
3370 sa = tmp;
3371 MEMZERO(&hints, struct addrinfo, 1);
3372 if (RARRAY_LEN(sa) == 3) {
3373 af = RARRAY_PTR(sa)[0];
3374 port = RARRAY_PTR(sa)[1];
3375 host = RARRAY_PTR(sa)[2];
3377 else if (RARRAY_LEN(sa) >= 4) {
3378 af = RARRAY_PTR(sa)[0];
3379 port = RARRAY_PTR(sa)[1];
3380 host = RARRAY_PTR(sa)[3];
3381 if (NIL_P(host)) {
3382 host = RARRAY_PTR(sa)[2];
3384 else {
3386 * 4th element holds numeric form, don't resolve.
3387 * see ipaddr().
3389 #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
3390 hints.ai_flags |= AI_NUMERICHOST;
3391 #endif
3394 else {
3395 rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
3396 RARRAY_LEN(sa));
3398 /* host */
3399 if (NIL_P(host)) {
3400 hptr = NULL;
3402 else {
3403 strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
3404 hbuf[sizeof(hbuf) - 1] = '\0';
3405 hptr = hbuf;
3407 /* port */
3408 if (NIL_P(port)) {
3409 strcpy(pbuf, "0");
3410 pptr = NULL;
3412 else if (FIXNUM_P(port)) {
3413 snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
3414 pptr = pbuf;
3416 else {
3417 strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
3418 pbuf[sizeof(pbuf) - 1] = '\0';
3419 pptr = pbuf;
3421 hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
3422 /* af */
3423 if (NIL_P(af)) {
3424 hints.ai_family = PF_UNSPEC;
3426 else if (FIXNUM_P(af)) {
3427 hints.ai_family = FIX2INT(af);
3429 else if ((ap = StringValuePtr(af)) != 0) {
3430 if (strcmp(ap, "AF_INET") == 0) {
3431 hints.ai_family = PF_INET;
3433 #ifdef INET6
3434 else if (strcmp(ap, "AF_INET6") == 0) {
3435 hints.ai_family = PF_INET6;
3437 #endif
3439 error = getaddrinfo(hptr, pptr, &hints, &res);
3440 if (error) goto error_exit_addr;
3441 sap = res->ai_addr;
3443 else {
3444 rb_raise(rb_eTypeError, "expecting String or Array");
3447 call_nameinfo:
3448 error = getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
3449 pbuf, sizeof(pbuf), fl);
3450 if (error) goto error_exit_name;
3451 if (res) {
3452 for (r = res->ai_next; r; r = r->ai_next) {
3453 char hbuf2[1024], pbuf2[1024];
3455 sap = r->ai_addr;
3456 error = getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2),
3457 pbuf2, sizeof(pbuf2), fl);
3458 if (error) goto error_exit_name;
3459 if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
3460 freeaddrinfo(res);
3461 rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
3464 freeaddrinfo(res);
3466 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
3468 error_exit_addr:
3469 if (res) freeaddrinfo(res);
3470 raise_socket_error("getaddrinfo", error);
3472 error_exit_name:
3473 if (res) freeaddrinfo(res);
3474 raise_socket_error("getnameinfo", error);
3477 static VALUE
3478 sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
3480 struct addrinfo *res = sock_addrinfo(host, port, 0, 0);
3481 VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
3483 freeaddrinfo(res);
3484 OBJ_INFECT(addr, port);
3485 OBJ_INFECT(addr, host);
3487 return addr;
3490 static VALUE
3491 sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
3493 struct sockaddr_in * sockaddr;
3494 VALUE host;
3496 sockaddr = (struct sockaddr_in*)StringValuePtr(addr);
3497 if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
3498 #ifdef INET6
3499 && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
3500 #endif
3502 #ifdef INET6
3503 rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
3504 #else
3505 rb_raise(rb_eArgError, "not an AF_INET sockaddr");
3506 #endif
3508 host = make_ipaddr((struct sockaddr*)sockaddr);
3509 OBJ_INFECT(host, addr);
3510 return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
3513 #ifdef HAVE_SYS_UN_H
3514 static VALUE
3515 sock_s_pack_sockaddr_un(VALUE self, VALUE path)
3517 struct sockaddr_un sockaddr;
3518 char *sun_path;
3519 VALUE addr;
3521 MEMZERO(&sockaddr, struct sockaddr_un, 1);
3522 sockaddr.sun_family = AF_UNIX;
3523 sun_path = StringValueCStr(path);
3524 if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) {
3525 rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)",
3526 (int)sizeof(sockaddr.sun_path)-1);
3528 strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1);
3529 addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr));
3530 OBJ_INFECT(addr, path);
3532 return addr;
3535 static VALUE
3536 sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
3538 struct sockaddr_un * sockaddr;
3539 const char *sun_path;
3540 VALUE path;
3542 sockaddr = (struct sockaddr_un*)StringValuePtr(addr);
3543 if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
3544 rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
3546 if (sizeof(struct sockaddr_un) < RSTRING_LEN(addr)) {
3547 rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
3548 RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
3550 sun_path = unixpath(sockaddr, RSTRING_LEN(addr));
3551 if (sizeof(struct sockaddr_un) == RSTRING_LEN(addr) &&
3552 sun_path == sockaddr->sun_path &&
3553 sun_path + strlen(sun_path) == RSTRING_PTR(addr) + RSTRING_LEN(addr)) {
3554 rb_raise(rb_eArgError, "sockaddr_un.sun_path not NUL terminated");
3556 path = rb_str_new2(sun_path);
3557 OBJ_INFECT(path, addr);
3558 return path;
3560 #endif
3562 static VALUE mConst;
3564 static void
3565 sock_define_const(const char *name, int value)
3567 rb_define_const(rb_cSocket, name, INT2FIX(value));
3568 rb_define_const(mConst, name, INT2FIX(value));
3572 * Class +Socket+ provides access to the underlying operating system
3573 * socket implementations. It can be used to provide more operating system
3574 * specific functionality than the protocol-specific socket classes but at the
3575 * expense of greater complexity. In particular, the class handles addresses
3576 * using +struct+ sockaddr structures packed into Ruby strings, which can be
3577 * a joy to manipulate.
3579 * === Exception Handling
3580 * Ruby's implementation of +Socket+ causes an exception to be raised
3581 * based on the error generated by the system dependent implementation.
3582 * This is why the methods are documented in a way that isolate
3583 * Unix-based system exceptions from Windows based exceptions. If more
3584 * information on particular exception is needed please refer to the
3585 * Unix manual pages or the Windows WinSock reference.
3588 * === Documentation by
3589 * * Zach Dennis
3590 * * Sam Roberts
3591 * * <em>Programming Ruby</em> from The Pragmatic Bookshelf.
3593 * Much material in this documentation is taken with permission from
3594 * <em>Programming Ruby</em> from The Pragmatic Bookshelf.
3596 void
3597 Init_socket()
3599 rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
3601 rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO);
3602 rb_undef_method(rb_cBasicSocket, "initialize");
3604 rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup",
3605 bsock_do_not_rev_lookup, 0);
3606 rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=",
3607 bsock_do_not_rev_lookup_set, 1);
3608 rb_define_singleton_method(rb_cBasicSocket, "for_fd", bsock_s_for_fd, 1);
3610 rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0);
3611 rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0);
3612 rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1);
3613 rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, 3);
3614 rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2);
3615 rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0);
3616 rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
3617 rb_define_method(rb_cBasicSocket, "send", bsock_send, -1);
3618 rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
3619 rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
3620 rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
3621 rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
3623 rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
3624 rb_define_method(rb_cIPSocket, "addr", ip_addr, 0);
3625 rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, 0);
3626 rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
3627 rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1);
3629 rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket);
3630 rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1);
3631 rb_define_method(rb_cTCPSocket, "initialize", tcp_init, -1);
3633 #ifdef SOCKS
3634 rb_cSOCKSSocket = rb_define_class("SOCKSSocket", rb_cTCPSocket);
3635 rb_define_method(rb_cSOCKSSocket, "initialize", socks_init, 2);
3636 #ifdef SOCKS5
3637 rb_define_method(rb_cSOCKSSocket, "close", socks_s_close, 0);
3638 #endif
3639 #endif
3641 rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
3642 rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
3643 rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0);
3644 rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
3645 rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
3646 rb_define_method(rb_cTCPServer, "listen", sock_listen, 1);
3648 rb_cUDPSocket = rb_define_class("UDPSocket", rb_cIPSocket);
3649 rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1);
3650 rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
3651 rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
3652 rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
3653 rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
3655 #ifdef HAVE_SYS_UN_H
3656 rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
3657 rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1);
3658 rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
3659 rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
3660 rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
3661 rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
3662 rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
3663 rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
3664 rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1);
3665 rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1);
3667 rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
3668 rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1);
3669 rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
3670 rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, 0);
3671 rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
3672 rb_define_method(rb_cUNIXServer, "listen", sock_listen, 1);
3673 #endif
3675 rb_cSocket = rb_define_class("Socket", rb_cBasicSocket);
3677 rb_define_method(rb_cSocket, "initialize", sock_initialize, 3);
3678 rb_define_method(rb_cSocket, "connect", sock_connect, 1);
3679 rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1);
3680 rb_define_method(rb_cSocket, "bind", sock_bind, 1);
3681 rb_define_method(rb_cSocket, "listen", sock_listen, 1);
3682 rb_define_method(rb_cSocket, "accept", sock_accept, 0);
3683 rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0);
3684 rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
3686 rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
3687 rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
3689 rb_define_singleton_method(rb_cSocket, "socketpair", sock_s_socketpair, 3);
3690 rb_define_singleton_method(rb_cSocket, "pair", sock_s_socketpair, 3);
3691 rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0);
3692 rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1);
3693 rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1);
3694 rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyname, -1);
3695 rb_define_singleton_method(rb_cSocket, "getservbyport", sock_s_getservbyport, -1);
3696 rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1);
3697 rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1);
3698 rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2);
3699 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2);
3700 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1);
3701 #ifdef HAVE_SYS_UN_H
3702 rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1);
3703 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1);
3704 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1);
3705 #endif
3707 /* constants */
3708 mConst = rb_define_module_under(rb_cSocket, "Constants");
3709 #include "constants.h"
3710 #ifdef INET6 /* IPv6 is not supported although AF_INET6 is defined on bcc32/mingw */
3711 sock_define_const("AF_INET6", AF_INET6);
3712 sock_define_const("PF_INET6", PF_INET6);
3713 #endif