1 /************************************************
6 created at: Thu Mar 31 12:21:29 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 ************************************************/
12 #include "ruby/ruby.h"
14 #include "ruby/signal.h"
15 #include "ruby/util.h"
17 #include <sys/types.h>
32 #if defined(__BEOS__) && !defined(__HAIKU__)
33 # include <net/socket.h>
35 # include <sys/socket.h>
37 #include <netinet/in.h>
38 #ifdef HAVE_NETINET_IN_SYSTM_H
39 # include <netinet/in_systm.h>
41 #ifdef HAVE_NETINET_TCP_H
42 # include <netinet/tcp.h>
44 #ifdef HAVE_NETINET_UDP_H
45 # include <netinet/udp.h>
47 #ifdef HAVE_ARPA_INET_H
48 # include <arpa/inet.h>
57 #if defined(HAVE_FCNTL)
58 #ifdef HAVE_SYS_SELECT_H
59 #include <sys/select.h>
61 #ifdef HAVE_SYS_TYPES_H
62 #include <sys/types.h>
64 #ifdef HAVE_SYS_TIME_H
72 #define EWOULDBLOCK EAGAIN
74 #ifndef HAVE_GETADDRINFO
75 # include "addrinfo.h"
79 static int do_not_reverse_lookup
= 0;
80 #define FMODE_NOREVLOOKUP 0x100
82 VALUE rb_cBasicSocket
;
93 static VALUE rb_eSocket
;
96 VALUE rb_cSOCKSSocket
;
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
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
{
123 unsigned char ss_len
; /* address length */
124 unsigned char ss_family
; /* address family */
126 unsigned short ss_family
;
128 char __ss_pad1
[_SS_PAD1SIZE
];
129 double __ss_align
; /* force desired structure storage alignment */
130 char __ss_pad2
[_SS_PAD2SIZE
];
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
,
142 /* should not happen */
147 ruby_getaddrinfo(char *nodename
, char *servname
,
148 struct addrinfo
*hints
, struct addrinfo
**res
)
150 struct addrinfo tmp_hints
;
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
);
163 if (tmp_hints
.ai_family
== PF_UNSPEC
) {
174 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res))
179 ruby_getaddrinfo__aix(char *nodename
, char *servname
,
180 struct addrinfo
*hints
, struct addrinfo
**res
)
182 int error
= getaddrinfo(nodename
, servname
, hints
, res
);
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
;
195 #define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res))
197 ruby_getnameinfo__aix(sa
, salen
, host
, hostlen
, serv
, servlen
, flags
)
198 const struct sockaddr
*sa
;
206 struct sockaddr_in6
*sa6
;
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
);
219 return getnameinfo(sa
, salen
, host
, hostlen
, serv
, servlen
, flags
);
222 #define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
223 ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags))
225 # define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
228 # define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
234 #define close closesocket
238 init_sock(VALUE sock
, int fd
)
242 MakeOpenFile(sock
, fp
);
244 fp
->mode
= FMODE_READWRITE
|FMODE_DUPLEX
;
245 #if defined(_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__EMX__)
246 fp
->mode
|= FMODE_BINMODE
;
248 if (do_not_reverse_lookup
) {
249 fp
->mode
|= FMODE_NOREVLOOKUP
;
251 rb_io_synchronized(fp
);
257 bsock_s_for_fd(VALUE klass
, VALUE fd
)
260 VALUE sock
= init_sock(rb_obj_alloc(klass
), NUM2INT(fd
));
262 GetOpenFile(sock
, fptr
);
268 bsock_shutdown(int argc
, VALUE
*argv
, VALUE sock
)
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
);
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)
294 bsock_close_read(VALUE sock
)
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
;
312 bsock_close_write(VALUE sock
)
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
;
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.
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,
349 * - String: the string's data and length is passed to the socket.
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:
365 * struct in_addr imr_multiaddr;
366 * struct in_addr imr_interface;
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)
375 bsock_setsockopt(VALUE sock
, VALUE lev
, VALUE optname
, VALUE val
)
384 level
= NUM2INT(lev
);
385 option
= NUM2INT(optname
);
397 v
= (char*)&i
; vlen
= sizeof(i
);
401 v
= RSTRING_PTR(val
);
402 vlen
= RSTRING_LEN(val
);
406 GetOpenFile(sock
, fptr
);
407 if (setsockopt(fptr
->fd
, level
, option
, v
, vlen
) < 0)
408 rb_sys_fail(fptr
->path
);
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.
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.
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
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"
454 bsock_getsockopt(VALUE sock
, VALUE lev
, VALUE optname
)
456 #if !defined(__BEOS__)
462 level
= NUM2INT(lev
);
463 option
= NUM2INT(optname
);
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
);
478 bsock_getsockname(VALUE sock
)
481 socklen_t len
= sizeof buf
;
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
);
491 bsock_getpeername(VALUE sock
)
494 socklen_t len
= sizeof buf
;
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
);
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
);
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
),
529 bsock_send(int argc
, VALUE
*argv
, VALUE sock
)
535 rb_blocking_function_t
*func
;
538 rb_scan_args(argc
, argv
, "21", &arg
.mesg
, &flags
, &to
);
540 StringValue(arg
.mesg
);
543 to
= rb_str_new4(to
);
544 arg
.to
= (struct sockaddr
*)RSTRING_PTR(to
);
545 arg
.tolen
= RSTRING_LEN(to
);
546 func
= sendto_blocking
;
549 func
= send_blocking
;
551 GetOpenFile(sock
, fptr
);
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
)) {
559 rb_sys_fail("send(2)");
565 bsock_do_not_reverse_lookup(VALUE sock
)
569 GetOpenFile(sock
, fptr
);
570 return (fptr
->mode
& FMODE_NOREVLOOKUP
) ? Qtrue
: Qfalse
;
574 bsock_do_not_reverse_lookup_set(VALUE sock
, VALUE state
)
579 GetOpenFile(sock
, fptr
);
581 fptr
->mode
|= FMODE_NOREVLOOKUP
;
584 fptr
->mode
&= ~FMODE_NOREVLOOKUP
;
589 static VALUE
ipaddr(struct sockaddr
*, int);
591 static VALUE
unixaddr(struct sockaddr_un
*, socklen_t
);
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
{
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
);
617 s_recvfrom(VALUE sock
, int argc
, VALUE
*argv
, enum sock_recv_type from
)
621 struct recvfrom_arg arg
;
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");
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
);
661 if (arg
.alen
!= sizeof(struct sockaddr_in
)) {
662 rb_raise(rb_eTypeError
, "sockaddr size differs - should not happen");
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
));
668 return rb_assoc_new(str
, Qnil
);
672 return rb_assoc_new(str
, unixaddr((struct sockaddr_un
*)arg
.buf
, arg
.alen
));
675 return rb_assoc_new(str
, rb_str_new(arg
.buf
, arg
.alen
));
677 rb_bug("s_recvfrom called with bad value");
682 s_recvfrom_nonblock(VALUE sock
, int argc
, VALUE
*argv
, enum sock_recv_type from
)
687 socklen_t alen
= sizeof buf
;
694 rb_scan_args(argc
, argv
, "11", &len
, &flg
);
696 if (flg
== Qnil
) flags
= 0;
697 else flags
= NUM2INT(flg
);
698 buflen
= NUM2INT(len
);
701 /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
702 It is not portable, though. */
703 flags
|= MSG_DONTWAIT
;
706 GetOpenFile(sock
, fptr
);
707 if (rb_io_read_pending(fptr
)) {
708 rb_raise(rb_eIOError
, "recvfrom for buffered IO");
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
);
719 rb_sys_fail("recvfrom(2)");
721 if (slen
< RSTRING_LEN(str
)) {
722 rb_str_set_len(str
, slen
);
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
);
735 addr
= rb_str_new(buf
, alen
);
739 rb_bug("s_recvfrom_nonblock called with bad value");
741 return rb_assoc_new(str
, addr
);
745 bsock_recv(int argc
, VALUE
*argv
, VALUE sock
)
747 return s_recvfrom(sock
, argc
, argv
, RECV_RECV
);
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.
765 * * +maxlen+ - the number of bytes to receive from the socket
766 * * +flags+ - zero or more of the +MSG_+ options
769 * serv = TCPServer.new("127.0.0.1", 0)
770 * af, port, host, addr = serv.addr
771 * c = TCPSocket.new(addr, port)
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.
788 bsock_recv_nonblock(int argc
, VALUE
*argv
, VALUE sock
)
790 return s_recvfrom_nonblock(sock
, argc
, argv
, RECV_RECV
);
794 bsock_do_not_rev_lookup(void)
796 return do_not_reverse_lookup
?Qtrue
:Qfalse
;
800 bsock_do_not_rev_lookup_set(VALUE self
, VALUE val
)
803 do_not_reverse_lookup
= RTEST(val
);
807 NORETURN(static void raise_socket_error(const char *, int));
809 raise_socket_error(const char *reason
, int error
)
812 if (error
== EAI_SYSTEM
) rb_sys_fail(reason
);
814 rb_raise(rb_eSocket
, "%s: %s", reason
, gai_strerror(error
));
818 make_ipaddr0(struct sockaddr
*addr
, char *buf
, size_t len
)
822 error
= getnameinfo(addr
, SA_LEN(addr
), buf
, len
, NULL
, 0, NI_NUMERICHOST
);
824 raise_socket_error("getnameinfo", error
);
829 make_ipaddr(struct sockaddr
*addr
)
833 make_ipaddr0(addr
, buf
, sizeof(buf
));
834 return rb_str_new2(buf
);
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
);
850 str_isnumber(const char *p
)
854 if (!p
|| *p
== '\0')
857 (void)STRTOUL(p
, &ep
, 10);
858 if (ep
&& *ep
== '\0')
865 host_str(VALUE host
, char *hbuf
, size_t len
)
870 else if (rb_obj_is_kind_of(host
, rb_cInteger
)) {
871 long i
= NUM2LONG(host
);
873 make_inetaddr(htonl(i
), hbuf
, len
);
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
")",
899 port_str(VALUE port
, char *pbuf
, size_t len
)
904 else if (FIXNUM_P(port
)) {
905 snprintf(pbuf
, len
, "%ld", FIX2LONG(port
));
911 SafeStringValue(port
);
912 serv
= RSTRING_PTR(port
);
913 if (strlen(serv
) >= len
) {
914 rb_raise(rb_eArgError
, "service name too long (%"PRIuSIZE
")",
923 # define NI_MAXHOST 1025
926 # define NI_MAXSERV 32
929 static struct addrinfo
*
930 sock_addrinfo(VALUE host
, VALUE port
, int socktype
, int flags
)
932 struct addrinfo hints
;
933 struct addrinfo
* res
= NULL
;
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
);
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__)
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
;
979 ipaddr(struct sockaddr
*sockaddr
, int norevlookup
)
981 VALUE family
, port
, addr1
, addr2
;
984 char hbuf
[1024], pbuf
[1024];
986 switch (sockaddr
->sa_family
) {
988 family
= rb_str_new2("AF_UNSPEC");
991 family
= rb_str_new2("AF_INET");
995 family
= rb_str_new2("AF_INET6");
1000 family
= rb_str_new2("AF_LOCAL");
1004 family
= rb_str_new2("AF_UNIX");
1008 sprintf(pbuf
, "unknown:%d", sockaddr
->sa_family
);
1009 family
= rb_str_new2(pbuf
);
1015 error
= getnameinfo(sockaddr
, SA_LEN(sockaddr
), hbuf
, sizeof(hbuf
),
1018 addr1
= rb_str_new2(hbuf
);
1021 error
= getnameinfo(sockaddr
, SA_LEN(sockaddr
), hbuf
, sizeof(hbuf
),
1022 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
| NI_NUMERICSERV
);
1024 raise_socket_error("getnameinfo", error
);
1026 addr2
= rb_str_new2(hbuf
);
1027 if (addr1
== Qnil
) {
1030 port
= INT2FIX(atoi(pbuf
));
1031 ary
= rb_ary_new3(4, family
, port
, addr1
, addr2
);
1037 ruby_socket(int domain
, int type
, int proto
)
1041 fd
= socket(domain
, type
, proto
);
1043 if (errno
== EMFILE
|| errno
== ENFILE
) {
1045 fd
= socket(domain
, type
, proto
);
1052 wait_connectable0(int fd
, rb_fdset_t
*fds_w
, rb_fdset_t
*fds_e
)
1055 socklen_t sockerrlen
;
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
)) {
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) {
1074 continue; /* workaround for winsock */
1084 struct wait_connectable_arg
{
1090 #ifdef HAVE_RB_FD_INIT
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
);
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
);
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
1117 return (int)rb_ensure(try_wait_connectable
, (VALUE
)&arg
,
1118 wait_connectable_ensure
,(VALUE
)&arg
);
1120 return wait_connectable0(fd
, &arg
.fds_w
, &arg
.fds_e
);
1125 #define WAIT_IN_PROGRESS 10
1128 #define WAIT_IN_PROGRESS 10
1131 /* returns correct error */
1132 #define WAIT_IN_PROGRESS 0
1134 #ifndef WAIT_IN_PROGRESS
1135 /* BSD origin code apparently has a problem */
1136 #define WAIT_IN_PROGRESS 1
1139 struct connect_arg
{
1141 const struct sockaddr
*sockaddr
;
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)
1154 socks_connect_blocking(void *data
)
1156 struct connect_arg
*arg
= data
;
1157 return (VALUE
)Rconnect(arg
->fd
, arg
->sockaddr
, arg
->len
);
1162 ruby_connect(int fd
, const struct sockaddr
*sockaddr
, int len
, int socks
)
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;
1170 socklen_t sockerrlen
;
1174 arg
.sockaddr
= sockaddr
;
1176 #if defined(SOCKS) && !defined(SOCKS5)
1177 if (socks
) func
= socks_connect_blocking
;
1180 status
= (int)BLOCKING_REGION(func
, &arg
);
1187 #if WAIT_IN_PROGRESS > 0
1188 sockerrlen
= sizeof(sockerr
);
1189 status
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, (void *)&sockerr
, &sockerrlen
);
1200 #if WAIT_IN_PROGRESS > 0
1201 wait_in_progress
= WAIT_IN_PROGRESS
;
1203 status
= wait_connectable(fd
);
1210 #if WAIT_IN_PROGRESS > 0
1212 if (wait_in_progress
-- > 0) {
1214 * connect() after EINPROGRESS returns EINVAL on
1215 * some platforms, need to check true error
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
);
1250 struct addrinfo
*res
;
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
);
1274 init_inetsock_internal(struct inetsock_arg
*arg
)
1276 int type
= arg
->type
;
1277 struct addrinfo
*res
;
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);
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)";
1300 if (type
== INET_SERVER
) {
1301 #if !defined(_WIN32) && !defined(__CYGWIN__)
1303 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
,
1304 (char*)&status
, sizeof(status
));
1306 status
= bind(fd
, res
->ai_addr
, res
->ai_addrlen
);
1307 syscall
= "bind(2)";
1310 if (arg
->local
.res
) {
1311 status
= bind(fd
, arg
->local
.res
->ai_addr
, arg
->local
.res
->ai_addrlen
);
1312 syscall
= "bind(2)";
1316 status
= ruby_connect(fd
, res
->ai_addr
, res
->ai_addrlen
,
1317 (type
== INET_SOCKS
));
1318 syscall
= "connect(2)";
1330 rb_sys_fail(syscall
);
1335 if (type
== INET_SERVER
)
1338 /* create new instance */
1339 return init_sock(arg
->sock
, fd
);
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
;
1348 arg
.remote
.host
= remote_host
;
1349 arg
.remote
.serv
= remote_serv
;
1351 arg
.local
.host
= local_host
;
1352 arg
.local
.serv
= local_serv
;
1356 return rb_ensure(init_inetsock_internal
, (VALUE
)&arg
,
1357 inetsock_cleanup
, (VALUE
)&arg
);
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.
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
);
1383 socks_init(VALUE sock
, VALUE host
, VALUE serv
)
1392 return init_inetsock(sock
, host
, serv
, Qnil
, Qnil
, INET_SOCKS
);
1397 socks_s_close(VALUE sock
)
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
);
1411 struct hostent_arg
{
1413 struct addrinfo
* addr
;
1414 VALUE (*ipaddr
)(struct sockaddr
*, size_t);
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
;
1429 char hbuf
[NI_MAXHOST
];
1432 if (addr
->ai_canonname
) {
1433 hostp
= addr
->ai_canonname
;
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
));
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
));
1461 make_hostent(VALUE host
, struct addrinfo
*addr
, VALUE (*ipaddr
)(struct sockaddr
*, size_t))
1463 struct hostent_arg arg
;
1467 arg
.ipaddr
= ipaddr
;
1468 return rb_ensure(make_hostent_internal
, (VALUE
)&arg
,
1469 RUBY_METHOD_FUNC(freeaddrinfo
), (VALUE
)addr
);
1473 tcp_sockaddr(struct sockaddr
*addr
, size_t len
)
1475 return make_ipaddr(addr
);
1479 tcp_s_gethostbyname(VALUE obj
, VALUE host
)
1482 return make_hostent(host
, sock_addrinfo(host
, Qnil
, SOCK_STREAM
, AI_CANONNAME
),
1487 tcp_svr_init(int argc
, VALUE
*argv
, VALUE sock
)
1491 if (rb_scan_args(argc
, argv
, "11", &arg1
, &arg2
) == 2)
1492 return init_inetsock(sock
, arg1
, arg2
, Qnil
, Qnil
, INET_SERVER
);
1494 return init_inetsock(sock
, Qnil
, arg1
, Qnil
, Qnil
, INET_SERVER
);
1498 make_fd_nonblock(int fd
)
1502 flags
= fcntl(fd
, F_GETFL
);
1509 flags
|= O_NONBLOCK
;
1510 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
1516 s_accept_nonblock(VALUE klass
, rb_io_t
*fptr
, struct sockaddr
*sockaddr
, socklen_t
*len
)
1521 rb_io_set_nonblock(fptr
);
1522 fd2
= accept(fptr
->fd
, (struct sockaddr
*)sockaddr
, len
);
1524 rb_sys_fail("accept(2)");
1526 make_fd_nonblock(fd2
);
1527 return init_sock(rb_obj_alloc(klass
), fd2
);
1532 struct sockaddr
*sockaddr
;
1537 accept_blocking(void *data
)
1539 struct accept_arg
*arg
= data
;
1540 return (VALUE
)accept(arg
->fd
, arg
->sockaddr
, arg
->len
);
1544 s_accept(VALUE klass
, int fd
, struct sockaddr
*sockaddr
, socklen_t
*len
)
1548 struct accept_arg arg
;
1552 arg
.sockaddr
= sockaddr
;
1555 rb_thread_wait_fd(fd
);
1556 fd2
= BLOCKING_REGION(accept_blocking
, &arg
);
1566 if (!rb_io_wait_readable(fd
)) break;
1572 if (!klass
) return INT2NUM(fd2
);
1573 return init_sock(rb_obj_alloc(klass
), fd2
);
1577 tcp_accept(VALUE sock
)
1580 struct sockaddr_storage from
;
1583 GetOpenFile(sock
, fptr
);
1584 fromlen
= sizeof(from
);
1585 return s_accept(rb_cTCPSocket
, fptr
->fd
,
1586 (struct sockaddr
*)&from
, &fromlen
);
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.
1599 * serv = TCPServer.new(2202)
1601 * sock = serv.accept_nonblock
1602 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
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.
1615 * * TCPServer#accept
1619 tcp_accept_nonblock(VALUE sock
)
1622 struct sockaddr_storage from
;
1625 GetOpenFile(sock
, fptr
);
1626 fromlen
= sizeof(from
);
1627 return s_accept_nonblock(rb_cTCPSocket
, fptr
,
1628 (struct sockaddr
*)&from
, &fromlen
);
1632 tcp_sysaccept(VALUE sock
)
1635 struct sockaddr_storage from
;
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
;
1650 unixsock_connect_internal(struct unixsock_arg
*arg
)
1652 return (VALUE
)ruby_connect(arg
->fd
, (struct sockaddr
*)arg
->sockaddr
,
1653 sizeof(*arg
->sockaddr
), 0);
1657 init_unixsock(VALUE sock
, VALUE path
, int server
)
1659 struct sockaddr_un sockaddr
;
1663 SafeStringValue(path
);
1664 fd
= ruby_socket(AF_UNIX
, SOCK_STREAM
, 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
));
1678 status
= bind(fd
, (struct sockaddr
*)&sockaddr
, sizeof(sockaddr
));
1682 struct unixsock_arg arg
;
1683 arg
.sockaddr
= &sockaddr
;
1685 status
= rb_protect((VALUE(*)(VALUE
))unixsock_connect_internal
,
1686 (VALUE
)&arg
, &prot
);
1695 rb_sys_fail(sockaddr
.sun_path
);
1698 if (server
) listen(fd
, 5);
1700 init_sock(sock
, fd
);
1702 GetOpenFile(sock
, fptr
);
1703 fptr
->path
= strdup(RSTRING_PTR(path
));
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
);
1725 ip_peeraddr(VALUE sock
)
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
);
1739 ip_recvfrom(int argc
, VALUE
*argv
, VALUE sock
)
1741 return s_recvfrom(sock
, argc
, argv
, RECV_IP
);
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
);
1754 return make_ipaddr((struct sockaddr
*)&addr
);
1758 udp_init(int argc
, VALUE
*argv
, VALUE sock
)
1761 int socktype
= AF_INET
;
1765 if (rb_scan_args(argc
, argv
, "01", &arg
) == 1) {
1766 socktype
= NUM2INT(arg
);
1768 fd
= ruby_socket(socktype
, SOCK_DGRAM
, 0);
1770 rb_sys_fail("socket(2) - udp");
1773 return init_sock(sock
, fd
);
1778 struct addrinfo
*res
;
1783 udp_connect_internal(struct udp_arg
*arg
)
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) {
1797 udp_connect(VALUE sock
, VALUE host
, VALUE port
)
1804 arg
.res
= sock_addrinfo(host
, port
, SOCK_DGRAM
, 0);
1805 GetOpenFile(sock
, fptr
);
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)");
1814 udp_bind(VALUE sock
, VALUE host
, VALUE port
)
1817 struct addrinfo
*res0
, *res
;
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) {
1830 rb_sys_fail("bind(2)");
1835 udp_send(int argc
, VALUE
*argv
, VALUE sock
)
1837 VALUE flags
, host
, port
;
1840 struct addrinfo
*res0
, *res
;
1841 struct send_arg arg
;
1843 if (argc
== 2 || argc
== 3) {
1844 return bsock_send(argc
, argv
, sock
);
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
);
1853 arg
.flags
= NUM2INT(flags
);
1854 for (res
= res0
; res
; res
= res
->ai_next
) {
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
);
1864 if (rb_io_wait_writable(fptr
->fd
)) {
1869 rb_sys_fail("sendto(2)");
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.
1889 * * +maxlen+ - the number of bytes to receive from the socket
1890 * * +flags+ - zero or more of the +MSG_+ options
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))
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.
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
1921 unix_init(VALUE sock
, VALUE path
)
1923 return init_unixsock(sock
, path
, 0);
1927 unixpath(struct sockaddr_un
*sockaddr
, socklen_t len
)
1929 if (sockaddr
->sun_path
< (char*)sockaddr
+ len
)
1930 return sockaddr
->sun_path
;
1936 unix_path(VALUE sock
)
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)
1946 fptr
->path
= strdup(unixpath(&addr
, len
));
1948 return rb_str_new2(fptr
->path
);
1952 unix_svr_init(VALUE sock
, VALUE path
)
1954 return init_unixsock(sock
, path
, 1);
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
1966 #define FD_PASSING_BY_MSG_CONTROL 0
1969 #if defined(HAVE_ST_MSG_ACCRIGHTS)
1970 #define FD_PASSING_BY_MSG_ACCRIGHTS 1
1972 #define FD_PASSING_BY_MSG_ACCRIGHTS 0
1981 sendmsg_blocking(void *data
)
1983 struct iomsg_arg
*arg
= data
;
1984 return sendmsg(arg
->fd
, &arg
->msg
, 0);
1988 unix_send_io(VALUE sock
, VALUE val
)
1990 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
1993 struct iomsg_arg arg
;
1994 struct iovec vec
[1];
1997 #if FD_PASSING_BY_MSG_CONTROL
2000 char pad
[8+sizeof(int)+8];
2004 if (rb_obj_is_kind_of(val
, rb_cIO
)) {
2006 GetOpenFile(val
, valfptr
);
2009 else if (FIXNUM_P(val
)) {
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. */
2023 vec
[0].iov_base
= buf
;
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
;
2038 arg
.msg
.msg_accrights
= (caddr_t
)&fd
;
2039 arg
.msg
.msg_accrightslen
= sizeof(fd
);
2043 rb_thread_fd_writable(arg
.fd
);
2044 if ((int)BLOCKING_REGION(sendmsg_blocking
, &arg
) == -1)
2045 rb_sys_fail("sendmsg(2)");
2050 return Qnil
; /* not reached */
2055 recvmsg_blocking(void *data
)
2057 struct iomsg_arg
*arg
= data
;
2058 return recvmsg(arg
->fd
, &arg
->msg
, 0);
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)
2067 struct iomsg_arg arg
;
2068 struct iovec vec
[2];
2072 #if FD_PASSING_BY_MSG_CONTROL
2075 char pad
[8+sizeof(int)+8];
2079 rb_scan_args(argc
, argv
, "02", &klass
, &mode
);
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;
2104 arg
.msg
.msg_accrights
= (caddr_t
)&fd
;
2105 arg
.msg
.msg_accrightslen
= sizeof(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
);
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
));
2143 #if FD_PASSING_BY_MSG_CONTROL
2144 fd
= *(int *)CMSG_DATA(&cmsg
.hdr
);
2150 static ID for_fd
= 0;
2154 for_fd
= rb_intern("for_fd");
2155 ff_argc
= mode
== Qnil
? 1 : 2;
2156 ff_argv
[0] = INT2FIX(fd
);
2158 return rb_funcall2(klass
, for_fd
, ff_argc
, ff_argv
);
2162 return Qnil
; /* not reached */
2167 unix_accept(VALUE sock
)
2170 struct sockaddr_un from
;
2173 GetOpenFile(sock
, fptr
);
2174 fromlen
= sizeof(struct sockaddr_un
);
2175 return s_accept(rb_cUNIXSocket
, fptr
->fd
,
2176 (struct sockaddr
*)&from
, &fromlen
);
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.
2189 * serv = UNIXServer.new("/tmp/sock")
2191 * sock = serv.accept_nonblock
2192 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
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.
2205 * * UNIXServer#accept
2209 unix_accept_nonblock(VALUE sock
)
2212 struct sockaddr_un from
;
2215 GetOpenFile(sock
, fptr
);
2216 fromlen
= sizeof(from
);
2217 return s_accept_nonblock(rb_cUNIXSocket
, fptr
,
2218 (struct sockaddr
*)&from
, &fromlen
);
2222 unix_sysaccept(VALUE sock
)
2225 struct sockaddr_un from
;
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
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
)));
2243 unix_addr(VALUE sock
)
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
);
2257 unix_peeraddr(VALUE sock
)
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
);
2272 setup_domain_and_type(VALUE domain
, int *dv
, VALUE type
, int *tv
)
2277 tmp
= rb_check_string_type(domain
);
2280 rb_check_safe_obj(domain
);
2281 ptr
= RSTRING_PTR(domain
);
2282 if (strcmp(ptr
, "AF_INET") == 0)
2285 else if (strcmp(ptr
, "AF_UNIX") == 0)
2289 else if (strcmp(ptr
, "AF_ISO") == 0)
2293 else if (strcmp(ptr
, "AF_NS") == 0)
2297 else if (strcmp(ptr
, "AF_IMPLINK") == 0)
2301 else if (strcmp(ptr
, "PF_INET") == 0)
2305 else if (strcmp(ptr
, "PF_UNIX") == 0)
2309 else if (strcmp(ptr
, "PF_IMPLINK") == 0)
2311 else if (strcmp(ptr
, "AF_IMPLINK") == 0)
2315 else if (strcmp(ptr
, "PF_AX25") == 0)
2319 else if (strcmp(ptr
, "PF_IPX") == 0)
2323 rb_raise(rb_eSocket
, "unknown socket domain %s", ptr
);
2326 *dv
= NUM2INT(domain
);
2328 tmp
= rb_check_string_type(type
);
2331 rb_check_safe_obj(type
);
2332 ptr
= RSTRING_PTR(type
);
2333 if (strcmp(ptr
, "SOCK_STREAM") == 0)
2335 else if (strcmp(ptr
, "SOCK_DGRAM") == 0)
2338 else if (strcmp(ptr
, "SOCK_RAW") == 0)
2341 #ifdef SOCK_SEQPACKET
2342 else if (strcmp(ptr
, "SOCK_SEQPACKET") == 0)
2343 *tv
= SOCK_SEQPACKET
;
2346 else if (strcmp(ptr
, "SOCK_RDM") == 0)
2350 else if (strcmp(ptr
, "SOCK_PACKET") == 0)
2354 rb_raise(rb_eSocket
, "unknown socket type %s", ptr
);
2357 *tv
= NUM2INT(type
);
2362 sock_initialize(VALUE sock
, VALUE domain
, VALUE type
, VALUE protocol
)
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
);
2376 sock_s_socketpair(VALUE klass
, VALUE domain
, VALUE type
, VALUE protocol
)
2378 #if defined HAVE_SOCKETPAIR
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
)) {
2387 ret
= socketpair(d
, t
, p
, sp
);
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]));
2400 #ifdef HAVE_SYS_UN_H
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
);
2409 type
= INT2FIX(SOCK_STREAM
);
2411 protocol
= INT2FIX(0);
2413 return sock_s_socketpair(klass
, domain
, type
, protocol
);
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.
2425 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
2428 * # Pull down Google's web page
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
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
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
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
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
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_
2482 * * Errno::EIO - an i/o error occured while reading from or writing to the
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
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
2525 * * connect manual pages on unix-based systems
2526 * * connect function in Microsoft's Winsock functions reference
2529 sock_connect(VALUE sock
, VALUE addr
)
2535 addr
= rb_str_new4(addr
);
2536 GetOpenFile(sock
, fptr
);
2538 n
= ruby_connect(fd
, (struct sockaddr
*)RSTRING_PTR(addr
), RSTRING_LEN(addr
), 0);
2540 rb_sys_fail("connect(2)");
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.
2555 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
2558 * # Pull down Google's web page
2560 * include Socket::Constants
2561 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2562 * sockaddr = Socket.sockaddr_in(80, 'www.google.com')
2564 * socket.connect_nonblock(sockaddr)
2565 * rescue Errno::EINPROGRESS
2566 * IO.select(nil, [socket])
2568 * socket.connect_nonblock(sockaddr)
2569 * rescue Errno::EISCONN
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.
2585 sock_connect_nonblock(VALUE sock
, VALUE 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
));
2596 rb_sys_fail("connect(2)");
2604 * socket.bind(server_sockaddr) => 0
2606 * Binds to the given +struct+ sockaddr.
2609 * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
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
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
2635 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
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_
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
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
2678 * * bind manual pages on unix-based systems
2679 * * bind function in Microsoft's Winsock functions reference
2682 sock_bind(VALUE sock
, VALUE 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)");
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
2703 * * +backlog+ - the maximum length of the queue for pending connections.
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):
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
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
2761 * * listen manual pages on unix-based systems
2762 * * listen function in Microsoft's Winsock functions reference
2765 sock_listen(VALUE sock
, VALUE log
)
2771 backlog
= NUM2INT(log
);
2772 GetOpenFile(sock
, fptr
);
2773 if (listen(fptr
->fd
, backlog
) < 0)
2774 rb_sys_fail("listen(2)");
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
2790 * * +maxlen+ - the number of bytes to receive from the socket
2791 * * +flags+ - zero or more of the +MSG_+ options
2794 * # In one file, start this first
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}'"
2807 * # In another file, start this second
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!"
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
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
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
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
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
2885 sock_recvfrom(int argc
, VALUE
*argv
, VALUE sock
)
2887 return s_recvfrom(sock
, argc
, argv
, RECV_SOCKET
);
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
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.
2907 * * +maxlen+ - the number of bytes to receive from the socket
2908 * * +flags+ - zero or more of the +MSG_+ options
2911 * # In one file, start this first
2913 * include Socket::Constants
2914 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2915 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
2916 * socket.bind(sockaddr)
2918 * client, client_sockaddr = socket.accept
2920 * pair = client.recvfrom_nonblock(20)
2921 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK
2922 * IO.select([client])
2925 * data = pair[0].chomp
2926 * puts "I only received 20 bytes '#{data}'"
2930 * # In another file, start this second
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!"
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.
2949 sock_recvfrom_nonblock(int argc
, VALUE
*argv
, VALUE sock
)
2951 return s_recvfrom_nonblock(sock
, argc
, argv
, RECV_SOCKET
);
2955 sock_accept(VALUE sock
)
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
));
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_.
2980 * # In one script, start this first
2982 * include Socket::Constants
2983 * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
2984 * sockaddr = Socket.sockaddr_in(2200, 'localhost')
2985 * socket.bind(sockaddr)
2988 * client_socket, client_sockaddr = socket.accept_nonblock
2989 * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
2990 * IO.select([socket])
2993 * puts "The client said, '#{client_socket.readline.chomp}'"
2994 * client_socket.puts "Hello from script one!"
2997 * # In another script, start this second
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}'"
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.
3017 sock_accept_nonblock(VALUE sock
)
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
));
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_.
3039 * # In one script, start this first
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!"
3052 * # In another script, start this second
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}'"
3062 * Refer to Socket#accept for the exceptions that may be thrown if the call
3063 * to _sysaccept_ fails.
3069 sock_sysaccept(VALUE sock
)
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
3084 sock_gethostname(VALUE obj
)
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
);
3098 #include <sys/utsname.h>
3101 sock_gethostname(VALUE obj
)
3107 return rb_str_new2(un
.nodename
);
3111 sock_gethostname(VALUE obj
)
3119 make_addrinfo(struct addrinfo
*res0
)
3122 struct addrinfo
*res
;
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
);
3142 sock_sockaddr(struct sockaddr
*addr
, size_t len
)
3146 switch (addr
->sa_family
) {
3148 ptr
= (char*)&((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
;
3149 len
= sizeof(((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
);
3153 ptr
= (char*)&((struct sockaddr_in6
*)addr
)->sin6_addr
.s6_addr
;
3154 len
= sizeof(((struct sockaddr_in6
*)addr
)->sin6_addr
.s6_addr
);
3158 rb_raise(rb_eSocket
, "unknown socket family:%d", addr
->sa_family
);
3161 return rb_str_new(ptr
, len
);
3165 sock_s_gethostbyname(VALUE obj
, VALUE host
)
3168 return make_hostent(host
, sock_addrinfo(host
, Qnil
, SOCK_STREAM
, AI_CANONNAME
), sock_sockaddr
);
3172 sock_s_gethostbyaddr(int argc
, VALUE
*argv
)
3176 struct sockaddr
*sa
;
3181 rb_scan_args(argc
, argv
, "11", &addr
, &type
);
3182 sa
= (struct sockaddr
*)StringValuePtr(addr
);
3187 else if (RSTRING_LEN(addr
) == 16) {
3191 h
= gethostbyaddr(RSTRING_PTR(addr
), RSTRING_LEN(addr
), t
);
3193 #ifdef HAVE_HSTRERROR
3195 rb_raise(rb_eSocket
, "%s", (char*)hstrerror(h_errno
));
3197 rb_raise(rb_eSocket
, "host not found");
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
));
3211 for (pch
= h
->h_addr_list
; *pch
; pch
++) {
3212 rb_ary_push(ary
, rb_str_new(*pch
, h
->h_length
));
3215 rb_ary_push(ary
, rb_str_new(h
->h_addr
, h
->h_length
));
3222 sock_s_getservbyname(int argc
, VALUE
*argv
)
3224 VALUE service
, proto
;
3228 rb_scan_args(argc
, argv
, "11", &service
, &proto
);
3229 if (NIL_P(proto
)) proto
= rb_str_new2("tcp");
3230 StringValue(service
);
3233 sp
= getservbyname(StringValueCStr(service
), StringValueCStr(proto
));
3235 port
= ntohs(sp
->s_port
);
3238 char *s
= RSTRING_PTR(service
);
3241 port
= STRTOUL(s
, &end
, 0);
3243 rb_raise(rb_eSocket
, "no such service %s/%s", s
, RSTRING_PTR(proto
));
3246 return INT2FIX(port
);
3250 sock_s_getservbyport(int argc
, VALUE
*argv
)
3255 rb_scan_args(argc
, argv
, "11", &port
, &proto
);
3256 if (NIL_P(proto
)) proto
= rb_str_new2("tcp");
3259 sp
= getservbyport(NUM2INT(port
), StringValueCStr(proto
));
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
);
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
;
3275 host
= port
= family
= socktype
= protocol
= flags
= Qnil
;
3276 rb_scan_args(argc
, argv
, "24", &host
, &port
, &family
, &socktype
, &protocol
, &flags
);
3281 strncpy(hbuf
, StringValuePtr(host
), sizeof(hbuf
));
3282 hbuf
[sizeof(hbuf
) - 1] = '\0';
3288 else if (FIXNUM_P(port
)) {
3289 snprintf(pbuf
, sizeof(pbuf
), "%ld", FIX2LONG(port
));
3293 strncpy(pbuf
, StringValuePtr(port
), sizeof(pbuf
));
3294 pbuf
[sizeof(pbuf
) - 1] = '\0';
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
;
3310 else if (strcmp(ap
, "AF_INET6") == 0) {
3311 hints
.ai_family
= PF_INET6
;
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
);
3327 raise_socket_error("getaddrinfo", error
);
3330 ret
= make_addrinfo(res
);
3336 sock_s_getnameinfo(int argc
, VALUE
*argv
)
3338 VALUE sa
, af
= Qnil
, host
= Qnil
, port
= Qnil
, flags
, tmp
;
3340 char hbuf
[1024], pbuf
[1024];
3342 struct addrinfo hints
, *res
= NULL
, *r
;
3344 struct sockaddr_storage ss
;
3345 struct sockaddr
*sap
;
3349 rb_scan_args(argc
, argv
, "11", &sa
, &flags
);
3352 if (!NIL_P(flags
)) {
3353 fl
= NUM2INT(flags
);
3355 tmp
= rb_check_string_type(sa
);
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
;
3368 tmp
= rb_check_array_type(sa
);
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];
3382 host
= RARRAY_PTR(sa
)[2];
3386 * 4th element holds numeric form, don't resolve.
3389 #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
3390 hints
.ai_flags
|= AI_NUMERICHOST
;
3395 rb_raise(rb_eArgError
, "array size should be 3 or 4, %ld given",
3403 strncpy(hbuf
, StringValuePtr(host
), sizeof(hbuf
));
3404 hbuf
[sizeof(hbuf
) - 1] = '\0';
3412 else if (FIXNUM_P(port
)) {
3413 snprintf(pbuf
, sizeof(pbuf
), "%ld", NUM2LONG(port
));
3417 strncpy(pbuf
, StringValuePtr(port
), sizeof(pbuf
));
3418 pbuf
[sizeof(pbuf
) - 1] = '\0';
3421 hints
.ai_socktype
= (fl
& NI_DGRAM
) ? SOCK_DGRAM
: SOCK_STREAM
;
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
;
3434 else if (strcmp(ap
, "AF_INET6") == 0) {
3435 hints
.ai_family
= PF_INET6
;
3439 error
= getaddrinfo(hptr
, pptr
, &hints
, &res
);
3440 if (error
) goto error_exit_addr
;
3444 rb_raise(rb_eTypeError
, "expecting String or Array");
3448 error
= getnameinfo(sap
, SA_LEN(sap
), hbuf
, sizeof(hbuf
),
3449 pbuf
, sizeof(pbuf
), fl
);
3450 if (error
) goto error_exit_name
;
3452 for (r
= res
->ai_next
; r
; r
= r
->ai_next
) {
3453 char hbuf2
[1024], pbuf2
[1024];
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) {
3461 rb_raise(rb_eSocket
, "sockaddr resolved to multiple nodename");
3466 return rb_assoc_new(rb_str_new2(hbuf
), rb_str_new2(pbuf
));
3469 if (res
) freeaddrinfo(res
);
3470 raise_socket_error("getaddrinfo", error
);
3473 if (res
) freeaddrinfo(res
);
3474 raise_socket_error("getnameinfo", error
);
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
);
3484 OBJ_INFECT(addr
, port
);
3485 OBJ_INFECT(addr
, host
);
3491 sock_s_unpack_sockaddr_in(VALUE self
, VALUE addr
)
3493 struct sockaddr_in
* sockaddr
;
3496 sockaddr
= (struct sockaddr_in
*)StringValuePtr(addr
);
3497 if (((struct sockaddr
*)sockaddr
)->sa_family
!= AF_INET
3499 && ((struct sockaddr
*)sockaddr
)->sa_family
!= AF_INET6
3503 rb_raise(rb_eArgError
, "not an AF_INET/AF_INET6 sockaddr");
3505 rb_raise(rb_eArgError
, "not an AF_INET sockaddr");
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
3515 sock_s_pack_sockaddr_un(VALUE self
, VALUE path
)
3517 struct sockaddr_un sockaddr
;
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
);
3536 sock_s_unpack_sockaddr_un(VALUE self
, VALUE addr
)
3538 struct sockaddr_un
* sockaddr
;
3539 const char *sun_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
);
3562 static VALUE mConst
;
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
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.
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);
3634 rb_cSOCKSSocket
= rb_define_class("SOCKSSocket", rb_cTCPSocket
);
3635 rb_define_method(rb_cSOCKSSocket
, "initialize", socks_init
, 2);
3637 rb_define_method(rb_cSOCKSSocket
, "close", socks_s_close
, 0);
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);
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);
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
);