summaryrefslogtreecommitdiff
path: root/ext/socket
diff options
context:
space:
mode:
Diffstat (limited to 'ext/socket')
-rw-r--r--ext/socket/.document1
-rw-r--r--ext/socket/ancdata.c410
-rw-r--r--ext/socket/basicsocket.c259
-rw-r--r--ext/socket/constants.c5
-rw-r--r--ext/socket/depend2879
-rw-r--r--ext/socket/extconf.rb801
-rw-r--r--ext/socket/getaddrinfo.c27
-rw-r--r--ext/socket/getnameinfo.c36
-rw-r--r--ext/socket/ifaddr.c478
-rw-r--r--ext/socket/init.c711
-rw-r--r--ext/socket/ipsocket.c163
-rw-r--r--ext/socket/lib/socket.rb716
-rw-r--r--ext/socket/mkconstants.rb216
-rw-r--r--ext/socket/option.c599
-rw-r--r--ext/socket/raddrinfo.c852
-rw-r--r--ext/socket/rubysocket.h350
-rw-r--r--ext/socket/socket.c935
-rw-r--r--ext/socket/sockport.h86
-rw-r--r--ext/socket/sockssocket.c17
-rw-r--r--ext/socket/tcpserver.c83
-rw-r--r--ext/socket/tcpsocket.c49
-rw-r--r--ext/socket/udpsocket.c205
-rw-r--r--ext/socket/unixserver.c72
-rw-r--r--ext/socket/unixsocket.c129
24 files changed, 7823 insertions, 2256 deletions
diff --git a/ext/socket/.document b/ext/socket/.document
index 0216c5aa45..53cfac0b10 100644
--- a/ext/socket/.document
+++ b/ext/socket/.document
@@ -2,6 +2,7 @@ ancdata.c
basicsocket.c
constants.c
constdefs.c
+ifaddr.c
init.c
ipsocket.c
option.c
diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c
index 050da974c4..aa62cab0ec 100644
--- a/ext/socket/ancdata.c
+++ b/ext/socket/ancdata.c
@@ -2,7 +2,9 @@
#include <time.h>
-#if defined(HAVE_ST_MSG_CONTROL)
+static VALUE sym_wait_readable, sym_wait_writable;
+
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
static VALUE rb_cAncillaryData;
static VALUE
@@ -86,9 +88,9 @@ ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE
static VALUE
ancdata_new(int family, int level, int type, VALUE data)
{
- NEWOBJ_OF(obj, struct RObject, rb_cAncillaryData, T_OBJECT);
+ VALUE obj = rb_obj_alloc(rb_cAncillaryData);
StringValue(data);
- ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
+ ancillary_initialize(obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
return (VALUE)obj;
}
@@ -204,7 +206,7 @@ ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
str = rb_str_buf_new(sizeof(int) * argc);
for (i = 0 ; i < argc; i++) {
- VALUE obj = RARRAY_PTR(ary)[i];
+ VALUE obj = RARRAY_AREF(ary, i);
rb_io_t *fptr;
int fd;
GetOpenFile(obj, fptr);
@@ -276,8 +278,8 @@ ancillary_unix_rights(VALUE self)
* returns the timestamp as a time object.
*
* _ancillarydata_ should be one of following type:
- * - SOL_SOCKET/SCM_TIMESTAMP (micro second) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
- * - SOL_SOCKET/SCM_TIMESTAMPNS (nano second) GNU/Linux
+ * - SOL_SOCKET/SCM_TIMESTAMP (microsecond) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
+ * - SOL_SOCKET/SCM_TIMESTAMPNS (nanosecond) GNU/Linux
* - SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD
*
* Addrinfo.udp("127.0.0.1", 0).bind {|s1|
@@ -357,6 +359,8 @@ ancillary_timestamp(VALUE self)
*
* The size and endian is dependent on the host.
*
+ * require 'socket'
+ *
* p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
* #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
*/
@@ -573,9 +577,7 @@ extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockadd
memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
- memset(sa_ptr, 0, sizeof(*sa_ptr));
- SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6));
- sa_ptr->sin6_family = AF_INET6;
+ INIT_SOCKADDR((struct sockaddr *)sa_ptr, AF_INET6, sizeof(*sa_ptr));
memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
@@ -849,6 +851,12 @@ anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
}
#endif
+#ifdef HAVE_GMTIME_R
+# define LOCALTIME(time, tm) localtime_r(&(time), &(tm))
+#else
+# define LOCALTIME(time, tm) ((tm) = *localtime(&(time)))
+#endif
+
#if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
static int
inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
@@ -860,7 +868,7 @@ inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
char buf[32];
memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
time = tv.tv_sec;
- tm = *localtime(&time);
+ LOCALTIME(time, tm);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
return 1;
@@ -880,7 +888,7 @@ inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
struct tm tm;
char buf[32];
memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
- tm = *localtime(&ts.tv_sec);
+ LOCALTIME(ts.tv_sec, tm);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
return 1;
@@ -904,7 +912,7 @@ inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
uint64_t res_h, res_l;
char buf[32];
memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
- tm = *localtime(&bt.sec);
+ LOCALTIME(bt.sec, tm);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
/* res_h = frac * 10**19 / 2**64 */
@@ -989,7 +997,7 @@ ancillary_inspect(VALUE self)
vtype = ip_cmsg_type_to_sym(level, type);
if (SYMBOL_P(vtype))
- rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
+ rb_str_catf(ret, " %"PRIsVALUE, rb_sym2str(vtype));
else
rb_str_catf(ret, " cmsg_type:%d", type);
}
@@ -1054,7 +1062,7 @@ ancillary_inspect(VALUE self)
# if defined(IPPROTO_IPV6)
case IPPROTO_IPV6:
switch (type) {
-# if defined(IPV6_PKTINFO) /* RFC 3542 */
+# if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* RFC 3542 */
case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
# endif
}
@@ -1105,8 +1113,8 @@ ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
#if defined(HAVE_SENDMSG)
struct sendmsg_args_struct {
int fd;
- const struct msghdr *msg;
int flags;
+ const struct msghdr *msg;
};
static void *
@@ -1127,42 +1135,40 @@ rb_sendmsg(int fd, const struct msghdr *msg, int flags)
}
static VALUE
-bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
+bsock_sendmsg_internal(VALUE sock, VALUE data, VALUE vflags,
+ VALUE dest_sockaddr, VALUE controls, VALUE ex,
+ int nonblock)
{
rb_io_t *fptr;
- VALUE data, vflags, dest_sockaddr;
- VALUE *controls_ptr;
- int controls_num;
struct msghdr mh;
struct iovec iov;
-#if defined(HAVE_ST_MSG_CONTROL)
- volatile VALUE controls_str = 0;
+ VALUE tmp;
+ int controls_num;
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ VALUE controls_str = 0;
+ int family;
#endif
int flags;
ssize_t ss;
- int family;
- rb_secure(4);
GetOpenFile(sock, fptr);
- family = rsock_getfamily(fptr->fd);
-
- data = vflags = dest_sockaddr = Qnil;
- controls_ptr = NULL;
- controls_num = 0;
-
- if (argc == 0)
- rb_raise(rb_eArgError, "mesg argument required");
- data = argv[0];
- if (1 < argc) vflags = argv[1];
- if (2 < argc) dest_sockaddr = argv[2];
- if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ family = rsock_getfamily(fptr);
+#endif
StringValue(data);
+ tmp = rb_str_tmp_frozen_acquire(data);
+
+ if (!RB_TYPE_P(controls, T_ARRAY)) {
+ controls = rb_ary_new();
+ }
+ controls_num = RARRAY_LENINT(controls);
if (controls_num) {
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
int i;
size_t last_pad = 0;
+ const VALUE *controls_ptr = RARRAY_CONST_PTR(controls);
#if defined(__NetBSD__)
int last_level = 0;
int last_type = 0;
@@ -1237,6 +1243,7 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
#endif
}
+ RB_GC_GUARD(controls);
#else
rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
#endif
@@ -1257,118 +1264,91 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
memset(&mh, 0, sizeof(mh));
if (!NIL_P(dest_sockaddr)) {
mh.msg_name = RSTRING_PTR(dest_sockaddr);
- mh.msg_namelen = RSTRING_LENINT(dest_sockaddr);
+ mh.msg_namelen = RSTRING_SOCKLEN(dest_sockaddr);
}
mh.msg_iovlen = 1;
mh.msg_iov = &iov;
- iov.iov_base = RSTRING_PTR(data);
- iov.iov_len = RSTRING_LEN(data);
-#if defined(HAVE_ST_MSG_CONTROL)
+ iov.iov_base = RSTRING_PTR(tmp);
+ iov.iov_len = RSTRING_LEN(tmp);
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
if (controls_str) {
mh.msg_control = RSTRING_PTR(controls_str);
- mh.msg_controllen = RSTRING_LENINT(controls_str);
- }
- else {
- mh.msg_control = NULL;
- mh.msg_controllen = 0;
+ mh.msg_controllen = RSTRING_SOCKLEN(controls_str);
}
#endif
rb_io_check_closed(fptr);
- if (nonblock)
+ if (nonblock && !MSG_DONTWAIT_RELIABLE)
rb_io_set_nonblock(fptr);
ss = rb_sendmsg(fptr->fd, &mh, flags);
- if (!nonblock && rb_io_wait_writable(fptr->fd)) {
- rb_io_check_closed(fptr);
- goto retry;
- }
-
if (ss == -1) {
- if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
- rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
- rb_sys_fail("sendmsg(2)");
+ int e;
+ if (!nonblock && rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
+ rb_io_check_closed(fptr);
+ goto retry;
+ }
+ e = errno;
+ if (nonblock && (e == EWOULDBLOCK || e == EAGAIN)) {
+ if (ex == Qfalse) {
+ return sym_wait_writable;
+ }
+ rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
+ "sendmsg(2) would block");
+ }
+ rb_syserr_fail(e, "sendmsg(2)");
}
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ RB_GC_GUARD(controls_str);
+#endif
+ rb_str_tmp_frozen_release(data, tmp);
return SSIZET2NUM(ss);
}
#endif
#if defined(HAVE_SENDMSG)
-/*
- * call-seq:
- * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
- *
- * sendmsg sends a message using sendmsg(2) system call in blocking manner.
- *
- * _mesg_ is a string to send.
- *
- * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
- *
- * _dest_sockaddr_ is a destination socket address for connection-less socket.
- * It should be a sockaddr such as a result of Socket.sockaddr_in.
- * An Addrinfo object can be used too.
- *
- * _controls_ is a list of ancillary data.
- * The element of _controls_ should be Socket::AncillaryData or
- * 3-elements array.
- * The 3-element array should contains cmsg_level, cmsg_type and data.
- *
- * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
- *
- * sendmsg can be used to implement send_io as follows:
- *
- * # use Socket::AncillaryData.
- * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
- * sock.sendmsg("a", 0, nil, ancdata)
- *
- * # use 3-element array.
- * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
- * sock.sendmsg("\0", 0, nil, ancdata)
- *
- */
VALUE
-rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags, VALUE dest_sockaddr,
+ VALUE controls)
{
- return bsock_sendmsg_internal(argc, argv, sock, 0);
+ return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr, controls,
+ Qtrue, 0);
}
#endif
#if defined(HAVE_SENDMSG)
-/*
- * call-seq:
- * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
- *
- * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
- *
- * It is similar to BasicSocket#sendmsg
- * but the non-blocking flag is set before the system call
- * and it doesn't retry the system call.
- *
- */
VALUE
-rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags,
+ VALUE dest_sockaddr, VALUE controls, VALUE ex)
{
- return bsock_sendmsg_internal(argc, argv, sock, 1);
+ return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr,
+ controls, ex, 1);
}
#endif
#if defined(HAVE_RECVMSG)
struct recvmsg_args_struct {
int fd;
- struct msghdr *msg;
int flags;
+ struct msghdr *msg;
};
ssize_t
rsock_recvmsg(int socket, struct msghdr *message, int flags)
{
+ ssize_t ret;
+ socklen_t len0;
#ifdef MSG_CMSG_CLOEXEC
/* MSG_CMSG_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
flags |= MSG_CMSG_CLOEXEC;
#endif
- return recvmsg(socket, message, flags);
+ len0 = message->msg_namelen;
+ ret = recvmsg(socket, message, flags);
+ if (ret != -1 && len0 < message->msg_namelen)
+ message->msg_namelen = len0;
+ return ret;
}
static void *
@@ -1389,7 +1369,7 @@ rb_recvmsg(int fd, struct msghdr *msg, int flags)
return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
}
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
static void
discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
{
@@ -1410,7 +1390,7 @@ discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
int *end = (int *)((char *)cmh + cmh->cmsg_len);
while ((char *)fdp + sizeof(int) <= (char *)end &&
(char *)fdp + sizeof(int) <= msg_end) {
- rb_fd_fix_cloexec(*fdp);
+ rb_update_max_fd(*fdp);
close(*fdp);
fdp++;
}
@@ -1421,7 +1401,7 @@ discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
void
rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
{
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
struct cmsghdr *cmh;
char *msg_end;
@@ -1436,7 +1416,7 @@ rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
#endif
}
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
static void
make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
{
@@ -1453,7 +1433,8 @@ make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
VALUE io;
if (fstat(fd, &stbuf) == -1)
rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
- rb_fd_fix_cloexec(fd);
+ rb_update_max_fd(fd);
+ rb_maygvl_fd_fix_cloexec(fd);
if (S_ISSOCK(stbuf.st_mode))
io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
else
@@ -1468,50 +1449,39 @@ make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
#endif
static VALUE
-bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
+bsock_recvmsg_internal(VALUE sock,
+ VALUE vmaxdatlen, VALUE vflags, VALUE vmaxctllen,
+ VALUE scm_rights, VALUE ex, int nonblock)
{
rb_io_t *fptr;
- VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
int grow_buffer;
size_t maxdatlen;
int flags, orig_flags;
- int request_scm_rights;
struct msghdr mh;
struct iovec iov;
- struct sockaddr_storage namebuf;
- char datbuf0[4096], *datbuf;
+ union_sockaddr namebuf;
+ char *datbuf;
VALUE dat_str = Qnil;
VALUE ret;
ssize_t ss;
-#if defined(HAVE_ST_MSG_CONTROL)
+ int request_scm_rights;
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
struct cmsghdr *cmh;
size_t maxctllen;
- union {
- char bytes[4096];
- struct cmsghdr align;
- } ctlbuf0;
char *ctlbuf;
VALUE ctl_str = Qnil;
int family;
int gc_done = 0;
#endif
- rb_secure(4);
-
- vopts = Qnil;
- if (0 < argc && RB_TYPE_P(argv[argc-1], T_HASH))
- vopts = argv[--argc];
-
- rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
-
- maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
-#if defined(HAVE_ST_MSG_CONTROL)
- maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
+ maxdatlen = NIL_P(vmaxdatlen) ? 4096 : NUM2SIZET(vmaxdatlen);
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ maxctllen = NIL_P(vmaxctllen) ? 4096 : NUM2SIZET(vmaxctllen);
#else
if (!NIL_P(vmaxctllen))
rb_raise(rb_eArgError, "control message not supported");
#endif
- flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
+ flags = NUM2INT(vflags);
#ifdef MSG_DONTWAIT
if (nonblock)
flags |= MSG_DONTWAIT;
@@ -1521,15 +1491,19 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
request_scm_rights = 0;
- if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
+ if (RTEST(scm_rights))
request_scm_rights = 1;
+#if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ if (request_scm_rights)
+ rb_raise(rb_eNotImpError, "control message for recvmsg is unimplemented");
+#endif
GetOpenFile(sock, fptr);
if (rb_io_read_pending(fptr)) {
rb_raise(rb_eIOError, "recvmsg for buffered IO");
}
-#if !defined(HAVE_ST_MSG_CONTROL)
+#if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
if (grow_buffer) {
int socktype;
socklen_t optlen = (socklen_t)sizeof(socktype);
@@ -1542,32 +1516,24 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
#endif
retry:
- if (maxdatlen <= sizeof(datbuf0))
- datbuf = datbuf0;
- else {
- if (NIL_P(dat_str))
- dat_str = rb_str_tmp_new(maxdatlen);
- else
- rb_str_resize(dat_str, maxdatlen);
- datbuf = RSTRING_PTR(dat_str);
- }
+ if (NIL_P(dat_str))
+ dat_str = rb_str_tmp_new(maxdatlen);
+ else
+ rb_str_resize(dat_str, maxdatlen);
+ datbuf = RSTRING_PTR(dat_str);
-#if defined(HAVE_ST_MSG_CONTROL)
- if (maxctllen <= sizeof(ctlbuf0))
- ctlbuf = ctlbuf0.bytes;
- else {
- if (NIL_P(ctl_str))
- ctl_str = rb_str_tmp_new(maxctllen);
- else
- rb_str_resize(ctl_str, maxctllen);
- ctlbuf = RSTRING_PTR(ctl_str);
- }
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ if (NIL_P(ctl_str))
+ ctl_str = rb_str_tmp_new(maxctllen);
+ else
+ rb_str_resize(ctl_str, maxctllen);
+ ctlbuf = RSTRING_PTR(ctl_str);
#endif
memset(&mh, 0, sizeof(mh));
memset(&namebuf, 0, sizeof(namebuf));
- mh.msg_name = (struct sockaddr *)&namebuf;
+ mh.msg_name = &namebuf.addr;
mh.msg_namelen = (socklen_t)sizeof(namebuf);
mh.msg_iov = &iov;
@@ -1575,7 +1541,7 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
iov.iov_base = datbuf;
iov.iov_len = maxdatlen;
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
mh.msg_control = ctlbuf;
mh.msg_controllen = (socklen_t)maxctllen;
#endif
@@ -1584,21 +1550,26 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
flags |= MSG_PEEK;
rb_io_check_closed(fptr);
- if (nonblock)
+ if (nonblock && !MSG_DONTWAIT_RELIABLE)
rb_io_set_nonblock(fptr);
ss = rb_recvmsg(fptr->fd, &mh, flags);
- if (!nonblock && rb_io_wait_readable(fptr->fd)) {
- rb_io_check_closed(fptr);
- goto retry;
- }
-
if (ss == -1) {
- if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
- rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
-#if defined(HAVE_ST_MSG_CONTROL)
- if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
+ int e;
+ if (!nonblock && rb_io_maybe_wait_readable(errno, fptr->self, Qnil)) {
+ rb_io_check_closed(fptr);
+ goto retry;
+ }
+ e = errno;
+ if (nonblock && (e == EWOULDBLOCK || e == EAGAIN)) {
+ if (ex == Qfalse) {
+ return sym_wait_readable;
+ }
+ rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "recvmsg(2) would block");
+ }
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ if (!gc_done && (e == EMFILE || e == EMSGSIZE)) {
/*
* When SCM_RIGHTS hit the file descriptors limit:
* - Linux 2.6.18 causes success with MSG_CTRUNC
@@ -1610,23 +1581,27 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
gc_done = 1;
goto retry;
}
+#else
+ if (NIL_P(vmaxdatlen) && grow_buffer && e == EMSGSIZE)
+ ss = (ssize_t)iov.iov_len;
+ else
#endif
- rb_sys_fail("recvmsg(2)");
+ rb_syserr_fail(e, "recvmsg(2)");
}
if (grow_buffer) {
int grown = 0;
-#if defined(HAVE_ST_MSG_CONTROL)
- if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
+ if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
if (SIZE_MAX/2 < maxdatlen)
rb_raise(rb_eArgError, "max data length too big");
maxdatlen *= 2;
grown = 1;
}
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
#define BIG_ENOUGH_SPACE 65536
if (BIG_ENOUGH_SPACE < maxctllen &&
- mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
+ (socklen_t)mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
/* there are big space bug truncated.
* file descriptors limit? */
if (!gc_done) {
@@ -1642,13 +1617,6 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
}
#undef BIG_ENOUGH_SPACE
}
-#else
- if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
- if (SIZE_MAX/2 < maxdatlen)
- rb_raise(rb_eArgError, "max data length too big");
- maxdatlen *= 2;
- grown = 1;
- }
#endif
if (grown) {
rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
@@ -1665,24 +1633,23 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
}
if (NIL_P(dat_str))
- dat_str = rb_tainted_str_new(datbuf, ss);
+ dat_str = rb_str_new(datbuf, ss);
else {
rb_str_resize(dat_str, ss);
- OBJ_TAINT(dat_str);
- RBASIC(dat_str)->klass = rb_cString;
+ rb_obj_reveal(dat_str, rb_cString);
}
ret = rb_ary_new3(3, dat_str,
rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
INT2NUM(mh.msg_flags)
#else
Qnil
#endif
);
-#if defined(HAVE_ST_MSG_CONTROL)
- family = rsock_getfamily(fptr->fd);
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+ family = rsock_getfamily(fptr);
if (mh.msg_controllen) {
char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
@@ -1694,13 +1661,14 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
}
ctl_end = (char*)cmh + cmh->cmsg_len;
clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
- ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
+ ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_str_new((char*)CMSG_DATA(cmh), clen));
if (request_scm_rights)
make_io_for_unix_rights(ctl, cmh, msg_end);
else
discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
rb_ary_push(ret, ctl);
}
+ RB_GC_GUARD(ctl_str);
}
#endif
@@ -1709,89 +1677,28 @@ bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
#endif
#if defined(HAVE_RECVMSG)
-/*
- * call-seq:
- * basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
- *
- * recvmsg receives a message using recvmsg(2) system call in blocking manner.
- *
- * _maxmesglen_ is the maximum length of mesg to receive.
- *
- * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
- *
- * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
- *
- * _opts_ is option hash.
- * Currently :scm_rights=>bool is the only option.
- *
- * :scm_rights option specifies that application expects SCM_RIGHTS control message.
- * If the value is nil or false, application don't expects SCM_RIGHTS control message.
- * In this case, recvmsg closes the passed file descriptors immediately.
- * This is the default behavior.
- *
- * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
- * In this case, recvmsg creates IO objects for each file descriptors for
- * Socket::AncillaryData#unix_rights method.
- *
- * The return value is 4-elements array.
- *
- * _mesg_ is a string of the received message.
- *
- * _sender_addrinfo_ is a sender socket address for connection-less socket.
- * It is an Addrinfo object.
- * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
- *
- * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
- * It will be nil if the system uses 4.3BSD style old recvmsg system call.
- *
- * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
- *
- * #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
- *
- * _maxmesglen_ and _maxcontrollen_ can be nil.
- * In that case, the buffer will be grown until the message is not truncated.
- * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
- *
- * recvmsg can be used to implement recv_io as follows:
- *
- * mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
- * controls.each {|ancdata|
- * if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
- * return ancdata.unix_rights[0]
- * end
- * }
- *
- */
VALUE
-rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_recvmsg(VALUE sock, VALUE dlen, VALUE flags, VALUE clen,
+ VALUE scm_rights)
{
- return bsock_recvmsg_internal(argc, argv, sock, 0);
+ VALUE ex = Qtrue;
+ return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 0);
}
#endif
#if defined(HAVE_RECVMSG)
-/*
- * call-seq:
- * basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
- *
- * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
- *
- * It is similar to BasicSocket#recvmsg
- * but non-blocking flag is set before the system call
- * and it doesn't retry the system call.
- *
- */
VALUE
-rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_recvmsg_nonblock(VALUE sock, VALUE dlen, VALUE flags, VALUE clen,
+ VALUE scm_rights, VALUE ex)
{
- return bsock_recvmsg_internal(argc, argv, sock, 1);
+ return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 1);
}
#endif
void
rsock_init_ancdata(void)
{
-#if defined(HAVE_ST_MSG_CONTROL)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
/*
* Document-class: Socket::AncillaryData
*
@@ -1825,4 +1732,7 @@ rsock_init_ancdata(void)
rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
#endif
+#undef rb_intern
+ sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
+ sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
}
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index c1ae88d80c..44fb7a4eb7 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -10,6 +10,28 @@
#include "rubysocket.h"
+#ifdef _WIN32
+#define is_socket(fd) rb_w32_is_socket(fd)
+#else
+static int
+is_socket(int fd)
+{
+ struct stat sbuf;
+
+ if (fstat(fd, &sbuf) < 0)
+ rb_sys_fail("fstat(2)");
+ return S_ISSOCK(sbuf.st_mode);
+}
+#endif
+
+static void
+rsock_validate_descriptor(int descriptor)
+{
+ if (!is_socket(descriptor) || rb_reserved_fd_p(descriptor)) {
+ rb_syserr_fail(EBADF, "not a socket file descriptor");
+ }
+}
+
/*
* call-seq:
* BasicSocket.for_fd(fd) => basicsocket
@@ -22,10 +44,14 @@
*
*/
static VALUE
-bsock_s_for_fd(VALUE klass, VALUE fd)
+bsock_s_for_fd(VALUE klass, VALUE _descriptor)
{
rb_io_t *fptr;
- VALUE sock = rsock_init_sock(rb_obj_alloc(klass), NUM2INT(fd));
+
+ int descriptor = RB_NUM2INT(_descriptor);
+ rsock_validate_descriptor(descriptor);
+
+ VALUE sock = rsock_init_sock(rb_obj_alloc(klass), descriptor);
GetOpenFile(sock, fptr);
@@ -66,9 +92,6 @@ bsock_shutdown(int argc, VALUE *argv, VALUE sock)
int how;
rb_io_t *fptr;
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
- rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket");
- }
rb_scan_args(argc, argv, "01", &howto);
if (howto == Qnil)
how = SHUT_RDWR;
@@ -80,7 +103,7 @@ bsock_shutdown(int argc, VALUE *argv, VALUE sock)
}
GetOpenFile(sock, fptr);
if (shutdown(fptr->fd, how) == -1)
- rb_sys_fail(0);
+ rb_sys_fail("shutdown(2)");
return INT2FIX(0);
}
@@ -100,9 +123,6 @@ bsock_close_read(VALUE sock)
{
rb_io_t *fptr;
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
- rb_raise(rb_eSecurityError, "Insecure: can't close socket");
- }
GetOpenFile(sock, fptr);
shutdown(fptr->fd, 0);
if (!(fptr->mode & FMODE_WRITABLE)) {
@@ -133,9 +153,6 @@ bsock_close_write(VALUE sock)
{
rb_io_t *fptr;
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
- rb_raise(rb_eSecurityError, "Insecure: can't close socket");
- }
GetOpenFile(sock, fptr);
if (!(fptr->mode & FMODE_READABLE)) {
return rb_io_close(sock);
@@ -167,10 +184,10 @@ bsock_close_write(VALUE sock)
* * +optval+ is the value of the option, it is passed to the underlying
* setsockopt() as a pointer to a certain number of bytes. How this is
* done depends on the type:
- * - Fixnum: value is assigned to an int, and a pointer to the int is
+ * - Integer: value is assigned to an int, and a pointer to the int is
* passed, with length of sizeof(int).
* - true or false: 1 or 0 (respectively) is assigned to an int, and the
- * int is passed as for a Fixnum. Note that +false+ must be passed,
+ * int is passed as for an Integer. Note that +false+ must be passed,
* not +nil+.
* - String: the string's data and length is passed to the socket.
* * +socketoption+ is an instance of Socket::Option
@@ -222,9 +239,8 @@ bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
rb_scan_args(argc, argv, "30", &lev, &optname, &val);
}
- rb_secure(2);
GetOpenFile(sock, fptr);
- family = rsock_getfamily(fptr->fd);
+ family = rsock_getfamily(fptr);
level = rsock_level_arg(family, lev);
option = rsock_optname_arg(family, level, optname);
@@ -243,20 +259,17 @@ bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
default:
StringValue(val);
v = RSTRING_PTR(val);
- vlen = RSTRING_LENINT(val);
+ vlen = RSTRING_SOCKLEN(val);
break;
}
-#define rb_sys_fail_path(path) rb_sys_fail_str(path)
-
rb_io_check_closed(fptr);
if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
- rb_sys_fail_path(fptr->pathv);
+ rsock_sys_fail_path("setsockopt(2)", fptr->pathv);
return INT2FIX(0);
}
-#if !defined(__BEOS__)
/*
* Document-method: getsockopt
* call-seq:
@@ -293,7 +306,7 @@ bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
* ipttl = sock.getsockopt(:IP, :TTL).int
*
* optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
- * ipttl = optval.unpack("i")[0]
+ * ipttl = optval.unpack1("i")
*
* Option values may be structs. Decoding them can be complex as it involves
* examining your system headers to determine the correct definition. An
@@ -323,22 +336,31 @@ bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
int family;
GetOpenFile(sock, fptr);
- family = rsock_getfamily(fptr->fd);
+ family = rsock_getfamily(fptr);
level = rsock_level_arg(family, lev);
option = rsock_optname_arg(family, level, optname);
len = 256;
+#ifdef _AIX
+ switch (option) {
+ case SO_DEBUG:
+ case SO_REUSEADDR:
+ case SO_KEEPALIVE:
+ case SO_DONTROUTE:
+ case SO_BROADCAST:
+ case SO_OOBINLINE:
+ /* AIX doesn't set len for boolean options */
+ len = sizeof(int);
+ }
+#endif
buf = ALLOCA_N(char,len);
rb_io_check_closed(fptr);
if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
- rb_sys_fail_path(fptr->pathv);
+ rsock_sys_fail_path("getsockopt(2)", fptr->pathv);
return rsock_sockopt_new(family, level, option, rb_str_new(buf, len));
}
-#else
-#define bsock_getsockopt rb_f_notimplement
-#endif
/*
* call-seq:
@@ -356,13 +378,15 @@ bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
static VALUE
bsock_getsockname(VALUE sock)
{
- struct sockaddr_storage buf;
+ union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
+ socklen_t len0 = len;
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
+ if (getsockname(fptr->fd, &buf.addr, &len) < 0)
rb_sys_fail("getsockname(2)");
+ if (len0 < len) len = len0;
return rb_str_new((char*)&buf, len);
}
@@ -385,13 +409,15 @@ bsock_getsockname(VALUE sock)
static VALUE
bsock_getpeername(VALUE sock)
{
- struct sockaddr_storage buf;
+ union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
+ socklen_t len0 = len;
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
+ if (getpeername(fptr->fd, &buf.addr, &len) < 0)
rb_sys_fail("getpeername(2)");
+ if (len0 < len) len = len0;
return rb_str_new((char*)&buf, len);
}
@@ -427,7 +453,7 @@ bsock_getpeereid(VALUE self)
gid_t egid;
GetOpenFile(self, fptr);
if (getpeereid(fptr->fd, &euid, &egid) == -1)
- rb_sys_fail("getpeereid");
+ rb_sys_fail("getpeereid(3)");
return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
#elif defined(SO_PEERCRED) /* GNU/Linux */
rb_io_t *fptr;
@@ -443,7 +469,7 @@ bsock_getpeereid(VALUE self)
VALUE ret;
GetOpenFile(self, fptr);
if (getpeerucred(fptr->fd, &uc) == -1)
- rb_sys_fail("getpeerucred");
+ rb_sys_fail("getpeerucred(3C)");
ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
ucred_free(uc);
return ret;
@@ -473,14 +499,16 @@ bsock_getpeereid(VALUE self)
static VALUE
bsock_local_address(VALUE sock)
{
- struct sockaddr_storage buf;
+ union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
+ socklen_t len0 = len;
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
+ if (getsockname(fptr->fd, &buf.addr, &len) < 0)
rb_sys_fail("getsockname(2)");
- return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
+ if (len0 < len) len = len0;
+ return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
}
/*
@@ -505,14 +533,16 @@ bsock_local_address(VALUE sock)
static VALUE
bsock_remote_address(VALUE sock)
{
- struct sockaddr_storage buf;
+ union_sockaddr buf;
socklen_t len = (socklen_t)sizeof buf;
+ socklen_t len0 = len;
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
+ if (getpeername(fptr->fd, &buf.addr, &len) < 0)
rb_sys_fail("getpeername(2)");
- return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
+ if (len0 < len) len = len0;
+ return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
}
/*
@@ -533,39 +563,50 @@ bsock_remote_address(VALUE sock)
* }
*/
VALUE
-rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_send(int argc, VALUE *argv, VALUE socket)
{
struct rsock_send_arg arg;
VALUE flags, to;
rb_io_t *fptr;
- int n;
rb_blocking_function_t *func;
+ const char *funcname;
- rb_secure(4);
rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
StringValue(arg.mesg);
if (!NIL_P(to)) {
- SockAddrStringValue(to);
- to = rb_str_new4(to);
- arg.to = (struct sockaddr *)RSTRING_PTR(to);
- arg.tolen = (socklen_t)RSTRING_LENINT(to);
- func = rsock_sendto_blocking;
+ SockAddrStringValue(to);
+ to = rb_str_new4(to);
+ arg.to = (struct sockaddr *)RSTRING_PTR(to);
+ arg.tolen = RSTRING_SOCKLEN(to);
+ func = rsock_sendto_blocking;
+ funcname = "sendto(2)";
}
else {
- func = rsock_send_blocking;
+ func = rsock_send_blocking;
+ funcname = "send(2)";
}
- GetOpenFile(sock, fptr);
+
+ RB_IO_POINTER(socket, fptr);
+
arg.fd = fptr->fd;
arg.flags = NUM2INT(flags);
- while (rb_thread_fd_writable(arg.fd),
- (n = (int)BLOCKING_REGION_FD(func, &arg)) < 0) {
- if (rb_io_wait_writable(arg.fd)) {
- continue;
- }
- rb_sys_fail("send(2)");
+
+ while (true) {
+#ifdef RSOCK_WAIT_BEFORE_BLOCKING
+ rb_io_wait(socket, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil);
+#endif
+
+ ssize_t n = (ssize_t)BLOCKING_REGION_FD(func, &arg);
+
+ if (n >= 0) return SSIZET2NUM(n);
+
+ if (rb_io_maybe_wait_writable(errno, socket, Qnil)) {
+ continue;
+ }
+
+ rb_sys_fail(funcname);
}
- return INT2FIX(n);
}
/*
@@ -574,11 +615,15 @@ rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
*
* Gets the do_not_reverse_lookup flag of _basicsocket_.
*
+ * require 'socket'
+ *
+ * BasicSocket.do_not_reverse_lookup = false
* TCPSocket.open("www.ruby-lang.org", 80) {|sock|
* p sock.do_not_reverse_lookup #=> false
- * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
- * sock.do_not_reverse_lookup = true
- * p sock.peeraddr #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
+ * }
+ * BasicSocket.do_not_reverse_lookup = true
+ * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
+ * p sock.do_not_reverse_lookup #=> true
* }
*/
static VALUE
@@ -596,10 +641,12 @@ bsock_do_not_reverse_lookup(VALUE sock)
*
* Sets the do_not_reverse_lookup flag of _basicsocket_.
*
- * BasicSocket.do_not_reverse_lookup = false
- * p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> false
- * BasicSocket.do_not_reverse_lookup = true
- * p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> true
+ * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
+ * p sock.do_not_reverse_lookup #=> true
+ * p sock.peeraddr #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
+ * sock.do_not_reverse_lookup = false
+ * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "54.163.249.195"]
+ * }
*
*/
static VALUE
@@ -607,7 +654,6 @@ bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
{
rb_io_t *fptr;
- rb_secure(4);
GetOpenFile(sock, fptr);
if (RTEST(state)) {
fptr->mode |= FMODE_NOREVLOOKUP;
@@ -620,8 +666,7 @@ bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
/*
* call-seq:
- * basicsocket.recv(maxlen) => mesg
- * basicsocket.recv(maxlen, flags) => mesg
+ * basicsocket.recv(maxlen[, flags[, outbuf]]) => mesg
*
* Receives a message.
*
@@ -629,6 +674,9 @@ bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
*
* _flags_ should be a bitwise OR of Socket::MSG_* constants.
*
+ * _outbuf_ will contain only the received data after the method call
+ * even if it is not empty at the beginning.
+ *
* UNIXSocket.pair {|s1, s2|
* s1.puts "Hello World"
* p s2.recv(4) #=> "Hell"
@@ -643,55 +691,11 @@ bsock_recv(int argc, VALUE *argv, VALUE sock)
return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
}
-/*
- * call-seq:
- * basicsocket.recv_nonblock(maxlen) => mesg
- * basicsocket.recv_nonblock(maxlen, flags) => mesg
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The result, _mesg_, is the data received.
- *
- * When recvfrom(2) returns 0, Socket#recv_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- * serv = TCPServer.new("127.0.0.1", 0)
- * af, port, host, addr = serv.addr
- * c = TCPSocket.new(addr, port)
- * s = serv.accept
- * c.send "aaa", 0
- * begin # emulate blocking recv.
- * p s.recv_nonblock(10) #=> "aaa"
- * rescue IO::WaitReadable
- * IO.select([s])
- * retry
- * end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recv_nonblock_ fails.
- *
- * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
-
+/* :nodoc: */
static VALUE
-bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
+bsock_recv_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_RECV);
}
/*
@@ -703,7 +707,7 @@ bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
* BasicSocket.do_not_reverse_lookup #=> false
*/
static VALUE
-bsock_do_not_rev_lookup(void)
+bsock_do_not_rev_lookup(VALUE _)
{
return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
}
@@ -727,7 +731,6 @@ bsock_do_not_rev_lookup(void)
static VALUE
bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
{
- rb_secure(4);
rsock_do_not_reverse_lookup = RTEST(val);
return val;
}
@@ -761,13 +764,29 @@ rsock_init_basicsocket(void)
rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
- rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
+
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
- rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
- rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
- rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
- rb_define_method(rb_cBasicSocket, "recvmsg_nonblock", rsock_bsock_recvmsg_nonblock, -1); /* in ancdata.c */
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cBasicSocket,
+ "__recv_nonblock", bsock_recv_nonblock, 4);
+
+#if MSG_DONTWAIT_RELIABLE
+ rb_define_private_method(rb_cBasicSocket,
+ "__read_nonblock", rsock_read_nonblock, 3);
+ rb_define_private_method(rb_cBasicSocket,
+ "__write_nonblock", rsock_write_nonblock, 2);
+#endif
+
+ /* in ancdata.c */
+ rb_define_private_method(rb_cBasicSocket, "__sendmsg",
+ rsock_bsock_sendmsg, 4);
+ rb_define_private_method(rb_cBasicSocket, "__sendmsg_nonblock",
+ rsock_bsock_sendmsg_nonblock, 5);
+ rb_define_private_method(rb_cBasicSocket, "__recvmsg",
+ rsock_bsock_recvmsg, 4);
+ rb_define_private_method(rb_cBasicSocket, "__recvmsg_nonblock",
+ rsock_bsock_recvmsg_nonblock, 5);
}
diff --git a/ext/socket/constants.c b/ext/socket/constants.c
index 39f985b316..1bbb53b173 100644
--- a/ext/socket/constants.c
+++ b/ext/socket/constants.c
@@ -22,13 +22,12 @@ constant_arg(VALUE arg, int (*str_to_int)(const char*, long, int*), const char *
int ret;
if (SYMBOL_P(arg)) {
- arg = rb_sym_to_s(arg);
+ arg = rb_sym2str(arg);
goto str;
}
else if (!NIL_P(tmp = rb_check_string_type(arg))) {
arg = tmp;
str:
- rb_check_safe_obj(arg);
ptr = RSTRING_PTR(arg);
if (str_to_int(ptr, RSTRING_LEN(arg), &ret) == -1)
rb_raise(rb_eSocket, "%s: %s", errmsg, ptr);
@@ -105,7 +104,7 @@ rsock_cmsg_type_arg(int family, int level, VALUE type)
return constant_arg(type, rsock_scm_optname_to_int, "unknown UNIX control message");
case IPPROTO_IP:
return constant_arg(type, rsock_ip_optname_to_int, "unknown IP control message");
-#ifdef INET6
+#ifdef IPPROTO_IPV6
case IPPROTO_IPV6:
return constant_arg(type, rsock_ipv6_optname_to_int, "unknown IPv6 control message");
#endif
diff --git a/ext/socket/depend b/ext/socket/depend
index 1716f9cb89..99617e2532 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -1,25 +1,2864 @@
-SOCK_HEADERS = $(srcdir)/rubysocket.h $(hdrdir)/ruby/ruby.h $(arch_hdrdir)/ruby/config.h \
- $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/io.h $(hdrdir)/ruby/thread.h \
- $(srcdir)/addrinfo.h $(srcdir)/sockport.h constdefs.h $(top_srcdir)/internal.h
+srcs: constdefs.h constdefs.c
-init.o: init.c $(SOCK_HEADERS)
-constants.o: constants.c constdefs.c $(SOCK_HEADERS)
-basicsocket.o: basicsocket.c $(SOCK_HEADERS)
-socket.o: socket.c $(SOCK_HEADERS)
-ipsocket.o: ipsocket.c $(SOCK_HEADERS)
-tcpsocket.o: tcpsocket.c $(SOCK_HEADERS)
-tcpserver.o: tcpserver.c $(SOCK_HEADERS)
-sockssocket.o: sockssocket.c $(SOCK_HEADERS)
-udpsocket.o: udpsocket.c $(SOCK_HEADERS)
-unixsocket.o: unixsocket.c $(SOCK_HEADERS)
-unixserver.o: unixserver.c $(SOCK_HEADERS)
-option.o: option.c $(SOCK_HEADERS)
-ancdata.o: ancdata.c $(SOCK_HEADERS)
-raddrinfo.o: raddrinfo.c $(SOCK_HEADERS)
-
-getnameinfo.o: getnameinfo.c $(arch_hdrdir)/ruby/config.h addrinfo.h sockport.h
+getnameinfo.o: getnameinfo.c $(arch_hdrdir)/ruby/config.h addrinfo.h sockport.h rubysocket.h
getaddrinfo.o: getaddrinfo.c $(arch_hdrdir)/ruby/config.h addrinfo.h sockport.h
-constdefs.h constdefs.c : $(srcdir)/mkconstants.rb
+constdefs.h: $(srcdir)/mkconstants.rb
@echo "generating constant definitions"
@$(RUBY) $(srcdir)/mkconstants.rb -H constdefs.h -o constdefs.c
+
+constdefs.c: constdefs.h
+
+# AUTOGENERATED DEPENDENCIES START
+ancdata.o: $(RUBY_EXTCONF_H)
+ancdata.o: $(arch_hdrdir)/ruby/config.h
+ancdata.o: $(hdrdir)/ruby/assert.h
+ancdata.o: $(hdrdir)/ruby/backward.h
+ancdata.o: $(hdrdir)/ruby/backward/2/assume.h
+ancdata.o: $(hdrdir)/ruby/backward/2/attributes.h
+ancdata.o: $(hdrdir)/ruby/backward/2/bool.h
+ancdata.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+ancdata.o: $(hdrdir)/ruby/backward/2/inttypes.h
+ancdata.o: $(hdrdir)/ruby/backward/2/limits.h
+ancdata.o: $(hdrdir)/ruby/backward/2/long_long.h
+ancdata.o: $(hdrdir)/ruby/backward/2/stdalign.h
+ancdata.o: $(hdrdir)/ruby/backward/2/stdarg.h
+ancdata.o: $(hdrdir)/ruby/defines.h
+ancdata.o: $(hdrdir)/ruby/encoding.h
+ancdata.o: $(hdrdir)/ruby/fiber/scheduler.h
+ancdata.o: $(hdrdir)/ruby/intern.h
+ancdata.o: $(hdrdir)/ruby/internal/anyargs.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+ancdata.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+ancdata.o: $(hdrdir)/ruby/internal/assume.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/artificial.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/cold.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/const.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/error.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/format.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/noalias.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/noinline.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/pure.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/restrict.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/warning.h
+ancdata.o: $(hdrdir)/ruby/internal/attr/weakref.h
+ancdata.o: $(hdrdir)/ruby/internal/cast.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+ancdata.o: $(hdrdir)/ruby/internal/compiler_since.h
+ancdata.o: $(hdrdir)/ruby/internal/config.h
+ancdata.o: $(hdrdir)/ruby/internal/constant_p.h
+ancdata.o: $(hdrdir)/ruby/internal/core.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rarray.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rbasic.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rbignum.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rclass.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rdata.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rfile.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rhash.h
+ancdata.o: $(hdrdir)/ruby/internal/core/robject.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rregexp.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rstring.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rstruct.h
+ancdata.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+ancdata.o: $(hdrdir)/ruby/internal/ctype.h
+ancdata.o: $(hdrdir)/ruby/internal/dllexport.h
+ancdata.o: $(hdrdir)/ruby/internal/dosish.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/re.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/string.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+ancdata.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+ancdata.o: $(hdrdir)/ruby/internal/error.h
+ancdata.o: $(hdrdir)/ruby/internal/eval.h
+ancdata.o: $(hdrdir)/ruby/internal/event.h
+ancdata.o: $(hdrdir)/ruby/internal/fl_type.h
+ancdata.o: $(hdrdir)/ruby/internal/gc.h
+ancdata.o: $(hdrdir)/ruby/internal/glob.h
+ancdata.o: $(hdrdir)/ruby/internal/globals.h
+ancdata.o: $(hdrdir)/ruby/internal/has/attribute.h
+ancdata.o: $(hdrdir)/ruby/internal/has/builtin.h
+ancdata.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+ancdata.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+ancdata.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+ancdata.o: $(hdrdir)/ruby/internal/has/extension.h
+ancdata.o: $(hdrdir)/ruby/internal/has/feature.h
+ancdata.o: $(hdrdir)/ruby/internal/has/warning.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/array.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/bignum.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/class.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/compar.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/complex.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/cont.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/dir.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/enum.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/error.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/eval.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/file.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/gc.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/hash.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/io.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/load.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/marshal.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/numeric.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/object.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/parse.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/proc.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/process.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/random.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/range.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/rational.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/re.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/ruby.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/select.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/signal.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/string.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/struct.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/thread.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/time.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/variable.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/vm.h
+ancdata.o: $(hdrdir)/ruby/internal/interpreter.h
+ancdata.o: $(hdrdir)/ruby/internal/iterator.h
+ancdata.o: $(hdrdir)/ruby/internal/memory.h
+ancdata.o: $(hdrdir)/ruby/internal/method.h
+ancdata.o: $(hdrdir)/ruby/internal/module.h
+ancdata.o: $(hdrdir)/ruby/internal/newobj.h
+ancdata.o: $(hdrdir)/ruby/internal/rgengc.h
+ancdata.o: $(hdrdir)/ruby/internal/scan_args.h
+ancdata.o: $(hdrdir)/ruby/internal/special_consts.h
+ancdata.o: $(hdrdir)/ruby/internal/static_assert.h
+ancdata.o: $(hdrdir)/ruby/internal/stdalign.h
+ancdata.o: $(hdrdir)/ruby/internal/stdbool.h
+ancdata.o: $(hdrdir)/ruby/internal/symbol.h
+ancdata.o: $(hdrdir)/ruby/internal/value.h
+ancdata.o: $(hdrdir)/ruby/internal/value_type.h
+ancdata.o: $(hdrdir)/ruby/internal/variable.h
+ancdata.o: $(hdrdir)/ruby/internal/warning_push.h
+ancdata.o: $(hdrdir)/ruby/internal/xmalloc.h
+ancdata.o: $(hdrdir)/ruby/io.h
+ancdata.o: $(hdrdir)/ruby/missing.h
+ancdata.o: $(hdrdir)/ruby/onigmo.h
+ancdata.o: $(hdrdir)/ruby/oniguruma.h
+ancdata.o: $(hdrdir)/ruby/ruby.h
+ancdata.o: $(hdrdir)/ruby/st.h
+ancdata.o: $(hdrdir)/ruby/subst.h
+ancdata.o: $(hdrdir)/ruby/thread.h
+ancdata.o: $(hdrdir)/ruby/util.h
+ancdata.o: $(top_srcdir)/internal.h
+ancdata.o: $(top_srcdir)/internal/array.h
+ancdata.o: $(top_srcdir)/internal/compilers.h
+ancdata.o: $(top_srcdir)/internal/error.h
+ancdata.o: $(top_srcdir)/internal/gc.h
+ancdata.o: $(top_srcdir)/internal/io.h
+ancdata.o: $(top_srcdir)/internal/serial.h
+ancdata.o: $(top_srcdir)/internal/static_assert.h
+ancdata.o: $(top_srcdir)/internal/string.h
+ancdata.o: $(top_srcdir)/internal/thread.h
+ancdata.o: $(top_srcdir)/internal/vm.h
+ancdata.o: $(top_srcdir)/internal/warnings.h
+ancdata.o: ancdata.c
+ancdata.o: constdefs.h
+ancdata.o: rubysocket.h
+ancdata.o: sockport.h
+basicsocket.o: $(RUBY_EXTCONF_H)
+basicsocket.o: $(arch_hdrdir)/ruby/config.h
+basicsocket.o: $(hdrdir)/ruby/assert.h
+basicsocket.o: $(hdrdir)/ruby/backward.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/assume.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/bool.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/limits.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+basicsocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+basicsocket.o: $(hdrdir)/ruby/defines.h
+basicsocket.o: $(hdrdir)/ruby/encoding.h
+basicsocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+basicsocket.o: $(hdrdir)/ruby/intern.h
+basicsocket.o: $(hdrdir)/ruby/internal/anyargs.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+basicsocket.o: $(hdrdir)/ruby/internal/assume.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/const.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/error.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/format.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+basicsocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+basicsocket.o: $(hdrdir)/ruby/internal/cast.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+basicsocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+basicsocket.o: $(hdrdir)/ruby/internal/config.h
+basicsocket.o: $(hdrdir)/ruby/internal/constant_p.h
+basicsocket.o: $(hdrdir)/ruby/internal/core.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/robject.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+basicsocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+basicsocket.o: $(hdrdir)/ruby/internal/ctype.h
+basicsocket.o: $(hdrdir)/ruby/internal/dllexport.h
+basicsocket.o: $(hdrdir)/ruby/internal/dosish.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+basicsocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+basicsocket.o: $(hdrdir)/ruby/internal/error.h
+basicsocket.o: $(hdrdir)/ruby/internal/eval.h
+basicsocket.o: $(hdrdir)/ruby/internal/event.h
+basicsocket.o: $(hdrdir)/ruby/internal/fl_type.h
+basicsocket.o: $(hdrdir)/ruby/internal/gc.h
+basicsocket.o: $(hdrdir)/ruby/internal/glob.h
+basicsocket.o: $(hdrdir)/ruby/internal/globals.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/extension.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/feature.h
+basicsocket.o: $(hdrdir)/ruby/internal/has/warning.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/array.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/class.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/error.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/io.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/load.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/object.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/process.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/random.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/range.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/re.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/select.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/string.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/time.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+basicsocket.o: $(hdrdir)/ruby/internal/interpreter.h
+basicsocket.o: $(hdrdir)/ruby/internal/iterator.h
+basicsocket.o: $(hdrdir)/ruby/internal/memory.h
+basicsocket.o: $(hdrdir)/ruby/internal/method.h
+basicsocket.o: $(hdrdir)/ruby/internal/module.h
+basicsocket.o: $(hdrdir)/ruby/internal/newobj.h
+basicsocket.o: $(hdrdir)/ruby/internal/rgengc.h
+basicsocket.o: $(hdrdir)/ruby/internal/scan_args.h
+basicsocket.o: $(hdrdir)/ruby/internal/special_consts.h
+basicsocket.o: $(hdrdir)/ruby/internal/static_assert.h
+basicsocket.o: $(hdrdir)/ruby/internal/stdalign.h
+basicsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+basicsocket.o: $(hdrdir)/ruby/internal/symbol.h
+basicsocket.o: $(hdrdir)/ruby/internal/value.h
+basicsocket.o: $(hdrdir)/ruby/internal/value_type.h
+basicsocket.o: $(hdrdir)/ruby/internal/variable.h
+basicsocket.o: $(hdrdir)/ruby/internal/warning_push.h
+basicsocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+basicsocket.o: $(hdrdir)/ruby/io.h
+basicsocket.o: $(hdrdir)/ruby/missing.h
+basicsocket.o: $(hdrdir)/ruby/onigmo.h
+basicsocket.o: $(hdrdir)/ruby/oniguruma.h
+basicsocket.o: $(hdrdir)/ruby/ruby.h
+basicsocket.o: $(hdrdir)/ruby/st.h
+basicsocket.o: $(hdrdir)/ruby/subst.h
+basicsocket.o: $(hdrdir)/ruby/thread.h
+basicsocket.o: $(hdrdir)/ruby/util.h
+basicsocket.o: $(top_srcdir)/internal.h
+basicsocket.o: $(top_srcdir)/internal/array.h
+basicsocket.o: $(top_srcdir)/internal/compilers.h
+basicsocket.o: $(top_srcdir)/internal/error.h
+basicsocket.o: $(top_srcdir)/internal/gc.h
+basicsocket.o: $(top_srcdir)/internal/io.h
+basicsocket.o: $(top_srcdir)/internal/serial.h
+basicsocket.o: $(top_srcdir)/internal/static_assert.h
+basicsocket.o: $(top_srcdir)/internal/string.h
+basicsocket.o: $(top_srcdir)/internal/thread.h
+basicsocket.o: $(top_srcdir)/internal/vm.h
+basicsocket.o: $(top_srcdir)/internal/warnings.h
+basicsocket.o: basicsocket.c
+basicsocket.o: constdefs.h
+basicsocket.o: rubysocket.h
+basicsocket.o: sockport.h
+constants.o: $(RUBY_EXTCONF_H)
+constants.o: $(arch_hdrdir)/ruby/config.h
+constants.o: $(hdrdir)/ruby/assert.h
+constants.o: $(hdrdir)/ruby/backward.h
+constants.o: $(hdrdir)/ruby/backward/2/assume.h
+constants.o: $(hdrdir)/ruby/backward/2/attributes.h
+constants.o: $(hdrdir)/ruby/backward/2/bool.h
+constants.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+constants.o: $(hdrdir)/ruby/backward/2/inttypes.h
+constants.o: $(hdrdir)/ruby/backward/2/limits.h
+constants.o: $(hdrdir)/ruby/backward/2/long_long.h
+constants.o: $(hdrdir)/ruby/backward/2/stdalign.h
+constants.o: $(hdrdir)/ruby/backward/2/stdarg.h
+constants.o: $(hdrdir)/ruby/defines.h
+constants.o: $(hdrdir)/ruby/encoding.h
+constants.o: $(hdrdir)/ruby/fiber/scheduler.h
+constants.o: $(hdrdir)/ruby/intern.h
+constants.o: $(hdrdir)/ruby/internal/anyargs.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+constants.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+constants.o: $(hdrdir)/ruby/internal/assume.h
+constants.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+constants.o: $(hdrdir)/ruby/internal/attr/artificial.h
+constants.o: $(hdrdir)/ruby/internal/attr/cold.h
+constants.o: $(hdrdir)/ruby/internal/attr/const.h
+constants.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+constants.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+constants.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+constants.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+constants.o: $(hdrdir)/ruby/internal/attr/error.h
+constants.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+constants.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+constants.o: $(hdrdir)/ruby/internal/attr/format.h
+constants.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+constants.o: $(hdrdir)/ruby/internal/attr/noalias.h
+constants.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+constants.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+constants.o: $(hdrdir)/ruby/internal/attr/noinline.h
+constants.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+constants.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+constants.o: $(hdrdir)/ruby/internal/attr/pure.h
+constants.o: $(hdrdir)/ruby/internal/attr/restrict.h
+constants.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+constants.o: $(hdrdir)/ruby/internal/attr/warning.h
+constants.o: $(hdrdir)/ruby/internal/attr/weakref.h
+constants.o: $(hdrdir)/ruby/internal/cast.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+constants.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+constants.o: $(hdrdir)/ruby/internal/compiler_since.h
+constants.o: $(hdrdir)/ruby/internal/config.h
+constants.o: $(hdrdir)/ruby/internal/constant_p.h
+constants.o: $(hdrdir)/ruby/internal/core.h
+constants.o: $(hdrdir)/ruby/internal/core/rarray.h
+constants.o: $(hdrdir)/ruby/internal/core/rbasic.h
+constants.o: $(hdrdir)/ruby/internal/core/rbignum.h
+constants.o: $(hdrdir)/ruby/internal/core/rclass.h
+constants.o: $(hdrdir)/ruby/internal/core/rdata.h
+constants.o: $(hdrdir)/ruby/internal/core/rfile.h
+constants.o: $(hdrdir)/ruby/internal/core/rhash.h
+constants.o: $(hdrdir)/ruby/internal/core/robject.h
+constants.o: $(hdrdir)/ruby/internal/core/rregexp.h
+constants.o: $(hdrdir)/ruby/internal/core/rstring.h
+constants.o: $(hdrdir)/ruby/internal/core/rstruct.h
+constants.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+constants.o: $(hdrdir)/ruby/internal/ctype.h
+constants.o: $(hdrdir)/ruby/internal/dllexport.h
+constants.o: $(hdrdir)/ruby/internal/dosish.h
+constants.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+constants.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+constants.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+constants.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+constants.o: $(hdrdir)/ruby/internal/encoding/re.h
+constants.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+constants.o: $(hdrdir)/ruby/internal/encoding/string.h
+constants.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+constants.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+constants.o: $(hdrdir)/ruby/internal/error.h
+constants.o: $(hdrdir)/ruby/internal/eval.h
+constants.o: $(hdrdir)/ruby/internal/event.h
+constants.o: $(hdrdir)/ruby/internal/fl_type.h
+constants.o: $(hdrdir)/ruby/internal/gc.h
+constants.o: $(hdrdir)/ruby/internal/glob.h
+constants.o: $(hdrdir)/ruby/internal/globals.h
+constants.o: $(hdrdir)/ruby/internal/has/attribute.h
+constants.o: $(hdrdir)/ruby/internal/has/builtin.h
+constants.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+constants.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+constants.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+constants.o: $(hdrdir)/ruby/internal/has/extension.h
+constants.o: $(hdrdir)/ruby/internal/has/feature.h
+constants.o: $(hdrdir)/ruby/internal/has/warning.h
+constants.o: $(hdrdir)/ruby/internal/intern/array.h
+constants.o: $(hdrdir)/ruby/internal/intern/bignum.h
+constants.o: $(hdrdir)/ruby/internal/intern/class.h
+constants.o: $(hdrdir)/ruby/internal/intern/compar.h
+constants.o: $(hdrdir)/ruby/internal/intern/complex.h
+constants.o: $(hdrdir)/ruby/internal/intern/cont.h
+constants.o: $(hdrdir)/ruby/internal/intern/dir.h
+constants.o: $(hdrdir)/ruby/internal/intern/enum.h
+constants.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+constants.o: $(hdrdir)/ruby/internal/intern/error.h
+constants.o: $(hdrdir)/ruby/internal/intern/eval.h
+constants.o: $(hdrdir)/ruby/internal/intern/file.h
+constants.o: $(hdrdir)/ruby/internal/intern/gc.h
+constants.o: $(hdrdir)/ruby/internal/intern/hash.h
+constants.o: $(hdrdir)/ruby/internal/intern/io.h
+constants.o: $(hdrdir)/ruby/internal/intern/load.h
+constants.o: $(hdrdir)/ruby/internal/intern/marshal.h
+constants.o: $(hdrdir)/ruby/internal/intern/numeric.h
+constants.o: $(hdrdir)/ruby/internal/intern/object.h
+constants.o: $(hdrdir)/ruby/internal/intern/parse.h
+constants.o: $(hdrdir)/ruby/internal/intern/proc.h
+constants.o: $(hdrdir)/ruby/internal/intern/process.h
+constants.o: $(hdrdir)/ruby/internal/intern/random.h
+constants.o: $(hdrdir)/ruby/internal/intern/range.h
+constants.o: $(hdrdir)/ruby/internal/intern/rational.h
+constants.o: $(hdrdir)/ruby/internal/intern/re.h
+constants.o: $(hdrdir)/ruby/internal/intern/ruby.h
+constants.o: $(hdrdir)/ruby/internal/intern/select.h
+constants.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+constants.o: $(hdrdir)/ruby/internal/intern/signal.h
+constants.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+constants.o: $(hdrdir)/ruby/internal/intern/string.h
+constants.o: $(hdrdir)/ruby/internal/intern/struct.h
+constants.o: $(hdrdir)/ruby/internal/intern/thread.h
+constants.o: $(hdrdir)/ruby/internal/intern/time.h
+constants.o: $(hdrdir)/ruby/internal/intern/variable.h
+constants.o: $(hdrdir)/ruby/internal/intern/vm.h
+constants.o: $(hdrdir)/ruby/internal/interpreter.h
+constants.o: $(hdrdir)/ruby/internal/iterator.h
+constants.o: $(hdrdir)/ruby/internal/memory.h
+constants.o: $(hdrdir)/ruby/internal/method.h
+constants.o: $(hdrdir)/ruby/internal/module.h
+constants.o: $(hdrdir)/ruby/internal/newobj.h
+constants.o: $(hdrdir)/ruby/internal/rgengc.h
+constants.o: $(hdrdir)/ruby/internal/scan_args.h
+constants.o: $(hdrdir)/ruby/internal/special_consts.h
+constants.o: $(hdrdir)/ruby/internal/static_assert.h
+constants.o: $(hdrdir)/ruby/internal/stdalign.h
+constants.o: $(hdrdir)/ruby/internal/stdbool.h
+constants.o: $(hdrdir)/ruby/internal/symbol.h
+constants.o: $(hdrdir)/ruby/internal/value.h
+constants.o: $(hdrdir)/ruby/internal/value_type.h
+constants.o: $(hdrdir)/ruby/internal/variable.h
+constants.o: $(hdrdir)/ruby/internal/warning_push.h
+constants.o: $(hdrdir)/ruby/internal/xmalloc.h
+constants.o: $(hdrdir)/ruby/io.h
+constants.o: $(hdrdir)/ruby/missing.h
+constants.o: $(hdrdir)/ruby/onigmo.h
+constants.o: $(hdrdir)/ruby/oniguruma.h
+constants.o: $(hdrdir)/ruby/ruby.h
+constants.o: $(hdrdir)/ruby/st.h
+constants.o: $(hdrdir)/ruby/subst.h
+constants.o: $(hdrdir)/ruby/thread.h
+constants.o: $(hdrdir)/ruby/util.h
+constants.o: $(top_srcdir)/internal.h
+constants.o: $(top_srcdir)/internal/array.h
+constants.o: $(top_srcdir)/internal/compilers.h
+constants.o: $(top_srcdir)/internal/error.h
+constants.o: $(top_srcdir)/internal/gc.h
+constants.o: $(top_srcdir)/internal/io.h
+constants.o: $(top_srcdir)/internal/serial.h
+constants.o: $(top_srcdir)/internal/static_assert.h
+constants.o: $(top_srcdir)/internal/string.h
+constants.o: $(top_srcdir)/internal/thread.h
+constants.o: $(top_srcdir)/internal/vm.h
+constants.o: $(top_srcdir)/internal/warnings.h
+constants.o: constants.c
+constants.o: constdefs.c
+constants.o: constdefs.h
+constants.o: rubysocket.h
+constants.o: sockport.h
+ifaddr.o: $(RUBY_EXTCONF_H)
+ifaddr.o: $(arch_hdrdir)/ruby/config.h
+ifaddr.o: $(hdrdir)/ruby/assert.h
+ifaddr.o: $(hdrdir)/ruby/backward.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/assume.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/attributes.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/bool.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/inttypes.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/limits.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/long_long.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/stdalign.h
+ifaddr.o: $(hdrdir)/ruby/backward/2/stdarg.h
+ifaddr.o: $(hdrdir)/ruby/defines.h
+ifaddr.o: $(hdrdir)/ruby/encoding.h
+ifaddr.o: $(hdrdir)/ruby/fiber/scheduler.h
+ifaddr.o: $(hdrdir)/ruby/intern.h
+ifaddr.o: $(hdrdir)/ruby/internal/anyargs.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+ifaddr.o: $(hdrdir)/ruby/internal/assume.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/artificial.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/cold.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/const.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/error.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/format.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/noalias.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/noinline.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/pure.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/restrict.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/warning.h
+ifaddr.o: $(hdrdir)/ruby/internal/attr/weakref.h
+ifaddr.o: $(hdrdir)/ruby/internal/cast.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+ifaddr.o: $(hdrdir)/ruby/internal/compiler_since.h
+ifaddr.o: $(hdrdir)/ruby/internal/config.h
+ifaddr.o: $(hdrdir)/ruby/internal/constant_p.h
+ifaddr.o: $(hdrdir)/ruby/internal/core.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rarray.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rbasic.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rbignum.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rclass.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rdata.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rfile.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rhash.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/robject.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rregexp.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rstring.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rstruct.h
+ifaddr.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+ifaddr.o: $(hdrdir)/ruby/internal/ctype.h
+ifaddr.o: $(hdrdir)/ruby/internal/dllexport.h
+ifaddr.o: $(hdrdir)/ruby/internal/dosish.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/re.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/string.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+ifaddr.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+ifaddr.o: $(hdrdir)/ruby/internal/error.h
+ifaddr.o: $(hdrdir)/ruby/internal/eval.h
+ifaddr.o: $(hdrdir)/ruby/internal/event.h
+ifaddr.o: $(hdrdir)/ruby/internal/fl_type.h
+ifaddr.o: $(hdrdir)/ruby/internal/gc.h
+ifaddr.o: $(hdrdir)/ruby/internal/glob.h
+ifaddr.o: $(hdrdir)/ruby/internal/globals.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/attribute.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/builtin.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/extension.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/feature.h
+ifaddr.o: $(hdrdir)/ruby/internal/has/warning.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/array.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/bignum.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/class.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/compar.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/complex.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/cont.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/dir.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/enum.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/error.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/eval.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/file.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/gc.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/hash.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/io.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/load.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/marshal.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/numeric.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/object.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/parse.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/proc.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/process.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/random.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/range.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/rational.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/re.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/ruby.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/select.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/signal.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/string.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/struct.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/thread.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/time.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/variable.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/vm.h
+ifaddr.o: $(hdrdir)/ruby/internal/interpreter.h
+ifaddr.o: $(hdrdir)/ruby/internal/iterator.h
+ifaddr.o: $(hdrdir)/ruby/internal/memory.h
+ifaddr.o: $(hdrdir)/ruby/internal/method.h
+ifaddr.o: $(hdrdir)/ruby/internal/module.h
+ifaddr.o: $(hdrdir)/ruby/internal/newobj.h
+ifaddr.o: $(hdrdir)/ruby/internal/rgengc.h
+ifaddr.o: $(hdrdir)/ruby/internal/scan_args.h
+ifaddr.o: $(hdrdir)/ruby/internal/special_consts.h
+ifaddr.o: $(hdrdir)/ruby/internal/static_assert.h
+ifaddr.o: $(hdrdir)/ruby/internal/stdalign.h
+ifaddr.o: $(hdrdir)/ruby/internal/stdbool.h
+ifaddr.o: $(hdrdir)/ruby/internal/symbol.h
+ifaddr.o: $(hdrdir)/ruby/internal/value.h
+ifaddr.o: $(hdrdir)/ruby/internal/value_type.h
+ifaddr.o: $(hdrdir)/ruby/internal/variable.h
+ifaddr.o: $(hdrdir)/ruby/internal/warning_push.h
+ifaddr.o: $(hdrdir)/ruby/internal/xmalloc.h
+ifaddr.o: $(hdrdir)/ruby/io.h
+ifaddr.o: $(hdrdir)/ruby/missing.h
+ifaddr.o: $(hdrdir)/ruby/onigmo.h
+ifaddr.o: $(hdrdir)/ruby/oniguruma.h
+ifaddr.o: $(hdrdir)/ruby/ruby.h
+ifaddr.o: $(hdrdir)/ruby/st.h
+ifaddr.o: $(hdrdir)/ruby/subst.h
+ifaddr.o: $(hdrdir)/ruby/thread.h
+ifaddr.o: $(hdrdir)/ruby/util.h
+ifaddr.o: $(top_srcdir)/internal.h
+ifaddr.o: $(top_srcdir)/internal/array.h
+ifaddr.o: $(top_srcdir)/internal/compilers.h
+ifaddr.o: $(top_srcdir)/internal/error.h
+ifaddr.o: $(top_srcdir)/internal/gc.h
+ifaddr.o: $(top_srcdir)/internal/io.h
+ifaddr.o: $(top_srcdir)/internal/serial.h
+ifaddr.o: $(top_srcdir)/internal/static_assert.h
+ifaddr.o: $(top_srcdir)/internal/string.h
+ifaddr.o: $(top_srcdir)/internal/thread.h
+ifaddr.o: $(top_srcdir)/internal/vm.h
+ifaddr.o: $(top_srcdir)/internal/warnings.h
+ifaddr.o: constdefs.h
+ifaddr.o: ifaddr.c
+ifaddr.o: rubysocket.h
+ifaddr.o: sockport.h
+init.o: $(RUBY_EXTCONF_H)
+init.o: $(arch_hdrdir)/ruby/config.h
+init.o: $(hdrdir)/ruby/assert.h
+init.o: $(hdrdir)/ruby/backward.h
+init.o: $(hdrdir)/ruby/backward/2/assume.h
+init.o: $(hdrdir)/ruby/backward/2/attributes.h
+init.o: $(hdrdir)/ruby/backward/2/bool.h
+init.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+init.o: $(hdrdir)/ruby/backward/2/inttypes.h
+init.o: $(hdrdir)/ruby/backward/2/limits.h
+init.o: $(hdrdir)/ruby/backward/2/long_long.h
+init.o: $(hdrdir)/ruby/backward/2/stdalign.h
+init.o: $(hdrdir)/ruby/backward/2/stdarg.h
+init.o: $(hdrdir)/ruby/defines.h
+init.o: $(hdrdir)/ruby/encoding.h
+init.o: $(hdrdir)/ruby/fiber/scheduler.h
+init.o: $(hdrdir)/ruby/intern.h
+init.o: $(hdrdir)/ruby/internal/anyargs.h
+init.o: $(hdrdir)/ruby/internal/arithmetic.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+init.o: $(hdrdir)/ruby/internal/assume.h
+init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+init.o: $(hdrdir)/ruby/internal/attr/artificial.h
+init.o: $(hdrdir)/ruby/internal/attr/cold.h
+init.o: $(hdrdir)/ruby/internal/attr/const.h
+init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+init.o: $(hdrdir)/ruby/internal/attr/error.h
+init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+init.o: $(hdrdir)/ruby/internal/attr/format.h
+init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+init.o: $(hdrdir)/ruby/internal/attr/noalias.h
+init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+init.o: $(hdrdir)/ruby/internal/attr/noinline.h
+init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+init.o: $(hdrdir)/ruby/internal/attr/pure.h
+init.o: $(hdrdir)/ruby/internal/attr/restrict.h
+init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+init.o: $(hdrdir)/ruby/internal/attr/warning.h
+init.o: $(hdrdir)/ruby/internal/attr/weakref.h
+init.o: $(hdrdir)/ruby/internal/cast.h
+init.o: $(hdrdir)/ruby/internal/compiler_is.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+init.o: $(hdrdir)/ruby/internal/compiler_since.h
+init.o: $(hdrdir)/ruby/internal/config.h
+init.o: $(hdrdir)/ruby/internal/constant_p.h
+init.o: $(hdrdir)/ruby/internal/core.h
+init.o: $(hdrdir)/ruby/internal/core/rarray.h
+init.o: $(hdrdir)/ruby/internal/core/rbasic.h
+init.o: $(hdrdir)/ruby/internal/core/rbignum.h
+init.o: $(hdrdir)/ruby/internal/core/rclass.h
+init.o: $(hdrdir)/ruby/internal/core/rdata.h
+init.o: $(hdrdir)/ruby/internal/core/rfile.h
+init.o: $(hdrdir)/ruby/internal/core/rhash.h
+init.o: $(hdrdir)/ruby/internal/core/robject.h
+init.o: $(hdrdir)/ruby/internal/core/rregexp.h
+init.o: $(hdrdir)/ruby/internal/core/rstring.h
+init.o: $(hdrdir)/ruby/internal/core/rstruct.h
+init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+init.o: $(hdrdir)/ruby/internal/ctype.h
+init.o: $(hdrdir)/ruby/internal/dllexport.h
+init.o: $(hdrdir)/ruby/internal/dosish.h
+init.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+init.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+init.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+init.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+init.o: $(hdrdir)/ruby/internal/encoding/re.h
+init.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+init.o: $(hdrdir)/ruby/internal/encoding/string.h
+init.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+init.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+init.o: $(hdrdir)/ruby/internal/error.h
+init.o: $(hdrdir)/ruby/internal/eval.h
+init.o: $(hdrdir)/ruby/internal/event.h
+init.o: $(hdrdir)/ruby/internal/fl_type.h
+init.o: $(hdrdir)/ruby/internal/gc.h
+init.o: $(hdrdir)/ruby/internal/glob.h
+init.o: $(hdrdir)/ruby/internal/globals.h
+init.o: $(hdrdir)/ruby/internal/has/attribute.h
+init.o: $(hdrdir)/ruby/internal/has/builtin.h
+init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/extension.h
+init.o: $(hdrdir)/ruby/internal/has/feature.h
+init.o: $(hdrdir)/ruby/internal/has/warning.h
+init.o: $(hdrdir)/ruby/internal/intern/array.h
+init.o: $(hdrdir)/ruby/internal/intern/bignum.h
+init.o: $(hdrdir)/ruby/internal/intern/class.h
+init.o: $(hdrdir)/ruby/internal/intern/compar.h
+init.o: $(hdrdir)/ruby/internal/intern/complex.h
+init.o: $(hdrdir)/ruby/internal/intern/cont.h
+init.o: $(hdrdir)/ruby/internal/intern/dir.h
+init.o: $(hdrdir)/ruby/internal/intern/enum.h
+init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+init.o: $(hdrdir)/ruby/internal/intern/error.h
+init.o: $(hdrdir)/ruby/internal/intern/eval.h
+init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
+init.o: $(hdrdir)/ruby/internal/intern/hash.h
+init.o: $(hdrdir)/ruby/internal/intern/io.h
+init.o: $(hdrdir)/ruby/internal/intern/load.h
+init.o: $(hdrdir)/ruby/internal/intern/marshal.h
+init.o: $(hdrdir)/ruby/internal/intern/numeric.h
+init.o: $(hdrdir)/ruby/internal/intern/object.h
+init.o: $(hdrdir)/ruby/internal/intern/parse.h
+init.o: $(hdrdir)/ruby/internal/intern/proc.h
+init.o: $(hdrdir)/ruby/internal/intern/process.h
+init.o: $(hdrdir)/ruby/internal/intern/random.h
+init.o: $(hdrdir)/ruby/internal/intern/range.h
+init.o: $(hdrdir)/ruby/internal/intern/rational.h
+init.o: $(hdrdir)/ruby/internal/intern/re.h
+init.o: $(hdrdir)/ruby/internal/intern/ruby.h
+init.o: $(hdrdir)/ruby/internal/intern/select.h
+init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/signal.h
+init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+init.o: $(hdrdir)/ruby/internal/intern/string.h
+init.o: $(hdrdir)/ruby/internal/intern/struct.h
+init.o: $(hdrdir)/ruby/internal/intern/thread.h
+init.o: $(hdrdir)/ruby/internal/intern/time.h
+init.o: $(hdrdir)/ruby/internal/intern/variable.h
+init.o: $(hdrdir)/ruby/internal/intern/vm.h
+init.o: $(hdrdir)/ruby/internal/interpreter.h
+init.o: $(hdrdir)/ruby/internal/iterator.h
+init.o: $(hdrdir)/ruby/internal/memory.h
+init.o: $(hdrdir)/ruby/internal/method.h
+init.o: $(hdrdir)/ruby/internal/module.h
+init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
+init.o: $(hdrdir)/ruby/internal/scan_args.h
+init.o: $(hdrdir)/ruby/internal/special_consts.h
+init.o: $(hdrdir)/ruby/internal/static_assert.h
+init.o: $(hdrdir)/ruby/internal/stdalign.h
+init.o: $(hdrdir)/ruby/internal/stdbool.h
+init.o: $(hdrdir)/ruby/internal/symbol.h
+init.o: $(hdrdir)/ruby/internal/value.h
+init.o: $(hdrdir)/ruby/internal/value_type.h
+init.o: $(hdrdir)/ruby/internal/variable.h
+init.o: $(hdrdir)/ruby/internal/warning_push.h
+init.o: $(hdrdir)/ruby/internal/xmalloc.h
+init.o: $(hdrdir)/ruby/io.h
+init.o: $(hdrdir)/ruby/missing.h
+init.o: $(hdrdir)/ruby/onigmo.h
+init.o: $(hdrdir)/ruby/oniguruma.h
+init.o: $(hdrdir)/ruby/ruby.h
+init.o: $(hdrdir)/ruby/st.h
+init.o: $(hdrdir)/ruby/subst.h
+init.o: $(hdrdir)/ruby/thread.h
+init.o: $(hdrdir)/ruby/util.h
+init.o: $(top_srcdir)/internal.h
+init.o: $(top_srcdir)/internal/array.h
+init.o: $(top_srcdir)/internal/compilers.h
+init.o: $(top_srcdir)/internal/error.h
+init.o: $(top_srcdir)/internal/gc.h
+init.o: $(top_srcdir)/internal/io.h
+init.o: $(top_srcdir)/internal/serial.h
+init.o: $(top_srcdir)/internal/static_assert.h
+init.o: $(top_srcdir)/internal/string.h
+init.o: $(top_srcdir)/internal/thread.h
+init.o: $(top_srcdir)/internal/vm.h
+init.o: $(top_srcdir)/internal/warnings.h
+init.o: constdefs.h
+init.o: init.c
+init.o: rubysocket.h
+init.o: sockport.h
+ipsocket.o: $(RUBY_EXTCONF_H)
+ipsocket.o: $(arch_hdrdir)/ruby/config.h
+ipsocket.o: $(hdrdir)/ruby/assert.h
+ipsocket.o: $(hdrdir)/ruby/backward.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/assume.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/bool.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/limits.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+ipsocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+ipsocket.o: $(hdrdir)/ruby/defines.h
+ipsocket.o: $(hdrdir)/ruby/encoding.h
+ipsocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+ipsocket.o: $(hdrdir)/ruby/intern.h
+ipsocket.o: $(hdrdir)/ruby/internal/anyargs.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+ipsocket.o: $(hdrdir)/ruby/internal/assume.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/const.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/error.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/format.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+ipsocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+ipsocket.o: $(hdrdir)/ruby/internal/cast.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+ipsocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+ipsocket.o: $(hdrdir)/ruby/internal/config.h
+ipsocket.o: $(hdrdir)/ruby/internal/constant_p.h
+ipsocket.o: $(hdrdir)/ruby/internal/core.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/robject.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+ipsocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+ipsocket.o: $(hdrdir)/ruby/internal/ctype.h
+ipsocket.o: $(hdrdir)/ruby/internal/dllexport.h
+ipsocket.o: $(hdrdir)/ruby/internal/dosish.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+ipsocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+ipsocket.o: $(hdrdir)/ruby/internal/error.h
+ipsocket.o: $(hdrdir)/ruby/internal/eval.h
+ipsocket.o: $(hdrdir)/ruby/internal/event.h
+ipsocket.o: $(hdrdir)/ruby/internal/fl_type.h
+ipsocket.o: $(hdrdir)/ruby/internal/gc.h
+ipsocket.o: $(hdrdir)/ruby/internal/glob.h
+ipsocket.o: $(hdrdir)/ruby/internal/globals.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/extension.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/feature.h
+ipsocket.o: $(hdrdir)/ruby/internal/has/warning.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/array.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/class.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/error.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/io.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/load.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/object.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/process.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/random.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/range.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/re.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/select.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/string.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/time.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+ipsocket.o: $(hdrdir)/ruby/internal/interpreter.h
+ipsocket.o: $(hdrdir)/ruby/internal/iterator.h
+ipsocket.o: $(hdrdir)/ruby/internal/memory.h
+ipsocket.o: $(hdrdir)/ruby/internal/method.h
+ipsocket.o: $(hdrdir)/ruby/internal/module.h
+ipsocket.o: $(hdrdir)/ruby/internal/newobj.h
+ipsocket.o: $(hdrdir)/ruby/internal/rgengc.h
+ipsocket.o: $(hdrdir)/ruby/internal/scan_args.h
+ipsocket.o: $(hdrdir)/ruby/internal/special_consts.h
+ipsocket.o: $(hdrdir)/ruby/internal/static_assert.h
+ipsocket.o: $(hdrdir)/ruby/internal/stdalign.h
+ipsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+ipsocket.o: $(hdrdir)/ruby/internal/symbol.h
+ipsocket.o: $(hdrdir)/ruby/internal/value.h
+ipsocket.o: $(hdrdir)/ruby/internal/value_type.h
+ipsocket.o: $(hdrdir)/ruby/internal/variable.h
+ipsocket.o: $(hdrdir)/ruby/internal/warning_push.h
+ipsocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+ipsocket.o: $(hdrdir)/ruby/io.h
+ipsocket.o: $(hdrdir)/ruby/missing.h
+ipsocket.o: $(hdrdir)/ruby/onigmo.h
+ipsocket.o: $(hdrdir)/ruby/oniguruma.h
+ipsocket.o: $(hdrdir)/ruby/ruby.h
+ipsocket.o: $(hdrdir)/ruby/st.h
+ipsocket.o: $(hdrdir)/ruby/subst.h
+ipsocket.o: $(hdrdir)/ruby/thread.h
+ipsocket.o: $(hdrdir)/ruby/util.h
+ipsocket.o: $(top_srcdir)/internal.h
+ipsocket.o: $(top_srcdir)/internal/array.h
+ipsocket.o: $(top_srcdir)/internal/compilers.h
+ipsocket.o: $(top_srcdir)/internal/error.h
+ipsocket.o: $(top_srcdir)/internal/gc.h
+ipsocket.o: $(top_srcdir)/internal/io.h
+ipsocket.o: $(top_srcdir)/internal/serial.h
+ipsocket.o: $(top_srcdir)/internal/static_assert.h
+ipsocket.o: $(top_srcdir)/internal/string.h
+ipsocket.o: $(top_srcdir)/internal/thread.h
+ipsocket.o: $(top_srcdir)/internal/vm.h
+ipsocket.o: $(top_srcdir)/internal/warnings.h
+ipsocket.o: constdefs.h
+ipsocket.o: ipsocket.c
+ipsocket.o: rubysocket.h
+ipsocket.o: sockport.h
+option.o: $(RUBY_EXTCONF_H)
+option.o: $(arch_hdrdir)/ruby/config.h
+option.o: $(hdrdir)/ruby/assert.h
+option.o: $(hdrdir)/ruby/backward.h
+option.o: $(hdrdir)/ruby/backward/2/assume.h
+option.o: $(hdrdir)/ruby/backward/2/attributes.h
+option.o: $(hdrdir)/ruby/backward/2/bool.h
+option.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+option.o: $(hdrdir)/ruby/backward/2/inttypes.h
+option.o: $(hdrdir)/ruby/backward/2/limits.h
+option.o: $(hdrdir)/ruby/backward/2/long_long.h
+option.o: $(hdrdir)/ruby/backward/2/stdalign.h
+option.o: $(hdrdir)/ruby/backward/2/stdarg.h
+option.o: $(hdrdir)/ruby/defines.h
+option.o: $(hdrdir)/ruby/encoding.h
+option.o: $(hdrdir)/ruby/fiber/scheduler.h
+option.o: $(hdrdir)/ruby/intern.h
+option.o: $(hdrdir)/ruby/internal/anyargs.h
+option.o: $(hdrdir)/ruby/internal/arithmetic.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+option.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+option.o: $(hdrdir)/ruby/internal/assume.h
+option.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+option.o: $(hdrdir)/ruby/internal/attr/artificial.h
+option.o: $(hdrdir)/ruby/internal/attr/cold.h
+option.o: $(hdrdir)/ruby/internal/attr/const.h
+option.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+option.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+option.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+option.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+option.o: $(hdrdir)/ruby/internal/attr/error.h
+option.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+option.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+option.o: $(hdrdir)/ruby/internal/attr/format.h
+option.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+option.o: $(hdrdir)/ruby/internal/attr/noalias.h
+option.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+option.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+option.o: $(hdrdir)/ruby/internal/attr/noinline.h
+option.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+option.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+option.o: $(hdrdir)/ruby/internal/attr/pure.h
+option.o: $(hdrdir)/ruby/internal/attr/restrict.h
+option.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+option.o: $(hdrdir)/ruby/internal/attr/warning.h
+option.o: $(hdrdir)/ruby/internal/attr/weakref.h
+option.o: $(hdrdir)/ruby/internal/cast.h
+option.o: $(hdrdir)/ruby/internal/compiler_is.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+option.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+option.o: $(hdrdir)/ruby/internal/compiler_since.h
+option.o: $(hdrdir)/ruby/internal/config.h
+option.o: $(hdrdir)/ruby/internal/constant_p.h
+option.o: $(hdrdir)/ruby/internal/core.h
+option.o: $(hdrdir)/ruby/internal/core/rarray.h
+option.o: $(hdrdir)/ruby/internal/core/rbasic.h
+option.o: $(hdrdir)/ruby/internal/core/rbignum.h
+option.o: $(hdrdir)/ruby/internal/core/rclass.h
+option.o: $(hdrdir)/ruby/internal/core/rdata.h
+option.o: $(hdrdir)/ruby/internal/core/rfile.h
+option.o: $(hdrdir)/ruby/internal/core/rhash.h
+option.o: $(hdrdir)/ruby/internal/core/robject.h
+option.o: $(hdrdir)/ruby/internal/core/rregexp.h
+option.o: $(hdrdir)/ruby/internal/core/rstring.h
+option.o: $(hdrdir)/ruby/internal/core/rstruct.h
+option.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+option.o: $(hdrdir)/ruby/internal/ctype.h
+option.o: $(hdrdir)/ruby/internal/dllexport.h
+option.o: $(hdrdir)/ruby/internal/dosish.h
+option.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+option.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+option.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+option.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+option.o: $(hdrdir)/ruby/internal/encoding/re.h
+option.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+option.o: $(hdrdir)/ruby/internal/encoding/string.h
+option.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+option.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+option.o: $(hdrdir)/ruby/internal/error.h
+option.o: $(hdrdir)/ruby/internal/eval.h
+option.o: $(hdrdir)/ruby/internal/event.h
+option.o: $(hdrdir)/ruby/internal/fl_type.h
+option.o: $(hdrdir)/ruby/internal/gc.h
+option.o: $(hdrdir)/ruby/internal/glob.h
+option.o: $(hdrdir)/ruby/internal/globals.h
+option.o: $(hdrdir)/ruby/internal/has/attribute.h
+option.o: $(hdrdir)/ruby/internal/has/builtin.h
+option.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+option.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+option.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+option.o: $(hdrdir)/ruby/internal/has/extension.h
+option.o: $(hdrdir)/ruby/internal/has/feature.h
+option.o: $(hdrdir)/ruby/internal/has/warning.h
+option.o: $(hdrdir)/ruby/internal/intern/array.h
+option.o: $(hdrdir)/ruby/internal/intern/bignum.h
+option.o: $(hdrdir)/ruby/internal/intern/class.h
+option.o: $(hdrdir)/ruby/internal/intern/compar.h
+option.o: $(hdrdir)/ruby/internal/intern/complex.h
+option.o: $(hdrdir)/ruby/internal/intern/cont.h
+option.o: $(hdrdir)/ruby/internal/intern/dir.h
+option.o: $(hdrdir)/ruby/internal/intern/enum.h
+option.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+option.o: $(hdrdir)/ruby/internal/intern/error.h
+option.o: $(hdrdir)/ruby/internal/intern/eval.h
+option.o: $(hdrdir)/ruby/internal/intern/file.h
+option.o: $(hdrdir)/ruby/internal/intern/gc.h
+option.o: $(hdrdir)/ruby/internal/intern/hash.h
+option.o: $(hdrdir)/ruby/internal/intern/io.h
+option.o: $(hdrdir)/ruby/internal/intern/load.h
+option.o: $(hdrdir)/ruby/internal/intern/marshal.h
+option.o: $(hdrdir)/ruby/internal/intern/numeric.h
+option.o: $(hdrdir)/ruby/internal/intern/object.h
+option.o: $(hdrdir)/ruby/internal/intern/parse.h
+option.o: $(hdrdir)/ruby/internal/intern/proc.h
+option.o: $(hdrdir)/ruby/internal/intern/process.h
+option.o: $(hdrdir)/ruby/internal/intern/random.h
+option.o: $(hdrdir)/ruby/internal/intern/range.h
+option.o: $(hdrdir)/ruby/internal/intern/rational.h
+option.o: $(hdrdir)/ruby/internal/intern/re.h
+option.o: $(hdrdir)/ruby/internal/intern/ruby.h
+option.o: $(hdrdir)/ruby/internal/intern/select.h
+option.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+option.o: $(hdrdir)/ruby/internal/intern/signal.h
+option.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+option.o: $(hdrdir)/ruby/internal/intern/string.h
+option.o: $(hdrdir)/ruby/internal/intern/struct.h
+option.o: $(hdrdir)/ruby/internal/intern/thread.h
+option.o: $(hdrdir)/ruby/internal/intern/time.h
+option.o: $(hdrdir)/ruby/internal/intern/variable.h
+option.o: $(hdrdir)/ruby/internal/intern/vm.h
+option.o: $(hdrdir)/ruby/internal/interpreter.h
+option.o: $(hdrdir)/ruby/internal/iterator.h
+option.o: $(hdrdir)/ruby/internal/memory.h
+option.o: $(hdrdir)/ruby/internal/method.h
+option.o: $(hdrdir)/ruby/internal/module.h
+option.o: $(hdrdir)/ruby/internal/newobj.h
+option.o: $(hdrdir)/ruby/internal/rgengc.h
+option.o: $(hdrdir)/ruby/internal/scan_args.h
+option.o: $(hdrdir)/ruby/internal/special_consts.h
+option.o: $(hdrdir)/ruby/internal/static_assert.h
+option.o: $(hdrdir)/ruby/internal/stdalign.h
+option.o: $(hdrdir)/ruby/internal/stdbool.h
+option.o: $(hdrdir)/ruby/internal/symbol.h
+option.o: $(hdrdir)/ruby/internal/value.h
+option.o: $(hdrdir)/ruby/internal/value_type.h
+option.o: $(hdrdir)/ruby/internal/variable.h
+option.o: $(hdrdir)/ruby/internal/warning_push.h
+option.o: $(hdrdir)/ruby/internal/xmalloc.h
+option.o: $(hdrdir)/ruby/io.h
+option.o: $(hdrdir)/ruby/missing.h
+option.o: $(hdrdir)/ruby/onigmo.h
+option.o: $(hdrdir)/ruby/oniguruma.h
+option.o: $(hdrdir)/ruby/ruby.h
+option.o: $(hdrdir)/ruby/st.h
+option.o: $(hdrdir)/ruby/subst.h
+option.o: $(hdrdir)/ruby/thread.h
+option.o: $(hdrdir)/ruby/util.h
+option.o: $(top_srcdir)/internal.h
+option.o: $(top_srcdir)/internal/array.h
+option.o: $(top_srcdir)/internal/compilers.h
+option.o: $(top_srcdir)/internal/error.h
+option.o: $(top_srcdir)/internal/gc.h
+option.o: $(top_srcdir)/internal/io.h
+option.o: $(top_srcdir)/internal/serial.h
+option.o: $(top_srcdir)/internal/static_assert.h
+option.o: $(top_srcdir)/internal/string.h
+option.o: $(top_srcdir)/internal/thread.h
+option.o: $(top_srcdir)/internal/vm.h
+option.o: $(top_srcdir)/internal/warnings.h
+option.o: constdefs.h
+option.o: option.c
+option.o: rubysocket.h
+option.o: sockport.h
+raddrinfo.o: $(RUBY_EXTCONF_H)
+raddrinfo.o: $(arch_hdrdir)/ruby/config.h
+raddrinfo.o: $(hdrdir)/ruby/assert.h
+raddrinfo.o: $(hdrdir)/ruby/backward.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/assume.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/attributes.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/bool.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/inttypes.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/limits.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/long_long.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/stdalign.h
+raddrinfo.o: $(hdrdir)/ruby/backward/2/stdarg.h
+raddrinfo.o: $(hdrdir)/ruby/defines.h
+raddrinfo.o: $(hdrdir)/ruby/encoding.h
+raddrinfo.o: $(hdrdir)/ruby/fiber/scheduler.h
+raddrinfo.o: $(hdrdir)/ruby/intern.h
+raddrinfo.o: $(hdrdir)/ruby/internal/anyargs.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+raddrinfo.o: $(hdrdir)/ruby/internal/assume.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/artificial.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/cold.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/const.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/error.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/format.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/noalias.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/noinline.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/pure.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/restrict.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/warning.h
+raddrinfo.o: $(hdrdir)/ruby/internal/attr/weakref.h
+raddrinfo.o: $(hdrdir)/ruby/internal/cast.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+raddrinfo.o: $(hdrdir)/ruby/internal/compiler_since.h
+raddrinfo.o: $(hdrdir)/ruby/internal/config.h
+raddrinfo.o: $(hdrdir)/ruby/internal/constant_p.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rarray.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rbasic.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rbignum.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rclass.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rdata.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rfile.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rhash.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/robject.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rregexp.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rstring.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rstruct.h
+raddrinfo.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+raddrinfo.o: $(hdrdir)/ruby/internal/ctype.h
+raddrinfo.o: $(hdrdir)/ruby/internal/dllexport.h
+raddrinfo.o: $(hdrdir)/ruby/internal/dosish.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/re.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/string.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+raddrinfo.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+raddrinfo.o: $(hdrdir)/ruby/internal/error.h
+raddrinfo.o: $(hdrdir)/ruby/internal/eval.h
+raddrinfo.o: $(hdrdir)/ruby/internal/event.h
+raddrinfo.o: $(hdrdir)/ruby/internal/fl_type.h
+raddrinfo.o: $(hdrdir)/ruby/internal/gc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/glob.h
+raddrinfo.o: $(hdrdir)/ruby/internal/globals.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/attribute.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/builtin.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/extension.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/feature.h
+raddrinfo.o: $(hdrdir)/ruby/internal/has/warning.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/array.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/bignum.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/class.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/compar.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/complex.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/cont.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/dir.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/enum.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/error.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/eval.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/file.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/gc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/hash.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/io.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/load.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/marshal.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/numeric.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/object.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/parse.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/proc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/process.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/random.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/range.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/rational.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/re.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/ruby.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/select.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/signal.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/string.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/struct.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/thread.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/time.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/variable.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/vm.h
+raddrinfo.o: $(hdrdir)/ruby/internal/interpreter.h
+raddrinfo.o: $(hdrdir)/ruby/internal/iterator.h
+raddrinfo.o: $(hdrdir)/ruby/internal/memory.h
+raddrinfo.o: $(hdrdir)/ruby/internal/method.h
+raddrinfo.o: $(hdrdir)/ruby/internal/module.h
+raddrinfo.o: $(hdrdir)/ruby/internal/newobj.h
+raddrinfo.o: $(hdrdir)/ruby/internal/rgengc.h
+raddrinfo.o: $(hdrdir)/ruby/internal/scan_args.h
+raddrinfo.o: $(hdrdir)/ruby/internal/special_consts.h
+raddrinfo.o: $(hdrdir)/ruby/internal/static_assert.h
+raddrinfo.o: $(hdrdir)/ruby/internal/stdalign.h
+raddrinfo.o: $(hdrdir)/ruby/internal/stdbool.h
+raddrinfo.o: $(hdrdir)/ruby/internal/symbol.h
+raddrinfo.o: $(hdrdir)/ruby/internal/value.h
+raddrinfo.o: $(hdrdir)/ruby/internal/value_type.h
+raddrinfo.o: $(hdrdir)/ruby/internal/variable.h
+raddrinfo.o: $(hdrdir)/ruby/internal/warning_push.h
+raddrinfo.o: $(hdrdir)/ruby/internal/xmalloc.h
+raddrinfo.o: $(hdrdir)/ruby/io.h
+raddrinfo.o: $(hdrdir)/ruby/missing.h
+raddrinfo.o: $(hdrdir)/ruby/onigmo.h
+raddrinfo.o: $(hdrdir)/ruby/oniguruma.h
+raddrinfo.o: $(hdrdir)/ruby/ruby.h
+raddrinfo.o: $(hdrdir)/ruby/st.h
+raddrinfo.o: $(hdrdir)/ruby/subst.h
+raddrinfo.o: $(hdrdir)/ruby/thread.h
+raddrinfo.o: $(hdrdir)/ruby/util.h
+raddrinfo.o: $(top_srcdir)/internal.h
+raddrinfo.o: $(top_srcdir)/internal/array.h
+raddrinfo.o: $(top_srcdir)/internal/compilers.h
+raddrinfo.o: $(top_srcdir)/internal/error.h
+raddrinfo.o: $(top_srcdir)/internal/gc.h
+raddrinfo.o: $(top_srcdir)/internal/io.h
+raddrinfo.o: $(top_srcdir)/internal/serial.h
+raddrinfo.o: $(top_srcdir)/internal/static_assert.h
+raddrinfo.o: $(top_srcdir)/internal/string.h
+raddrinfo.o: $(top_srcdir)/internal/thread.h
+raddrinfo.o: $(top_srcdir)/internal/vm.h
+raddrinfo.o: $(top_srcdir)/internal/warnings.h
+raddrinfo.o: constdefs.h
+raddrinfo.o: raddrinfo.c
+raddrinfo.o: rubysocket.h
+raddrinfo.o: sockport.h
+socket.o: $(RUBY_EXTCONF_H)
+socket.o: $(arch_hdrdir)/ruby/config.h
+socket.o: $(hdrdir)/ruby/assert.h
+socket.o: $(hdrdir)/ruby/backward.h
+socket.o: $(hdrdir)/ruby/backward/2/assume.h
+socket.o: $(hdrdir)/ruby/backward/2/attributes.h
+socket.o: $(hdrdir)/ruby/backward/2/bool.h
+socket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+socket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+socket.o: $(hdrdir)/ruby/backward/2/limits.h
+socket.o: $(hdrdir)/ruby/backward/2/long_long.h
+socket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+socket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+socket.o: $(hdrdir)/ruby/defines.h
+socket.o: $(hdrdir)/ruby/encoding.h
+socket.o: $(hdrdir)/ruby/fiber/scheduler.h
+socket.o: $(hdrdir)/ruby/intern.h
+socket.o: $(hdrdir)/ruby/internal/anyargs.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+socket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+socket.o: $(hdrdir)/ruby/internal/assume.h
+socket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+socket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+socket.o: $(hdrdir)/ruby/internal/attr/cold.h
+socket.o: $(hdrdir)/ruby/internal/attr/const.h
+socket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+socket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+socket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+socket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+socket.o: $(hdrdir)/ruby/internal/attr/error.h
+socket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+socket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+socket.o: $(hdrdir)/ruby/internal/attr/format.h
+socket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+socket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+socket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+socket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+socket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+socket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+socket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+socket.o: $(hdrdir)/ruby/internal/attr/pure.h
+socket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+socket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+socket.o: $(hdrdir)/ruby/internal/attr/warning.h
+socket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+socket.o: $(hdrdir)/ruby/internal/cast.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+socket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+socket.o: $(hdrdir)/ruby/internal/compiler_since.h
+socket.o: $(hdrdir)/ruby/internal/config.h
+socket.o: $(hdrdir)/ruby/internal/constant_p.h
+socket.o: $(hdrdir)/ruby/internal/core.h
+socket.o: $(hdrdir)/ruby/internal/core/rarray.h
+socket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+socket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+socket.o: $(hdrdir)/ruby/internal/core/rclass.h
+socket.o: $(hdrdir)/ruby/internal/core/rdata.h
+socket.o: $(hdrdir)/ruby/internal/core/rfile.h
+socket.o: $(hdrdir)/ruby/internal/core/rhash.h
+socket.o: $(hdrdir)/ruby/internal/core/robject.h
+socket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+socket.o: $(hdrdir)/ruby/internal/core/rstring.h
+socket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+socket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+socket.o: $(hdrdir)/ruby/internal/ctype.h
+socket.o: $(hdrdir)/ruby/internal/dllexport.h
+socket.o: $(hdrdir)/ruby/internal/dosish.h
+socket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+socket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+socket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+socket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+socket.o: $(hdrdir)/ruby/internal/encoding/re.h
+socket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+socket.o: $(hdrdir)/ruby/internal/encoding/string.h
+socket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+socket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+socket.o: $(hdrdir)/ruby/internal/error.h
+socket.o: $(hdrdir)/ruby/internal/eval.h
+socket.o: $(hdrdir)/ruby/internal/event.h
+socket.o: $(hdrdir)/ruby/internal/fl_type.h
+socket.o: $(hdrdir)/ruby/internal/gc.h
+socket.o: $(hdrdir)/ruby/internal/glob.h
+socket.o: $(hdrdir)/ruby/internal/globals.h
+socket.o: $(hdrdir)/ruby/internal/has/attribute.h
+socket.o: $(hdrdir)/ruby/internal/has/builtin.h
+socket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+socket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+socket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+socket.o: $(hdrdir)/ruby/internal/has/extension.h
+socket.o: $(hdrdir)/ruby/internal/has/feature.h
+socket.o: $(hdrdir)/ruby/internal/has/warning.h
+socket.o: $(hdrdir)/ruby/internal/intern/array.h
+socket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+socket.o: $(hdrdir)/ruby/internal/intern/class.h
+socket.o: $(hdrdir)/ruby/internal/intern/compar.h
+socket.o: $(hdrdir)/ruby/internal/intern/complex.h
+socket.o: $(hdrdir)/ruby/internal/intern/cont.h
+socket.o: $(hdrdir)/ruby/internal/intern/dir.h
+socket.o: $(hdrdir)/ruby/internal/intern/enum.h
+socket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+socket.o: $(hdrdir)/ruby/internal/intern/error.h
+socket.o: $(hdrdir)/ruby/internal/intern/eval.h
+socket.o: $(hdrdir)/ruby/internal/intern/file.h
+socket.o: $(hdrdir)/ruby/internal/intern/gc.h
+socket.o: $(hdrdir)/ruby/internal/intern/hash.h
+socket.o: $(hdrdir)/ruby/internal/intern/io.h
+socket.o: $(hdrdir)/ruby/internal/intern/load.h
+socket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+socket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+socket.o: $(hdrdir)/ruby/internal/intern/object.h
+socket.o: $(hdrdir)/ruby/internal/intern/parse.h
+socket.o: $(hdrdir)/ruby/internal/intern/proc.h
+socket.o: $(hdrdir)/ruby/internal/intern/process.h
+socket.o: $(hdrdir)/ruby/internal/intern/random.h
+socket.o: $(hdrdir)/ruby/internal/intern/range.h
+socket.o: $(hdrdir)/ruby/internal/intern/rational.h
+socket.o: $(hdrdir)/ruby/internal/intern/re.h
+socket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+socket.o: $(hdrdir)/ruby/internal/intern/select.h
+socket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+socket.o: $(hdrdir)/ruby/internal/intern/signal.h
+socket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+socket.o: $(hdrdir)/ruby/internal/intern/string.h
+socket.o: $(hdrdir)/ruby/internal/intern/struct.h
+socket.o: $(hdrdir)/ruby/internal/intern/thread.h
+socket.o: $(hdrdir)/ruby/internal/intern/time.h
+socket.o: $(hdrdir)/ruby/internal/intern/variable.h
+socket.o: $(hdrdir)/ruby/internal/intern/vm.h
+socket.o: $(hdrdir)/ruby/internal/interpreter.h
+socket.o: $(hdrdir)/ruby/internal/iterator.h
+socket.o: $(hdrdir)/ruby/internal/memory.h
+socket.o: $(hdrdir)/ruby/internal/method.h
+socket.o: $(hdrdir)/ruby/internal/module.h
+socket.o: $(hdrdir)/ruby/internal/newobj.h
+socket.o: $(hdrdir)/ruby/internal/rgengc.h
+socket.o: $(hdrdir)/ruby/internal/scan_args.h
+socket.o: $(hdrdir)/ruby/internal/special_consts.h
+socket.o: $(hdrdir)/ruby/internal/static_assert.h
+socket.o: $(hdrdir)/ruby/internal/stdalign.h
+socket.o: $(hdrdir)/ruby/internal/stdbool.h
+socket.o: $(hdrdir)/ruby/internal/symbol.h
+socket.o: $(hdrdir)/ruby/internal/value.h
+socket.o: $(hdrdir)/ruby/internal/value_type.h
+socket.o: $(hdrdir)/ruby/internal/variable.h
+socket.o: $(hdrdir)/ruby/internal/warning_push.h
+socket.o: $(hdrdir)/ruby/internal/xmalloc.h
+socket.o: $(hdrdir)/ruby/io.h
+socket.o: $(hdrdir)/ruby/missing.h
+socket.o: $(hdrdir)/ruby/onigmo.h
+socket.o: $(hdrdir)/ruby/oniguruma.h
+socket.o: $(hdrdir)/ruby/ruby.h
+socket.o: $(hdrdir)/ruby/st.h
+socket.o: $(hdrdir)/ruby/subst.h
+socket.o: $(hdrdir)/ruby/thread.h
+socket.o: $(hdrdir)/ruby/util.h
+socket.o: $(top_srcdir)/internal.h
+socket.o: $(top_srcdir)/internal/array.h
+socket.o: $(top_srcdir)/internal/compilers.h
+socket.o: $(top_srcdir)/internal/error.h
+socket.o: $(top_srcdir)/internal/gc.h
+socket.o: $(top_srcdir)/internal/io.h
+socket.o: $(top_srcdir)/internal/serial.h
+socket.o: $(top_srcdir)/internal/static_assert.h
+socket.o: $(top_srcdir)/internal/string.h
+socket.o: $(top_srcdir)/internal/thread.h
+socket.o: $(top_srcdir)/internal/vm.h
+socket.o: $(top_srcdir)/internal/warnings.h
+socket.o: constdefs.h
+socket.o: rubysocket.h
+socket.o: socket.c
+socket.o: sockport.h
+sockssocket.o: $(RUBY_EXTCONF_H)
+sockssocket.o: $(arch_hdrdir)/ruby/config.h
+sockssocket.o: $(hdrdir)/ruby/assert.h
+sockssocket.o: $(hdrdir)/ruby/backward.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/assume.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/bool.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/limits.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+sockssocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+sockssocket.o: $(hdrdir)/ruby/defines.h
+sockssocket.o: $(hdrdir)/ruby/encoding.h
+sockssocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+sockssocket.o: $(hdrdir)/ruby/intern.h
+sockssocket.o: $(hdrdir)/ruby/internal/anyargs.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+sockssocket.o: $(hdrdir)/ruby/internal/assume.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/const.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/error.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/format.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+sockssocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+sockssocket.o: $(hdrdir)/ruby/internal/cast.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+sockssocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+sockssocket.o: $(hdrdir)/ruby/internal/config.h
+sockssocket.o: $(hdrdir)/ruby/internal/constant_p.h
+sockssocket.o: $(hdrdir)/ruby/internal/core.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/robject.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+sockssocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+sockssocket.o: $(hdrdir)/ruby/internal/ctype.h
+sockssocket.o: $(hdrdir)/ruby/internal/dllexport.h
+sockssocket.o: $(hdrdir)/ruby/internal/dosish.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+sockssocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+sockssocket.o: $(hdrdir)/ruby/internal/error.h
+sockssocket.o: $(hdrdir)/ruby/internal/eval.h
+sockssocket.o: $(hdrdir)/ruby/internal/event.h
+sockssocket.o: $(hdrdir)/ruby/internal/fl_type.h
+sockssocket.o: $(hdrdir)/ruby/internal/gc.h
+sockssocket.o: $(hdrdir)/ruby/internal/glob.h
+sockssocket.o: $(hdrdir)/ruby/internal/globals.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/extension.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/feature.h
+sockssocket.o: $(hdrdir)/ruby/internal/has/warning.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/array.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/class.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/error.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/file.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/io.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/load.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/object.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/process.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/random.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/range.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/re.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/select.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/string.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/time.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+sockssocket.o: $(hdrdir)/ruby/internal/interpreter.h
+sockssocket.o: $(hdrdir)/ruby/internal/iterator.h
+sockssocket.o: $(hdrdir)/ruby/internal/memory.h
+sockssocket.o: $(hdrdir)/ruby/internal/method.h
+sockssocket.o: $(hdrdir)/ruby/internal/module.h
+sockssocket.o: $(hdrdir)/ruby/internal/newobj.h
+sockssocket.o: $(hdrdir)/ruby/internal/rgengc.h
+sockssocket.o: $(hdrdir)/ruby/internal/scan_args.h
+sockssocket.o: $(hdrdir)/ruby/internal/special_consts.h
+sockssocket.o: $(hdrdir)/ruby/internal/static_assert.h
+sockssocket.o: $(hdrdir)/ruby/internal/stdalign.h
+sockssocket.o: $(hdrdir)/ruby/internal/stdbool.h
+sockssocket.o: $(hdrdir)/ruby/internal/symbol.h
+sockssocket.o: $(hdrdir)/ruby/internal/value.h
+sockssocket.o: $(hdrdir)/ruby/internal/value_type.h
+sockssocket.o: $(hdrdir)/ruby/internal/variable.h
+sockssocket.o: $(hdrdir)/ruby/internal/warning_push.h
+sockssocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+sockssocket.o: $(hdrdir)/ruby/io.h
+sockssocket.o: $(hdrdir)/ruby/missing.h
+sockssocket.o: $(hdrdir)/ruby/onigmo.h
+sockssocket.o: $(hdrdir)/ruby/oniguruma.h
+sockssocket.o: $(hdrdir)/ruby/ruby.h
+sockssocket.o: $(hdrdir)/ruby/st.h
+sockssocket.o: $(hdrdir)/ruby/subst.h
+sockssocket.o: $(hdrdir)/ruby/thread.h
+sockssocket.o: $(hdrdir)/ruby/util.h
+sockssocket.o: $(top_srcdir)/internal.h
+sockssocket.o: $(top_srcdir)/internal/array.h
+sockssocket.o: $(top_srcdir)/internal/compilers.h
+sockssocket.o: $(top_srcdir)/internal/error.h
+sockssocket.o: $(top_srcdir)/internal/gc.h
+sockssocket.o: $(top_srcdir)/internal/io.h
+sockssocket.o: $(top_srcdir)/internal/serial.h
+sockssocket.o: $(top_srcdir)/internal/static_assert.h
+sockssocket.o: $(top_srcdir)/internal/string.h
+sockssocket.o: $(top_srcdir)/internal/thread.h
+sockssocket.o: $(top_srcdir)/internal/vm.h
+sockssocket.o: $(top_srcdir)/internal/warnings.h
+sockssocket.o: constdefs.h
+sockssocket.o: rubysocket.h
+sockssocket.o: sockport.h
+sockssocket.o: sockssocket.c
+tcpserver.o: $(RUBY_EXTCONF_H)
+tcpserver.o: $(arch_hdrdir)/ruby/config.h
+tcpserver.o: $(hdrdir)/ruby/assert.h
+tcpserver.o: $(hdrdir)/ruby/backward.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/assume.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/attributes.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/bool.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/inttypes.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/limits.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/long_long.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/stdalign.h
+tcpserver.o: $(hdrdir)/ruby/backward/2/stdarg.h
+tcpserver.o: $(hdrdir)/ruby/defines.h
+tcpserver.o: $(hdrdir)/ruby/encoding.h
+tcpserver.o: $(hdrdir)/ruby/fiber/scheduler.h
+tcpserver.o: $(hdrdir)/ruby/intern.h
+tcpserver.o: $(hdrdir)/ruby/internal/anyargs.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+tcpserver.o: $(hdrdir)/ruby/internal/assume.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/artificial.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/cold.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/const.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/error.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/format.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/noalias.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/pure.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/warning.h
+tcpserver.o: $(hdrdir)/ruby/internal/attr/weakref.h
+tcpserver.o: $(hdrdir)/ruby/internal/cast.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+tcpserver.o: $(hdrdir)/ruby/internal/compiler_since.h
+tcpserver.o: $(hdrdir)/ruby/internal/config.h
+tcpserver.o: $(hdrdir)/ruby/internal/constant_p.h
+tcpserver.o: $(hdrdir)/ruby/internal/core.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rarray.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rbasic.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rbignum.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rclass.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rdata.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rfile.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rhash.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/robject.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rregexp.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rstring.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rstruct.h
+tcpserver.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+tcpserver.o: $(hdrdir)/ruby/internal/ctype.h
+tcpserver.o: $(hdrdir)/ruby/internal/dllexport.h
+tcpserver.o: $(hdrdir)/ruby/internal/dosish.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/re.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/string.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+tcpserver.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+tcpserver.o: $(hdrdir)/ruby/internal/error.h
+tcpserver.o: $(hdrdir)/ruby/internal/eval.h
+tcpserver.o: $(hdrdir)/ruby/internal/event.h
+tcpserver.o: $(hdrdir)/ruby/internal/fl_type.h
+tcpserver.o: $(hdrdir)/ruby/internal/gc.h
+tcpserver.o: $(hdrdir)/ruby/internal/glob.h
+tcpserver.o: $(hdrdir)/ruby/internal/globals.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/attribute.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/builtin.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/extension.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/feature.h
+tcpserver.o: $(hdrdir)/ruby/internal/has/warning.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/array.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/bignum.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/class.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/compar.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/complex.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/cont.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/dir.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/enum.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/error.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/eval.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/gc.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/hash.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/io.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/load.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/marshal.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/numeric.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/object.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/parse.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/proc.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/process.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/random.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/range.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/rational.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/re.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/select.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/signal.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/string.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/struct.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/thread.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/time.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/variable.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/vm.h
+tcpserver.o: $(hdrdir)/ruby/internal/interpreter.h
+tcpserver.o: $(hdrdir)/ruby/internal/iterator.h
+tcpserver.o: $(hdrdir)/ruby/internal/memory.h
+tcpserver.o: $(hdrdir)/ruby/internal/method.h
+tcpserver.o: $(hdrdir)/ruby/internal/module.h
+tcpserver.o: $(hdrdir)/ruby/internal/newobj.h
+tcpserver.o: $(hdrdir)/ruby/internal/rgengc.h
+tcpserver.o: $(hdrdir)/ruby/internal/scan_args.h
+tcpserver.o: $(hdrdir)/ruby/internal/special_consts.h
+tcpserver.o: $(hdrdir)/ruby/internal/static_assert.h
+tcpserver.o: $(hdrdir)/ruby/internal/stdalign.h
+tcpserver.o: $(hdrdir)/ruby/internal/stdbool.h
+tcpserver.o: $(hdrdir)/ruby/internal/symbol.h
+tcpserver.o: $(hdrdir)/ruby/internal/value.h
+tcpserver.o: $(hdrdir)/ruby/internal/value_type.h
+tcpserver.o: $(hdrdir)/ruby/internal/variable.h
+tcpserver.o: $(hdrdir)/ruby/internal/warning_push.h
+tcpserver.o: $(hdrdir)/ruby/internal/xmalloc.h
+tcpserver.o: $(hdrdir)/ruby/io.h
+tcpserver.o: $(hdrdir)/ruby/missing.h
+tcpserver.o: $(hdrdir)/ruby/onigmo.h
+tcpserver.o: $(hdrdir)/ruby/oniguruma.h
+tcpserver.o: $(hdrdir)/ruby/ruby.h
+tcpserver.o: $(hdrdir)/ruby/st.h
+tcpserver.o: $(hdrdir)/ruby/subst.h
+tcpserver.o: $(hdrdir)/ruby/thread.h
+tcpserver.o: $(hdrdir)/ruby/util.h
+tcpserver.o: $(top_srcdir)/internal.h
+tcpserver.o: $(top_srcdir)/internal/array.h
+tcpserver.o: $(top_srcdir)/internal/compilers.h
+tcpserver.o: $(top_srcdir)/internal/error.h
+tcpserver.o: $(top_srcdir)/internal/gc.h
+tcpserver.o: $(top_srcdir)/internal/io.h
+tcpserver.o: $(top_srcdir)/internal/serial.h
+tcpserver.o: $(top_srcdir)/internal/static_assert.h
+tcpserver.o: $(top_srcdir)/internal/string.h
+tcpserver.o: $(top_srcdir)/internal/thread.h
+tcpserver.o: $(top_srcdir)/internal/vm.h
+tcpserver.o: $(top_srcdir)/internal/warnings.h
+tcpserver.o: constdefs.h
+tcpserver.o: rubysocket.h
+tcpserver.o: sockport.h
+tcpserver.o: tcpserver.c
+tcpsocket.o: $(RUBY_EXTCONF_H)
+tcpsocket.o: $(arch_hdrdir)/ruby/config.h
+tcpsocket.o: $(hdrdir)/ruby/assert.h
+tcpsocket.o: $(hdrdir)/ruby/backward.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/bool.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/limits.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+tcpsocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+tcpsocket.o: $(hdrdir)/ruby/defines.h
+tcpsocket.o: $(hdrdir)/ruby/encoding.h
+tcpsocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+tcpsocket.o: $(hdrdir)/ruby/intern.h
+tcpsocket.o: $(hdrdir)/ruby/internal/anyargs.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+tcpsocket.o: $(hdrdir)/ruby/internal/assume.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/const.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/error.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/format.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+tcpsocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+tcpsocket.o: $(hdrdir)/ruby/internal/cast.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+tcpsocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+tcpsocket.o: $(hdrdir)/ruby/internal/config.h
+tcpsocket.o: $(hdrdir)/ruby/internal/constant_p.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/robject.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+tcpsocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+tcpsocket.o: $(hdrdir)/ruby/internal/ctype.h
+tcpsocket.o: $(hdrdir)/ruby/internal/dllexport.h
+tcpsocket.o: $(hdrdir)/ruby/internal/dosish.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+tcpsocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+tcpsocket.o: $(hdrdir)/ruby/internal/error.h
+tcpsocket.o: $(hdrdir)/ruby/internal/eval.h
+tcpsocket.o: $(hdrdir)/ruby/internal/event.h
+tcpsocket.o: $(hdrdir)/ruby/internal/fl_type.h
+tcpsocket.o: $(hdrdir)/ruby/internal/gc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/glob.h
+tcpsocket.o: $(hdrdir)/ruby/internal/globals.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/extension.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/feature.h
+tcpsocket.o: $(hdrdir)/ruby/internal/has/warning.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/array.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/class.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/object.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/process.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/random.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/range.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/time.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+tcpsocket.o: $(hdrdir)/ruby/internal/interpreter.h
+tcpsocket.o: $(hdrdir)/ruby/internal/iterator.h
+tcpsocket.o: $(hdrdir)/ruby/internal/memory.h
+tcpsocket.o: $(hdrdir)/ruby/internal/method.h
+tcpsocket.o: $(hdrdir)/ruby/internal/module.h
+tcpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+tcpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
+tcpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
+tcpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
+tcpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
+tcpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
+tcpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+tcpsocket.o: $(hdrdir)/ruby/internal/symbol.h
+tcpsocket.o: $(hdrdir)/ruby/internal/value.h
+tcpsocket.o: $(hdrdir)/ruby/internal/value_type.h
+tcpsocket.o: $(hdrdir)/ruby/internal/variable.h
+tcpsocket.o: $(hdrdir)/ruby/internal/warning_push.h
+tcpsocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+tcpsocket.o: $(hdrdir)/ruby/io.h
+tcpsocket.o: $(hdrdir)/ruby/missing.h
+tcpsocket.o: $(hdrdir)/ruby/onigmo.h
+tcpsocket.o: $(hdrdir)/ruby/oniguruma.h
+tcpsocket.o: $(hdrdir)/ruby/ruby.h
+tcpsocket.o: $(hdrdir)/ruby/st.h
+tcpsocket.o: $(hdrdir)/ruby/subst.h
+tcpsocket.o: $(hdrdir)/ruby/thread.h
+tcpsocket.o: $(hdrdir)/ruby/util.h
+tcpsocket.o: $(top_srcdir)/internal.h
+tcpsocket.o: $(top_srcdir)/internal/array.h
+tcpsocket.o: $(top_srcdir)/internal/compilers.h
+tcpsocket.o: $(top_srcdir)/internal/error.h
+tcpsocket.o: $(top_srcdir)/internal/gc.h
+tcpsocket.o: $(top_srcdir)/internal/io.h
+tcpsocket.o: $(top_srcdir)/internal/serial.h
+tcpsocket.o: $(top_srcdir)/internal/static_assert.h
+tcpsocket.o: $(top_srcdir)/internal/string.h
+tcpsocket.o: $(top_srcdir)/internal/thread.h
+tcpsocket.o: $(top_srcdir)/internal/vm.h
+tcpsocket.o: $(top_srcdir)/internal/warnings.h
+tcpsocket.o: constdefs.h
+tcpsocket.o: rubysocket.h
+tcpsocket.o: sockport.h
+tcpsocket.o: tcpsocket.c
+udpsocket.o: $(RUBY_EXTCONF_H)
+udpsocket.o: $(arch_hdrdir)/ruby/config.h
+udpsocket.o: $(hdrdir)/ruby/assert.h
+udpsocket.o: $(hdrdir)/ruby/backward.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/bool.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/limits.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+udpsocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+udpsocket.o: $(hdrdir)/ruby/defines.h
+udpsocket.o: $(hdrdir)/ruby/encoding.h
+udpsocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+udpsocket.o: $(hdrdir)/ruby/intern.h
+udpsocket.o: $(hdrdir)/ruby/internal/anyargs.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+udpsocket.o: $(hdrdir)/ruby/internal/assume.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/const.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/error.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/format.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+udpsocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+udpsocket.o: $(hdrdir)/ruby/internal/cast.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+udpsocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+udpsocket.o: $(hdrdir)/ruby/internal/config.h
+udpsocket.o: $(hdrdir)/ruby/internal/constant_p.h
+udpsocket.o: $(hdrdir)/ruby/internal/core.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/robject.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+udpsocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+udpsocket.o: $(hdrdir)/ruby/internal/ctype.h
+udpsocket.o: $(hdrdir)/ruby/internal/dllexport.h
+udpsocket.o: $(hdrdir)/ruby/internal/dosish.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+udpsocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+udpsocket.o: $(hdrdir)/ruby/internal/error.h
+udpsocket.o: $(hdrdir)/ruby/internal/eval.h
+udpsocket.o: $(hdrdir)/ruby/internal/event.h
+udpsocket.o: $(hdrdir)/ruby/internal/fl_type.h
+udpsocket.o: $(hdrdir)/ruby/internal/gc.h
+udpsocket.o: $(hdrdir)/ruby/internal/glob.h
+udpsocket.o: $(hdrdir)/ruby/internal/globals.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/extension.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/feature.h
+udpsocket.o: $(hdrdir)/ruby/internal/has/warning.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/array.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/class.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/object.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/process.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/random.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/range.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/time.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+udpsocket.o: $(hdrdir)/ruby/internal/interpreter.h
+udpsocket.o: $(hdrdir)/ruby/internal/iterator.h
+udpsocket.o: $(hdrdir)/ruby/internal/memory.h
+udpsocket.o: $(hdrdir)/ruby/internal/method.h
+udpsocket.o: $(hdrdir)/ruby/internal/module.h
+udpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+udpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
+udpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
+udpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
+udpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
+udpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
+udpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+udpsocket.o: $(hdrdir)/ruby/internal/symbol.h
+udpsocket.o: $(hdrdir)/ruby/internal/value.h
+udpsocket.o: $(hdrdir)/ruby/internal/value_type.h
+udpsocket.o: $(hdrdir)/ruby/internal/variable.h
+udpsocket.o: $(hdrdir)/ruby/internal/warning_push.h
+udpsocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+udpsocket.o: $(hdrdir)/ruby/io.h
+udpsocket.o: $(hdrdir)/ruby/missing.h
+udpsocket.o: $(hdrdir)/ruby/onigmo.h
+udpsocket.o: $(hdrdir)/ruby/oniguruma.h
+udpsocket.o: $(hdrdir)/ruby/ruby.h
+udpsocket.o: $(hdrdir)/ruby/st.h
+udpsocket.o: $(hdrdir)/ruby/subst.h
+udpsocket.o: $(hdrdir)/ruby/thread.h
+udpsocket.o: $(hdrdir)/ruby/util.h
+udpsocket.o: $(top_srcdir)/internal.h
+udpsocket.o: $(top_srcdir)/internal/array.h
+udpsocket.o: $(top_srcdir)/internal/compilers.h
+udpsocket.o: $(top_srcdir)/internal/error.h
+udpsocket.o: $(top_srcdir)/internal/gc.h
+udpsocket.o: $(top_srcdir)/internal/io.h
+udpsocket.o: $(top_srcdir)/internal/serial.h
+udpsocket.o: $(top_srcdir)/internal/static_assert.h
+udpsocket.o: $(top_srcdir)/internal/string.h
+udpsocket.o: $(top_srcdir)/internal/thread.h
+udpsocket.o: $(top_srcdir)/internal/vm.h
+udpsocket.o: $(top_srcdir)/internal/warnings.h
+udpsocket.o: constdefs.h
+udpsocket.o: rubysocket.h
+udpsocket.o: sockport.h
+udpsocket.o: udpsocket.c
+unixserver.o: $(RUBY_EXTCONF_H)
+unixserver.o: $(arch_hdrdir)/ruby/config.h
+unixserver.o: $(hdrdir)/ruby/assert.h
+unixserver.o: $(hdrdir)/ruby/backward.h
+unixserver.o: $(hdrdir)/ruby/backward/2/assume.h
+unixserver.o: $(hdrdir)/ruby/backward/2/attributes.h
+unixserver.o: $(hdrdir)/ruby/backward/2/bool.h
+unixserver.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+unixserver.o: $(hdrdir)/ruby/backward/2/inttypes.h
+unixserver.o: $(hdrdir)/ruby/backward/2/limits.h
+unixserver.o: $(hdrdir)/ruby/backward/2/long_long.h
+unixserver.o: $(hdrdir)/ruby/backward/2/stdalign.h
+unixserver.o: $(hdrdir)/ruby/backward/2/stdarg.h
+unixserver.o: $(hdrdir)/ruby/defines.h
+unixserver.o: $(hdrdir)/ruby/encoding.h
+unixserver.o: $(hdrdir)/ruby/fiber/scheduler.h
+unixserver.o: $(hdrdir)/ruby/intern.h
+unixserver.o: $(hdrdir)/ruby/internal/anyargs.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+unixserver.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+unixserver.o: $(hdrdir)/ruby/internal/assume.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/artificial.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/cold.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/const.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/error.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/format.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/noalias.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/pure.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/warning.h
+unixserver.o: $(hdrdir)/ruby/internal/attr/weakref.h
+unixserver.o: $(hdrdir)/ruby/internal/cast.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+unixserver.o: $(hdrdir)/ruby/internal/compiler_since.h
+unixserver.o: $(hdrdir)/ruby/internal/config.h
+unixserver.o: $(hdrdir)/ruby/internal/constant_p.h
+unixserver.o: $(hdrdir)/ruby/internal/core.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rarray.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rbasic.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rbignum.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rclass.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rdata.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rfile.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rhash.h
+unixserver.o: $(hdrdir)/ruby/internal/core/robject.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rregexp.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rstring.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rstruct.h
+unixserver.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+unixserver.o: $(hdrdir)/ruby/internal/ctype.h
+unixserver.o: $(hdrdir)/ruby/internal/dllexport.h
+unixserver.o: $(hdrdir)/ruby/internal/dosish.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/re.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/string.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+unixserver.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+unixserver.o: $(hdrdir)/ruby/internal/error.h
+unixserver.o: $(hdrdir)/ruby/internal/eval.h
+unixserver.o: $(hdrdir)/ruby/internal/event.h
+unixserver.o: $(hdrdir)/ruby/internal/fl_type.h
+unixserver.o: $(hdrdir)/ruby/internal/gc.h
+unixserver.o: $(hdrdir)/ruby/internal/glob.h
+unixserver.o: $(hdrdir)/ruby/internal/globals.h
+unixserver.o: $(hdrdir)/ruby/internal/has/attribute.h
+unixserver.o: $(hdrdir)/ruby/internal/has/builtin.h
+unixserver.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+unixserver.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+unixserver.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+unixserver.o: $(hdrdir)/ruby/internal/has/extension.h
+unixserver.o: $(hdrdir)/ruby/internal/has/feature.h
+unixserver.o: $(hdrdir)/ruby/internal/has/warning.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/array.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/bignum.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/class.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/compar.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/complex.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/cont.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/dir.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/enum.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/error.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/eval.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/file.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/gc.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/hash.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/io.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/load.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/marshal.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/numeric.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/object.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/parse.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/proc.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/process.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/random.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/range.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/rational.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/re.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/select.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/signal.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/string.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/struct.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/thread.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/time.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/variable.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/vm.h
+unixserver.o: $(hdrdir)/ruby/internal/interpreter.h
+unixserver.o: $(hdrdir)/ruby/internal/iterator.h
+unixserver.o: $(hdrdir)/ruby/internal/memory.h
+unixserver.o: $(hdrdir)/ruby/internal/method.h
+unixserver.o: $(hdrdir)/ruby/internal/module.h
+unixserver.o: $(hdrdir)/ruby/internal/newobj.h
+unixserver.o: $(hdrdir)/ruby/internal/rgengc.h
+unixserver.o: $(hdrdir)/ruby/internal/scan_args.h
+unixserver.o: $(hdrdir)/ruby/internal/special_consts.h
+unixserver.o: $(hdrdir)/ruby/internal/static_assert.h
+unixserver.o: $(hdrdir)/ruby/internal/stdalign.h
+unixserver.o: $(hdrdir)/ruby/internal/stdbool.h
+unixserver.o: $(hdrdir)/ruby/internal/symbol.h
+unixserver.o: $(hdrdir)/ruby/internal/value.h
+unixserver.o: $(hdrdir)/ruby/internal/value_type.h
+unixserver.o: $(hdrdir)/ruby/internal/variable.h
+unixserver.o: $(hdrdir)/ruby/internal/warning_push.h
+unixserver.o: $(hdrdir)/ruby/internal/xmalloc.h
+unixserver.o: $(hdrdir)/ruby/io.h
+unixserver.o: $(hdrdir)/ruby/missing.h
+unixserver.o: $(hdrdir)/ruby/onigmo.h
+unixserver.o: $(hdrdir)/ruby/oniguruma.h
+unixserver.o: $(hdrdir)/ruby/ruby.h
+unixserver.o: $(hdrdir)/ruby/st.h
+unixserver.o: $(hdrdir)/ruby/subst.h
+unixserver.o: $(hdrdir)/ruby/thread.h
+unixserver.o: $(hdrdir)/ruby/util.h
+unixserver.o: $(top_srcdir)/internal.h
+unixserver.o: $(top_srcdir)/internal/array.h
+unixserver.o: $(top_srcdir)/internal/compilers.h
+unixserver.o: $(top_srcdir)/internal/error.h
+unixserver.o: $(top_srcdir)/internal/gc.h
+unixserver.o: $(top_srcdir)/internal/io.h
+unixserver.o: $(top_srcdir)/internal/serial.h
+unixserver.o: $(top_srcdir)/internal/static_assert.h
+unixserver.o: $(top_srcdir)/internal/string.h
+unixserver.o: $(top_srcdir)/internal/thread.h
+unixserver.o: $(top_srcdir)/internal/vm.h
+unixserver.o: $(top_srcdir)/internal/warnings.h
+unixserver.o: constdefs.h
+unixserver.o: rubysocket.h
+unixserver.o: sockport.h
+unixserver.o: unixserver.c
+unixsocket.o: $(RUBY_EXTCONF_H)
+unixsocket.o: $(arch_hdrdir)/ruby/config.h
+unixsocket.o: $(hdrdir)/ruby/assert.h
+unixsocket.o: $(hdrdir)/ruby/backward.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/assume.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/bool.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/inttypes.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/limits.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/long_long.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/stdalign.h
+unixsocket.o: $(hdrdir)/ruby/backward/2/stdarg.h
+unixsocket.o: $(hdrdir)/ruby/defines.h
+unixsocket.o: $(hdrdir)/ruby/encoding.h
+unixsocket.o: $(hdrdir)/ruby/fiber/scheduler.h
+unixsocket.o: $(hdrdir)/ruby/intern.h
+unixsocket.o: $(hdrdir)/ruby/internal/anyargs.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+unixsocket.o: $(hdrdir)/ruby/internal/assume.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/artificial.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/cold.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/const.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/error.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/format.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/noalias.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/warning.h
+unixsocket.o: $(hdrdir)/ruby/internal/attr/weakref.h
+unixsocket.o: $(hdrdir)/ruby/internal/cast.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+unixsocket.o: $(hdrdir)/ruby/internal/compiler_since.h
+unixsocket.o: $(hdrdir)/ruby/internal/config.h
+unixsocket.o: $(hdrdir)/ruby/internal/constant_p.h
+unixsocket.o: $(hdrdir)/ruby/internal/core.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rarray.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rbasic.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rbignum.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rclass.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rdata.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rfile.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rhash.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/robject.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rregexp.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rstring.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rstruct.h
+unixsocket.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+unixsocket.o: $(hdrdir)/ruby/internal/ctype.h
+unixsocket.o: $(hdrdir)/ruby/internal/dllexport.h
+unixsocket.o: $(hdrdir)/ruby/internal/dosish.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/re.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/string.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+unixsocket.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+unixsocket.o: $(hdrdir)/ruby/internal/error.h
+unixsocket.o: $(hdrdir)/ruby/internal/eval.h
+unixsocket.o: $(hdrdir)/ruby/internal/event.h
+unixsocket.o: $(hdrdir)/ruby/internal/fl_type.h
+unixsocket.o: $(hdrdir)/ruby/internal/gc.h
+unixsocket.o: $(hdrdir)/ruby/internal/glob.h
+unixsocket.o: $(hdrdir)/ruby/internal/globals.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/attribute.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/builtin.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/extension.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/feature.h
+unixsocket.o: $(hdrdir)/ruby/internal/has/warning.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/array.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/bignum.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/class.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/compar.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/complex.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/cont.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/dir.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/enum.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/error.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/io.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/load.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/marshal.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/numeric.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/object.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/parse.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/proc.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/process.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/random.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/range.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/rational.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/re.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/select.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/string.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/struct.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/thread.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/time.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/variable.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/vm.h
+unixsocket.o: $(hdrdir)/ruby/internal/interpreter.h
+unixsocket.o: $(hdrdir)/ruby/internal/iterator.h
+unixsocket.o: $(hdrdir)/ruby/internal/memory.h
+unixsocket.o: $(hdrdir)/ruby/internal/method.h
+unixsocket.o: $(hdrdir)/ruby/internal/module.h
+unixsocket.o: $(hdrdir)/ruby/internal/newobj.h
+unixsocket.o: $(hdrdir)/ruby/internal/rgengc.h
+unixsocket.o: $(hdrdir)/ruby/internal/scan_args.h
+unixsocket.o: $(hdrdir)/ruby/internal/special_consts.h
+unixsocket.o: $(hdrdir)/ruby/internal/static_assert.h
+unixsocket.o: $(hdrdir)/ruby/internal/stdalign.h
+unixsocket.o: $(hdrdir)/ruby/internal/stdbool.h
+unixsocket.o: $(hdrdir)/ruby/internal/symbol.h
+unixsocket.o: $(hdrdir)/ruby/internal/value.h
+unixsocket.o: $(hdrdir)/ruby/internal/value_type.h
+unixsocket.o: $(hdrdir)/ruby/internal/variable.h
+unixsocket.o: $(hdrdir)/ruby/internal/warning_push.h
+unixsocket.o: $(hdrdir)/ruby/internal/xmalloc.h
+unixsocket.o: $(hdrdir)/ruby/io.h
+unixsocket.o: $(hdrdir)/ruby/missing.h
+unixsocket.o: $(hdrdir)/ruby/onigmo.h
+unixsocket.o: $(hdrdir)/ruby/oniguruma.h
+unixsocket.o: $(hdrdir)/ruby/ruby.h
+unixsocket.o: $(hdrdir)/ruby/st.h
+unixsocket.o: $(hdrdir)/ruby/subst.h
+unixsocket.o: $(hdrdir)/ruby/thread.h
+unixsocket.o: $(hdrdir)/ruby/util.h
+unixsocket.o: $(top_srcdir)/internal.h
+unixsocket.o: $(top_srcdir)/internal/array.h
+unixsocket.o: $(top_srcdir)/internal/compilers.h
+unixsocket.o: $(top_srcdir)/internal/error.h
+unixsocket.o: $(top_srcdir)/internal/gc.h
+unixsocket.o: $(top_srcdir)/internal/io.h
+unixsocket.o: $(top_srcdir)/internal/serial.h
+unixsocket.o: $(top_srcdir)/internal/static_assert.h
+unixsocket.o: $(top_srcdir)/internal/string.h
+unixsocket.o: $(top_srcdir)/internal/thread.h
+unixsocket.o: $(top_srcdir)/internal/vm.h
+unixsocket.o: $(top_srcdir)/internal/warnings.h
+unixsocket.o: constdefs.h
+unixsocket.o: rubysocket.h
+unixsocket.o: sockport.h
+unixsocket.o: unixsocket.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 87409394ff..b70a862414 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -1,43 +1,7 @@
+# frozen_string_literal: false
require 'mkmf'
-$INCFLAGS << " -I$(topdir) -I$(top_srcdir)"
-
-case RUBY_PLATFORM
-when /(ms|bcc)win(32|64)|mingw/
- test_func = "WSACleanup"
- have_library("ws2_32", "WSACleanup")
-when /cygwin/
- test_func = "socket"
-when /beos/
- test_func = "socket"
- have_library("net", "socket")
-when /haiku/
- test_func = "socket"
- have_library("network", "socket")
-when /i386-os2_emx/
- test_func = "socket"
- have_library("socket", "socket")
-else
- test_func = "socket"
- have_library("nsl", "t_open")
- have_library("socket", "socket")
-end
-
-unless $mswin or $bccwin or $mingw
- headers = %w<sys/types.h netdb.h string.h sys/socket.h netinet/in.h>
-end
-if /solaris/ =~ RUBY_PLATFORM and !try_compile("")
- # bug of gcc 3.0 on Solaris 8 ?
- headers << "sys/feature_tests.h"
-end
-if have_header("arpa/inet.h")
- headers << "arpa/inet.h"
-end
-
-ipv6 = false
-default_ipv6 = /cygwin|beos|haiku/ !~ RUBY_PLATFORM
-if enable_config("ipv6", default_ipv6)
- if checking_for("ipv6") {try_link(<<EOF)}
+AF_INET6_SOCKET_CREATION_TEST = <<EOF
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
@@ -49,82 +13,116 @@ main(void)
return 0;
}
EOF
- $defs << "-DENABLE_IPV6" << "-DINET6"
- ipv6 = true
- end
-end
-if ipv6
- if $mingw
- $CPPFLAGS << " -D_WIN32_WINNT=0x501" unless $CPPFLAGS.include?("_WIN32_WINNT")
- end
- ipv6lib = nil
- class << (fmt = "unknown")
- def %(s) s || self end
- end
- idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)})
- checking_for("ipv6 type", fmt) do
- if have_macro("IPV6_INRIA_VERSION", "netinet/in.h")
- "inria"
- elsif have_macro("__KAME__", "netinet/in.h")
- have_library(ipv6lib = "inet6")
- "kame"
- elsif have_macro("_TOSHIBA_INET6", "sys/param.h")
- have_library(ipv6lib = "inet6") and "toshiba"
- elsif have_macro("__V6D__", "sys/v6config.h")
- have_library(ipv6lib = "v6") and "v6d"
- elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h")
- have_library(ipv6lib = "inet6") and "zeta"
- elsif ipv6lib = with_config("ipv6-lib")
- warn <<EOS
---with-ipv6-lib and --with-ipv6-libdir option will be obsolete, use
---with-inet6lib and --with-inet6-{include,lib} options instead.
-EOS
- find_library(ipv6lib, nil, with_config("ipv6-libdir", ldirs)) and
- ipv6lib
- elsif have_library("inet6")
- "inet6"
- end
- end or not ipv6lib or abort <<EOS
-
-Fatal: no #{ipv6lib} library found. cannot continue.
-You need to fetch lib#{ipv6lib}.a from appropriate
-ipv6 kit and compile beforehand.
-EOS
-end
+GETADDRINFO_GETNAMEINFO_TEST = <<EOF
+#include <stdlib.h>
-if have_struct_member("struct sockaddr_in", "sin_len", headers)
- $defs[-1] = "-DHAVE_SIN_LEN"
-end
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
-# doug's fix, NOW add -Dss_family... only if required!
-doug = proc {have_struct_member("struct sockaddr_storage", "ss_family", headers)}
-if (doug[] or
- with_cppflags($CPPFLAGS + " -Dss_family=__ss_family", &doug))
- $defs[-1] = "-DHAVE_SOCKADDR_STORAGE"
- doug = proc {have_struct_member("struct sockaddr_storage", "ss_len", headers)}
- doug[] or with_cppflags($CPPFLAGS + " -Dss_len=__ss_len", &doug)
-end
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
-if have_struct_member("struct sockaddr", "sa_len", headers)
- $defs[-1] = "-DHAVE_SA_LEN "
-end
+int
+main(void)
+{
+ int passive, gaierr, inet4 = 0, inet6 = 0;
+ struct addrinfo hints, *ai, *aitop;
+ char straddr[INET6_ADDRSTRLEN], strport[16];
+#ifdef _WIN32
+ WSADATA retdata;
-have_header("netinet/tcp.h") if /cygwin/ !~ RUBY_PLATFORM # for cygwin 1.1.5
-have_header("netinet/udp.h")
+ WSAStartup(MAKEWORD(2, 0), &retdata);
+#endif
-if !have_macro("IPPROTO_IPV6", headers) && have_const("IPPROTO_IPV6", headers)
- IO.read(File.join(File.dirname(__FILE__), "mkconstants.rb")).sub(/\A.*^__END__$/m, '').split(/\r?\n/).grep(/\AIPPROTO_\w*/){$&}.each {|name|
- have_const(name, headers) unless $defs.include?("-DHAVE_CONST_#{name.upcase}")
+ for (passive = 0; passive <= 1; passive++) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = passive ? AI_PASSIVE : 0;
+ hints.ai_socktype = SOCK_STREAM;
+ if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) {
+ (void)gai_strerror(gaierr);
+ goto bad;
+ }
+ for (ai = aitop; ai; ai = ai->ai_next) {
+ if (ai->ai_family == AF_LOCAL) continue;
+ if (ai->ai_addr == NULL)
+ goto bad;
+#if defined(_AIX)
+ if (ai->ai_family == AF_INET6 && passive) {
+ inet6++;
+ continue;
+ }
+ ai->ai_addr->sa_len = ai->ai_addrlen;
+ ai->ai_addr->sa_family = ai->ai_family;
+#endif
+ if (ai->ai_addrlen == 0 ||
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ straddr, sizeof(straddr), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+ goto bad;
+ }
+ if (strcmp(strport, "54321") != 0) {
+ goto bad;
+ }
+ switch (ai->ai_family) {
+ case AF_INET:
+ if (passive) {
+ if (strcmp(straddr, "0.0.0.0") != 0) {
+ goto bad;
+ }
+ } else {
+ if (strcmp(straddr, "127.0.0.1") != 0) {
+ goto bad;
+ }
+ }
+ inet4++;
+ break;
+ case AF_INET6:
+ if (passive) {
+ if (strcmp(straddr, "::") != 0) {
+ goto bad;
+ }
+ } else {
+ if (strcmp(straddr, "::1") != 0) {
+ goto bad;
+ }
+ }
+ inet6++;
+ break;
+ case AF_UNSPEC:
+ goto bad;
+ break;
+ default:
+ /* another family support? */
+ break;
+ }
+ }
}
-end
-if have_func("sendmsg") | have_func("recvmsg")
- have_struct_member('struct msghdr', 'msg_control', ['sys/types.h', 'sys/socket.h'])
- have_struct_member('struct msghdr', 'msg_accrights', ['sys/types.h', 'sys/socket.h'])
-end
+ if (!(inet4 == 0 || inet4 == 2))
+ goto bad;
+ if (!(inet6 == 0 || inet6 == 2))
+ goto bad;
+
+ if (aitop)
+ freeaddrinfo(aitop);
+ return EXIT_SUCCESS;
+
+ bad:
+ if (aitop)
+ freeaddrinfo(aitop);
+ return EXIT_FAILURE;
+}
+EOF
-if checking_for("recvmsg() with MSG_PEEK allocate file descriptors") {try_run(cpp_include(headers) + <<'EOF')}
+RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST = <<'EOF'
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -244,147 +242,221 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS;
}
EOF
- $defs << "-DFD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK"
+
+def test_recvmsg_with_msg_peek_creates_fds(headers)
+ case RUBY_PLATFORM
+ when /linux/
+ # Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
+ close_fds = true
+ when /bsd|darwin/
+ # FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
+ # allocate fds by recvmsg with MSG_PEEK.
+ # [ruby-dev:44189]
+ # http://bugs.ruby-lang.org/issues/5075
+ close_fds = false
+ when /cygwin/
+ # Cygwin doesn't support fd passing.
+ # http://cygwin.com/ml/cygwin/2003-09/msg01808.html
+ close_fds = false
+ else
+ close_fds = nil
+ end
+ if !CROSS_COMPILING
+ if checking_for("recvmsg() with MSG_PEEK allocate file descriptors") {
+ try_run(cpp_include(headers) + RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST)
+ }
+ if close_fds == false
+ warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation unexpected."
+ elsif close_fds == nil
+ puts "info: #{RUBY_PLATFORM} recvmsg() with MSG_PEEK allocates fds on fd-passing."
+ end
+ close_fds = true
+ else
+ if close_fds == true
+ warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation expected."
+ elsif close_fds == nil
+ puts "info: #{RUBY_PLATFORM}: recvmsg() with MSG_PEEK doesn't allocates fds on fd-passing."
+ end
+ close_fds = false
+ end
+ end
+ if close_fds == nil
+ abort <<EOS
+Fatal: cannot test fd-passing recvmsg() with MSG_PEEK behavor
+because cross-compilation for #{RUBY_PLATFORM}.
+If recvmsg() with MSG_PEEK allocates fds on fd passing:
+--enable-close-fds-by-recvmsg-with-peek
+If recvmsg() with MSG_PEEK doesn't allocate fds on fd passing:
+--disable-close-fds-by-recvmsg-with-peek
+EOS
+ end
+ close_fds
end
-getaddr_info_ok = (enable_config("wide-getaddrinfo") && :wide) ||
- (checking_for("wide getaddrinfo") {try_run(<<EOF)} && :os)
-#{cpp_include(headers)}
-#include <stdlib.h>
+$INCFLAGS << " -I$(topdir) -I$(top_srcdir)"
-#ifndef EXIT_SUCCESS
-#define EXIT_SUCCESS 0
-#endif
-#ifndef EXIT_FAILURE
-#define EXIT_FAILURE 1
-#endif
+if /darwin/ =~ RUBY_PLATFORM
+ # For IPv6 extension header access on OS X 10.7+ [Bug #8517]
+ $CFLAGS << " -D__APPLE_USE_RFC_3542"
+end
-#ifndef AF_LOCAL
-#define AF_LOCAL AF_UNIX
-#endif
+headers = []
+unless $mswin or $mingw
+ headers = %w<sys/types.h netdb.h string.h sys/socket.h netinet/in.h>
+end
-int
-main(void)
-{
- int passive, gaierr, inet4 = 0, inet6 = 0;
- struct addrinfo hints, *ai, *aitop;
- char straddr[INET6_ADDRSTRLEN], strport[16];
-#ifdef _WIN32
- WSADATA retdata;
+%w[
+ sys/uio.h
+ xti.h
+ netinet/in_systm.h
+ netinet/tcp.h
+ netinet/tcp_fsm.h
+ netinet/udp.h
+ arpa/inet.h
+ netpacket/packet.h
+ net/ethernet.h
+ sys/un.h
+ ifaddrs.h
+ sys/ioctl.h
+ sys/sockio.h
+ net/if.h
+ sys/param.h
+ sys/ucred.h
+ ucred.h
+ net/if_dl.h
+ arpa/nameser.h
+ resolv.h
+].each {|h|
+ if have_header(h, headers)
+ headers << h
+ end
+}
- WSAStartup(MAKEWORD(2, 0), &retdata);
-#endif
+have_struct_member("struct sockaddr", "sa_len", headers) # 4.4BSD
+have_struct_member("struct sockaddr_in", "sin_len", headers) # 4.4BSD
+have_struct_member("struct sockaddr_in6", "sin6_len", headers) # 4.4BSD
- for (passive = 0; passive <= 1; passive++) {
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = passive ? AI_PASSIVE : 0;
- hints.ai_socktype = SOCK_STREAM;
- if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) {
- (void)gai_strerror(gaierr);
- goto bad;
- }
- for (ai = aitop; ai; ai = ai->ai_next) {
- if (ai->ai_family == AF_LOCAL) continue;
- if (ai->ai_addr == NULL)
- goto bad;
-#if defined(_AIX)
- if (ai->ai_family == AF_INET6 && passive) {
- inet6++;
- continue;
- }
- ai->ai_addr->sa_len = ai->ai_addrlen;
- ai->ai_addr->sa_family = ai->ai_family;
-#endif
- if (ai->ai_addrlen == 0 ||
- getnameinfo(ai->ai_addr, ai->ai_addrlen,
- straddr, sizeof(straddr), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- goto bad;
- }
- if (strcmp(strport, "54321") != 0) {
- goto bad;
- }
- switch (ai->ai_family) {
- case AF_INET:
- if (passive) {
- if (strcmp(straddr, "0.0.0.0") != 0) {
- goto bad;
- }
- } else {
- if (strcmp(straddr, "127.0.0.1") != 0) {
- goto bad;
- }
- }
- inet4++;
- break;
- case AF_INET6:
- if (passive) {
- if (strcmp(straddr, "::") != 0) {
- goto bad;
- }
- } else {
- if (strcmp(straddr, "::1") != 0) {
- goto bad;
- }
- }
- inet6++;
- break;
- case AF_UNSPEC:
- goto bad;
- break;
- default:
- /* another family support? */
- break;
- }
- }
- }
+if have_type("struct sockaddr_un", headers) # POSIX
+ have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
+end
- if (!(inet4 == 0 || inet4 == 2))
- goto bad;
- if (!(inet6 == 0 || inet6 == 2))
- goto bad;
+have_type("struct sockaddr_dl", headers) # AF_LINK address. 4.4BSD since Net2
- if (aitop)
- freeaddrinfo(aitop);
- return EXIT_SUCCESS;
+have_type("struct sockaddr_storage", headers)
- bad:
- if (aitop)
- freeaddrinfo(aitop);
- return EXIT_FAILURE;
+have_type("struct addrinfo", headers)
+
+if have_type("socklen_t", headers)
+ if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
+ $defs << "-DRSTRING_SOCKLEN=(socklen_t)RSTRING_LEN"
+ end
+end
+
+have_type("struct in_pktinfo", headers) {|src|
+ src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IP) && defined(IP_PKTINFO)") <<
+ "#else\n" << "#error\n" << ">>>>>> no in_pktinfo <<<<<<\n" << "#endif\n"
+} and have_struct_member("struct in_pktinfo", "ipi_spec_dst", headers)
+have_type("struct in6_pktinfo", headers) {|src|
+ src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)") <<
+ "#else\n" << "#error\n" << ">>>>>> no in6_pktinfo <<<<<<\n" << "#endif\n"
}
-EOF
-if ipv6 and not getaddr_info_ok
- abort <<EOS
-Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
-But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
-you cannot compile IPv6 socket classes with broken these functions.
-You can try --enable-wide-getaddrinfo.
-EOS
+have_type("struct sockcred", headers)
+have_type("struct cmsgcred", headers)
+
+have_type("struct ip_mreq", headers) # 4.4BSD
+have_type("struct ip_mreqn", headers) # Linux 2.4
+have_type("struct ipv6_mreq", headers) # RFC 3493
+
+have_msg_control = nil
+have_msg_control = have_struct_member('struct msghdr', 'msg_control', headers) unless $mswin or $mingw
+have_struct_member('struct msghdr', 'msg_accrights', headers)
+
+if have_type("struct tcp_info", headers)
+ have_const("TCP_ESTABLISHED", headers)
+ have_const("TCP_SYN_SENT", headers)
+ have_const("TCP_SYN_RECV", headers)
+ have_const("TCP_FIN_WAIT1", headers)
+ have_const("TCP_FIN_WAIT2", headers)
+ have_const("TCP_TIME_WAIT", headers)
+ have_const("TCP_CLOSE", headers)
+ have_const("TCP_CLOSE_WAIT", headers)
+ have_const("TCP_LAST_ACK", headers)
+ have_const("TCP_LISTEN", headers)
+ have_const("TCP_CLOSING", headers)
+ have_struct_member('struct tcp_info', 'tcpi_state', headers)
+ if /solaris/ !~ RUBY_PLATFORM
+ have_struct_member('struct tcp_info', 'tcpi_ca_state', headers)
+ end
+ have_struct_member('struct tcp_info', 'tcpi_retransmits', headers)
+ have_struct_member('struct tcp_info', 'tcpi_probes', headers)
+ have_struct_member('struct tcp_info', 'tcpi_backoff', headers)
+ have_struct_member('struct tcp_info', 'tcpi_options', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_wscale', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_wscale', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rto', headers)
+ have_struct_member('struct tcp_info', 'tcpi_ato', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_mss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_mss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_unacked', headers)
+ have_struct_member('struct tcp_info', 'tcpi_sacked', headers)
+ have_struct_member('struct tcp_info', 'tcpi_lost', headers)
+ have_struct_member('struct tcp_info', 'tcpi_retrans', headers)
+ have_struct_member('struct tcp_info', 'tcpi_fackets', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_data_sent', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_ack_sent', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_data_recv', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_ack_recv', headers)
+ have_struct_member('struct tcp_info', 'tcpi_pmtu', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_ssthresh', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rtt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rttvar', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_ssthresh', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_cwnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_advmss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_reordering', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_rtt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_space', headers)
+ have_struct_member('struct tcp_info', 'tcpi_total_retrans', headers)
+
+ # FreeBSD extension
+ have_struct_member('struct tcp_info', 'tcpi_snd_wnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_bwnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_nxt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_nxt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_toe_tid', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_rexmitpack', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_ooopack', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_zerowin', headers)
end
-case with_config("lookup-order-hack", "UNSPEC")
-when "INET"
- $defs << "-DLOOKUP_ORDER_HACK_INET"
-when "INET6"
- $defs << "-DLOOKUP_ORDER_HACK_INET6"
-when "UNSPEC"
- # nothing special
+case RUBY_PLATFORM
+when /mswin(32|64)|mingw/
+ test_func = "WSACleanup"
+ have_library("iphlpapi")
+ have_library("ws2_32", "WSACleanup", headers)
+when /cygwin/
+ test_func = "socket(0,0,0)"
+when /haiku/
+ test_func = "socket(0,0,0)"
+ have_library("network", "socket(0,0,0)", headers)
else
- abort <<EOS
-
-Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
-EOS
+ test_func = "socket(0,0,0)"
+ have_library("nsl", 't_open("", 0, (struct t_info *)NULL)', headers) # SunOS
+ have_library("socket", "socket(0,0,0)", headers) # SunOS
end
-have_type("struct addrinfo", headers)
-have_func("freehostent")
-have_func("freeaddrinfo")
-if /haiku/ !~ RUBY_PLATFORM and have_func("gai_strerror")
- if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
+if have_func(test_func, headers)
+
+ have_func("sendmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
+ have_recvmsg = have_func("recvmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
+
+ have_func("freehostent((struct hostent *)NULL)", headers) # RFC 2553
+ have_func("freeaddrinfo((struct addrinfo *)NULL)", headers) # RFC 2553
+
+ if /haiku/ !~ RUBY_PLATFORM and
+ have_func("gai_strerror(0)", headers) # POSIX
+ if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
#{cpp_include(headers)}
#include <stdlib.h>
void
@@ -393,109 +465,218 @@ conftest_gai_strerror_is_const()
*gai_strerror(0) = 0;
}
EOF
- $defs << "-DGAI_STRERROR_CONST"
+ $defs << "-DGAI_STRERROR_CONST"
+ end
end
-end
-have_func("accept4")
-
-$objs = [
- "init.#{$OBJEXT}",
- "constants.#{$OBJEXT}",
- "basicsocket.#{$OBJEXT}",
- "socket.#{$OBJEXT}",
- "ipsocket.#{$OBJEXT}",
- "tcpsocket.#{$OBJEXT}",
- "tcpserver.#{$OBJEXT}",
- "sockssocket.#{$OBJEXT}",
- "udpsocket.#{$OBJEXT}",
- "unixsocket.#{$OBJEXT}",
- "unixserver.#{$OBJEXT}",
- "option.#{$OBJEXT}",
- "ancdata.#{$OBJEXT}",
- "raddrinfo.#{$OBJEXT}"
-]
-
-if getaddr_info_ok == :wide or
- !have_func("getnameinfo", headers) or !have_func("getaddrinfo", headers)
- if have_struct_member("struct in6_addr", "s6_addr8", headers)
- $defs[-1] = "s6_addr=s6_addr8"
- end
- if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
- $defs[-1] = "-DFAITH"
- end
- $CPPFLAGS="-I. "+$CPPFLAGS
- $objs += ["getaddrinfo.#{$OBJEXT}"]
- $objs += ["getnameinfo.#{$OBJEXT}"]
- $defs << "-DGETADDRINFO_EMU"
-end
+ have_func("accept4", headers)
-have_func('inet_ntop(0, (const void *)0, (char *)0, 0)') or
- have_func("inet_ntoa(*(struct in_addr *)NULL)")
-have_func('inet_pton(0, "", (void *)0)') or have_func('inet_aton("", (struct in_addr *)0)')
-have_func('getservbyport(0, "")')
-have_header("arpa/nameser.h")
-have_header("resolv.h")
+ have_func('inet_ntop(0, (const void *)0, (char *)0, 0)', headers) or
+ have_func("inet_ntoa(*(struct in_addr *)NULL)", headers)
+ have_func('inet_pton(0, "", (void *)0)', headers) or
+ have_func('inet_aton("", (struct in_addr *)0)', headers)
+ have_func('getservbyport(0, "")', headers)
+ have_func("getifaddrs((struct ifaddrs **)NULL)", headers)
+ have_struct_member("struct if_data", "ifi_vhid", headers) # FreeBSD
-have_header("ifaddrs.h")
-have_func("getifaddrs")
-have_header("sys/ioctl.h")
-have_header("sys/sockio.h")
-have_header("net/if.h", headers)
+ have_func("getpeereid", headers)
-have_header("sys/param.h", headers)
-have_header("sys/ucred.h", headers)
+ have_func("getpeerucred(0, (ucred_t **)NULL)", headers) # SunOS
-unless have_type("socklen_t", headers)
- $defs << "-Dsocklen_t=int"
-end
+ have_func_decl = proc do |name, headers|
+ # check if there is a declaration of <name> by trying to declare
+ # both "int <name>(void)" and "void <name>(void)"
+ # (at least one attempt should fail if there is a declaration)
+ if !checking_for("declaration of #{name}()") {!%w[int void].all? {|ret| try_compile(<<EOF)}}
+#{cpp_include(headers)}
+#{ret} #{name}(void);
+EOF
+ $defs << "-DNEED_#{name.tr_cpp}_DECL"
+ end
+ end
+ if have_func('if_indextoname(0, "")', headers)
+ have_func_decl["if_indextoname", headers]
+ end
+ if have_func('if_nametoindex("")', headers)
+ have_func_decl["if_nametoindex", headers]
+ end
-have_header("sys/un.h")
-have_header("sys/uio.h")
-have_type("struct in_pktinfo", headers) {|src|
- src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IP) && defined(IP_PKTINFO)") <<
- "#else\n" << "#error\n" << ">>>>>> no in_pktinfo <<<<<<\n" << "#endif\n"
-} and have_struct_member("struct in_pktinfo", "ipi_spec_dst", headers)
-have_type("struct in6_pktinfo", headers) {|src|
- src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)") <<
- "#else\n" << "#error\n" << ">>>>>> no in6_pktinfo <<<<<<\n" << "#endif\n"
-}
+ have_func("hsterror", headers)
+ have_func('getipnodebyname("", 0, 0, (int *)0)', headers) # RFC 2553
+ have_func('gethostbyname2("", 0)', headers) # RFC 2133
+ have_func("socketpair(0, 0, 0, 0)", headers)
+ unless have_func("gethostname((char *)0, 0)", headers)
+ have_func("uname((struct utsname *)NULL)", headers)
+ end
-have_type("struct sockcred", headers)
-have_type("struct cmsgcred", headers)
+ ipv6 = false
+ default_ipv6 = /haiku/ !~ RUBY_PLATFORM
+ if enable_config("ipv6", default_ipv6)
+ if checking_for("ipv6") {try_link(AF_INET6_SOCKET_CREATION_TEST)}
+ $defs << "-DENABLE_IPV6" << "-DINET6"
+ ipv6 = true
+ end
+ end
-have_func("getpeereid")
+ if ipv6
+ if $mingw
+ $CPPFLAGS << " -D_WIN32_WINNT=0x501" unless $CPPFLAGS.include?("_WIN32_WINNT")
+ end
+ ipv6lib = nil
+ class << (fmt = "unknown")
+ def %(s) s || self end
+ end
+ idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)})
+ checking_for("ipv6 type", fmt) do
+ if have_macro("IPV6_INRIA_VERSION", "netinet/in.h")
+ "inria"
+ elsif have_macro("__KAME__", "netinet/in.h")
+ have_library(ipv6lib = "inet6")
+ "kame"
+ elsif have_macro("_TOSHIBA_INET6", "sys/param.h")
+ have_library(ipv6lib = "inet6") and "toshiba"
+ elsif have_macro("__V6D__", "sys/v6config.h")
+ have_library(ipv6lib = "v6") and "v6d"
+ elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h")
+ have_library(ipv6lib = "inet6") and "zeta"
+ elsif have_library("inet6")
+ "inet6"
+ end
+ end or not ipv6lib or abort <<EOS
-have_header("ucred.h", headers)
-have_func("getpeerucred")
+Fatal: no #{ipv6lib} library found. cannot continue.
+You need to fetch lib#{ipv6lib}.a from appropriate
+ipv6 kit and compile beforehand.
+EOS
+ end
+
+ if !have_macro("IPPROTO_IPV6", headers) && have_const("IPPROTO_IPV6", headers)
+ IO.read(File.join(File.dirname(__FILE__), "mkconstants.rb")).sub(/\A.*^__END__$/m, '').split(/\r?\n/).grep(/\AIPPROTO_\w*/){$&}.each {|name|
+ have_const(name, headers) unless $defs.include?("-DHAVE_CONST_#{name.upcase}")
+ }
+ end
-have_func("if_indextoname")
+ if enable_config("close-fds-by-recvmsg-with-peek") {
+ have_msg_control && have_recvmsg &&
+ have_const('AF_UNIX', headers) && have_const('SCM_RIGHTS', headers) &&
+ test_recvmsg_with_msg_peek_creates_fds(headers)
+ }
+ $defs << "-DFD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK"
+ end
-have_type("struct ip_mreq", headers) # 4.4BSD
-have_type("struct ip_mreqn", headers) # Linux 2.4
-have_type("struct ipv6_mreq", headers) # RFC 3493
+ case enable_config("wide-getaddrinfo")
+ when true
+ getaddr_info_ok = :wide
+ when nil, false
+ getaddr_info_ok = (:wide if getaddr_info_ok.nil?)
+ if have_func("getnameinfo", headers) and have_func("getaddrinfo", headers)
+ if CROSS_COMPILING ||
+ $mingw || $mswin ||
+ checking_for("system getaddrinfo working") {
+ try_run(cpp_include(headers) + GETADDRINFO_GETNAMEINFO_TEST)
+ }
+ getaddr_info_ok = :os
+ end
+ end
+ else
+ raise "unexpected enable_config() value"
+ end
-# workaround for recent Windows SDK
-$defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")
+ if ipv6 and not getaddr_info_ok
+ abort <<EOS
-$distcleanfiles << "constants.h" << "constdefs.*"
+Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
+But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
+you cannot compile IPv6 socket classes with broken these functions.
+You can try --enable-wide-getaddrinfo.
+EOS
+ end
+
+ case with_config("lookup-order-hack", "UNSPEC")
+ when "INET"
+ $defs << "-DLOOKUP_ORDER_HACK_INET"
+ when "INET6"
+ $defs << "-DLOOKUP_ORDER_HACK_INET6"
+ when "UNSPEC"
+ # nothing special
+ else
+ abort <<EOS
-if have_func(test_func)
- have_func("hsterror")
- have_func("getipnodebyname") or have_func("gethostbyname2")
- if !have_func("socketpair(0, 0, 0, 0)") and have_func("rb_w32_socketpair(0, 0, 0, 0)")
- $defs << "-Dsocketpair(a,b,c,d)=rb_w32_socketpair((a),(b),(c),(d))"
- $defs << "-DHAVE_SOCKETPAIR"
+Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
+EOS
end
- unless have_func("gethostname((char *)0, 0)")
- have_func("uname")
+
+ $objs = [
+ "init.#{$OBJEXT}",
+ "constants.#{$OBJEXT}",
+ "basicsocket.#{$OBJEXT}",
+ "socket.#{$OBJEXT}",
+ "ipsocket.#{$OBJEXT}",
+ "tcpsocket.#{$OBJEXT}",
+ "tcpserver.#{$OBJEXT}",
+ "sockssocket.#{$OBJEXT}",
+ "udpsocket.#{$OBJEXT}",
+ "unixsocket.#{$OBJEXT}",
+ "unixserver.#{$OBJEXT}",
+ "option.#{$OBJEXT}",
+ "ancdata.#{$OBJEXT}",
+ "raddrinfo.#{$OBJEXT}",
+ "ifaddr.#{$OBJEXT}"
+ ]
+
+ if getaddr_info_ok == :wide
+ if !have_type("struct in6_addr", headers) and have_type("struct in_addr6", headers)
+ $defs.pop(2)
+ $defs << "-Din_addr6=in6_addr"
+ end
+ if have_struct_member("struct in6_addr", "s6_addr8", headers)
+ $defs[-1] = "-Ds6_addr=s6_addr8"
+ end
+ if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
+ $defs[-1] = "-DFAITH"
+ end
+ $CPPFLAGS="-I. "+$CPPFLAGS
+ $objs += ["getaddrinfo.#{$OBJEXT}"]
+ $objs += ["getnameinfo.#{$OBJEXT}"]
+ $defs << "-DGETADDRINFO_EMU"
end
+
+ # workaround for recent Windows SDK
+ $defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")
+
+ $distcleanfiles << "constants.h" << "constdefs.*"
+
if enable_config("socks", ENV["SOCKS_SERVER"])
if have_library("socks5", "SOCKSinit")
$defs << "-DSOCKS5" << "-DSOCKS"
- elsif have_library("socks", "Rconnect")
+ elsif have_library("socksd", "Rconnect") || have_library("socks", "Rconnect")
$defs << "-DSOCKS"
end
end
+
+ hdr = "netinet6/in6.h"
+ if /darwin/ =~ RUBY_PLATFORM and !try_compile(<<"SRC", nil, :werror=>true)
+#include <netinet/in.h>
+int t(struct in6_addr *addr) {return IN6_IS_ADDR_UNSPECIFIED(addr);}
+SRC
+ print "fixing apple's netinet6/in6.h ..."; $stdout.flush
+ in6 = File.read("/usr/include/#{hdr}")
+ if in6.gsub!(/\*\(const\s+__uint32_t\s+\*\)\(const\s+void\s+\*\)\(&(\(\w+\))->s6_addr\[(\d+)\]\)/) do
+ i, r = $2.to_i.divmod(4)
+ if r.zero?
+ "#$1->__u6_addr.__u6_addr32[#{i}]"
+ else
+ $&
+ end
+ end
+ FileUtils.mkdir_p(File.dirname(hdr))
+ open(hdr, "w") {|f| f.write(in6)}
+ $distcleanfiles << hdr
+ $distcleandirs << File.dirname(hdr)
+ puts "done"
+ else
+ puts "not needed"
+ end
+ end
create_makefile("socket")
end
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index aa966b3c52..ce6dc40478 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -45,11 +45,7 @@
#include <sys/types.h>
#ifndef _WIN32
#include <sys/param.h>
-#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
-# include <net/socket.h>
-#else
-# include <sys/socket.h>
-#endif
+#include <sys/socket.h>
#include <netinet/in.h>
#if defined(HAVE_ARPA_INET_H)
#include <arpa/inet.h>
@@ -66,6 +62,9 @@
#endif
#include <unistd.h>
#else
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#include <windows.h>
+#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
@@ -80,6 +79,10 @@
#include <socks.h>
#endif
+#ifndef HAVE_TYPE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
#include "addrinfo.h"
#include "sockport.h"
@@ -146,6 +149,7 @@ static int get_addr __P((const char *, int, struct addrinfo **,
struct addrinfo *, int));
static int str_isnumber __P((const char *));
+#ifndef HAVE_GAI_STRERROR
static const char *const ai_errlist[] = {
"success.",
"address family for hostname not supported.", /* EAI_ADDRFAMILY */
@@ -163,6 +167,7 @@ static const char *const ai_errlist[] = {
"resolved protocol is unknown.", /* EAI_PROTOCOL */
"unknown error.", /* EAI_MAX */
};
+#endif
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
@@ -184,9 +189,9 @@ if (pai->ai_flags & AI_CANONNAME) {\
}\
memcpy((ai), pai, sizeof(struct addrinfo));\
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
- memset((ai)->ai_addr, 0, (afd)->a_socklen);\
- SET_SA_LEN((ai)->ai_addr, (ai)->ai_addrlen = (afd)->a_socklen);\
- (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
+ (ai)->ai_family = (afd)->a_af;\
+ (ai)->ai_addrlen = (afd)->a_socklen;\
+ INIT_SOCKADDR((ai)->ai_addr, (afd)->a_af, (afd)->a_socklen);\
((struct sockinet *)(ai)->ai_addr)->si_port = (port);\
p = (char *)((ai)->ai_addr);\
memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
@@ -432,11 +437,8 @@ getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *h
s = socket(afd->a_af, SOCK_DGRAM, 0);
if (s < 0)
continue;
-#if defined(__BEOS__)
- closesocket(s);
-#else
+
close(s);
-#endif
if (pai->ai_flags & AI_PASSIVE) {
GET_AI(cur->ai_next, afd, afd->a_addrany, port);
@@ -589,6 +591,7 @@ get_addr(const char *hostname, int af, struct addrinfo **res, struct addrinfo *p
} else
hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
#else
+ if (strlen(hostname) >= NI_MAXHOST) ERR(EAI_NODATA);
hp = gethostbyname((char*)hostname);
h_error = h_errno;
#endif
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index d1d5ff6c73..94a5eb9439 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -41,11 +41,7 @@
#include <stdio.h>
#include <sys/types.h>
#ifndef _WIN32
-#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
-# include <net/socket.h>
-#else
-# include <sys/socket.h>
-#endif
+#include <sys/socket.h>
#include <netinet/in.h>
#if defined(HAVE_ARPA_INET_H)
#include <arpa/inet.h>
@@ -59,6 +55,9 @@
#endif
#endif
#ifdef _WIN32
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#include <windows.h>
+#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
@@ -71,8 +70,13 @@
#include <socks.h>
#endif
+#ifndef HAVE_TYPE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
#include "addrinfo.h"
#include "sockport.h"
+#include "rubysocket.h"
#define SUCCESS 0
#define ANY 0
@@ -114,24 +118,6 @@ static struct afd {
#define ENI_FAMILY 5
#define ENI_SALEN 6
-#ifndef HAVE_INET_NTOP
-static const char *
-inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
-{
-#ifdef HAVE_INET_NTOA
- struct in_addr in;
- memcpy(&in.s_addr, addr, sizeof(in.s_addr));
- snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
-#else
- unsigned long x = ntohl(*(unsigned long*)addr);
- snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
- (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
- (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
-#endif
- return numaddr;
-}
-#endif
-
int
getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
{
@@ -151,8 +137,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (sa == NULL)
return ENI_NOSOCKET;
- len = SA_LEN(sa);
- if (len != salen) return ENI_SALEN;
+ if (!VALIDATE_SOCKLEN(sa, salen)) return ENI_SALEN;
+ len = salen;
family = sa->sa_family;
for (i = 0; afdl[i].a_af; i++)
diff --git a/ext/socket/ifaddr.c b/ext/socket/ifaddr.c
new file mode 100644
index 0000000000..1da259bd6f
--- /dev/null
+++ b/ext/socket/ifaddr.c
@@ -0,0 +1,478 @@
+#include "rubysocket.h"
+
+#ifdef HAVE_GETIFADDRS
+
+/*
+ * ifa_flags is usually unsigned int.
+ * However it is uint64_t on SunOS 5.11 (OpenIndiana).
+ */
+#ifdef HAVE_LONG_LONG
+typedef unsigned LONG_LONG ifa_flags_t;
+#define PRIxIFAFLAGS PRI_LL_PREFIX"x"
+#define IFAFLAGS2NUM(flags) ULL2NUM(flags)
+#else
+typedef unsigned int ifa_flags_t;
+#define PRIxIFAFLAGS "x"
+#define IFAFLAGS2NUM(flags) UINT2NUM(flags)
+#endif
+
+VALUE rb_cSockIfaddr;
+
+typedef struct rb_ifaddr_tag rb_ifaddr_t;
+typedef struct rb_ifaddr_root_tag rb_ifaddr_root_t;
+
+struct rb_ifaddr_tag {
+ int ord;
+ struct ifaddrs *ifaddr;
+};
+
+struct rb_ifaddr_root_tag {
+ int refcount;
+ int numifaddrs;
+ rb_ifaddr_t ary[1];
+};
+
+static rb_ifaddr_root_t *
+get_root(const rb_ifaddr_t *ifaddr)
+{
+ return (rb_ifaddr_root_t *)((char *)&ifaddr[-ifaddr->ord] -
+ offsetof(rb_ifaddr_root_t, ary));
+}
+
+static void
+ifaddr_free(void *ptr)
+{
+ rb_ifaddr_t *ifaddr = ptr;
+ rb_ifaddr_root_t *root = get_root(ifaddr);
+ root->refcount--;
+ if (root->refcount == 0) {
+ freeifaddrs(root->ary[0].ifaddr);
+ xfree(root);
+ }
+}
+
+static size_t
+ifaddr_memsize(const void *ptr)
+{
+ size_t size = offsetof(rb_ifaddr_root_t, ary);
+ const rb_ifaddr_t *ifaddr;
+ ifaddr = ptr;
+ if (ifaddr->ord == 0) size = sizeof(rb_ifaddr_root_t);
+ size += sizeof(struct ifaddrs);
+ return size;
+}
+
+static const rb_data_type_t ifaddr_type = {
+ "socket/ifaddr",
+ {0, ifaddr_free, ifaddr_memsize,},
+};
+
+static inline rb_ifaddr_t *
+check_ifaddr(VALUE self)
+{
+ return rb_check_typeddata(self, &ifaddr_type);
+}
+
+static rb_ifaddr_t *
+get_ifaddr(VALUE self)
+{
+ rb_ifaddr_t *rifaddr = check_ifaddr(self);
+
+ if (!rifaddr) {
+ rb_raise(rb_eTypeError, "uninitialized ifaddr");
+ }
+ return rifaddr;
+}
+
+static struct ifaddrs *
+get_ifaddrs(VALUE self)
+{
+ return get_ifaddr(self)->ifaddr;
+}
+
+static VALUE
+rsock_getifaddrs(void)
+{
+ int ret;
+ int numifaddrs, i;
+ struct ifaddrs *ifaddrs, *ifa;
+ rb_ifaddr_root_t *root;
+ VALUE result, addr;
+
+ ret = getifaddrs(&ifaddrs);
+ if (ret == -1)
+ rb_sys_fail("getifaddrs");
+
+ if (!ifaddrs) {
+ return rb_ary_new();
+ }
+
+ numifaddrs = 0;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
+ numifaddrs++;
+
+ addr = TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, 0);
+ root = xmalloc(offsetof(rb_ifaddr_root_t, ary) + numifaddrs * sizeof(rb_ifaddr_t));
+ root->refcount = 0;
+ root->numifaddrs = numifaddrs;
+
+ ifa = ifaddrs;
+ for (i = 0; i < numifaddrs; i++) {
+ root->ary[i].ord = i;
+ root->ary[i].ifaddr = ifa;
+ ifa = ifa->ifa_next;
+ }
+ RTYPEDDATA_DATA(addr) = &root->ary[0];
+ root->refcount++;
+
+ result = rb_ary_new2(numifaddrs);
+ rb_ary_push(result, addr);
+ for (i = 1; i < numifaddrs; i++) {
+ addr = TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, &root->ary[i]);
+ root->refcount++;
+ rb_ary_push(result, addr);
+ }
+
+ return result;
+}
+
+/*
+ * call-seq:
+ * ifaddr.name => string
+ *
+ * Returns the interface name of _ifaddr_.
+ */
+
+static VALUE
+ifaddr_name(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ return rb_str_new_cstr(ifa->ifa_name);
+}
+
+#ifdef HAVE_IF_NAMETOINDEX
+/*
+ * call-seq:
+ * ifaddr.ifindex => integer
+ *
+ * Returns the interface index of _ifaddr_.
+ */
+
+static VALUE
+ifaddr_ifindex(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ unsigned int ifindex = if_nametoindex(ifa->ifa_name);
+ if (ifindex == 0) {
+ rb_raise(rb_eArgError, "invalid interface name: %s", ifa->ifa_name);
+ }
+ return UINT2NUM(ifindex);
+}
+#else
+#define ifaddr_ifindex rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * ifaddr.flags => integer
+ *
+ * Returns the flags of _ifaddr_.
+ */
+
+static VALUE
+ifaddr_flags(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ return IFAFLAGS2NUM(ifa->ifa_flags);
+}
+
+/*
+ * call-seq:
+ * ifaddr.addr => addrinfo
+ *
+ * Returns the address of _ifaddr_.
+ * nil is returned if address is not available in _ifaddr_.
+ */
+
+static VALUE
+ifaddr_addr(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ if (ifa->ifa_addr)
+ return rsock_sockaddr_obj(ifa->ifa_addr, rsock_sockaddr_len(ifa->ifa_addr));
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ifaddr.netmask => addrinfo
+ *
+ * Returns the netmask address of _ifaddr_.
+ * nil is returned if netmask is not available in _ifaddr_.
+ */
+
+static VALUE
+ifaddr_netmask(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ if (ifa->ifa_netmask)
+ return rsock_sockaddr_obj(ifa->ifa_netmask, rsock_sockaddr_len(ifa->ifa_netmask));
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ifaddr.broadaddr => addrinfo
+ *
+ * Returns the broadcast address of _ifaddr_.
+ * nil is returned if the flags doesn't have IFF_BROADCAST.
+ */
+
+static VALUE
+ifaddr_broadaddr(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr)
+ return rsock_sockaddr_obj(ifa->ifa_broadaddr, rsock_sockaddr_len(ifa->ifa_broadaddr));
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ifaddr.dstaddr => addrinfo
+ *
+ * Returns the destination address of _ifaddr_.
+ * nil is returned if the flags doesn't have IFF_POINTOPOINT.
+ */
+
+static VALUE
+ifaddr_dstaddr(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr)
+ return rsock_sockaddr_obj(ifa->ifa_dstaddr, rsock_sockaddr_len(ifa->ifa_dstaddr));
+ return Qnil;
+}
+
+#ifdef HAVE_STRUCT_IF_DATA_IFI_VHID
+/*
+ * call-seq:
+ * ifaddr.vhid => Integer
+ *
+ * Returns the vhid address of _ifaddr_.
+ * nil is returned if there is no vhid.
+ */
+
+static VALUE
+ifaddr_vhid(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ if (ifa->ifa_data)
+ return (INT2FIX(((struct if_data*)ifa->ifa_data)->ifi_vhid));
+ else
+ return Qnil;
+}
+#endif
+
+static void
+ifaddr_inspect_flags(ifa_flags_t flags, VALUE result)
+{
+ const char *sep = " ";
+#define INSPECT_BIT(bit, name) \
+ if (flags & (bit)) { rb_str_catf(result, "%s" name, sep); flags &= ~(ifa_flags_t)(bit); sep = ","; }
+#ifdef IFF_UP
+ INSPECT_BIT(IFF_UP, "UP")
+#endif
+#ifdef IFF_BROADCAST
+ INSPECT_BIT(IFF_BROADCAST, "BROADCAST")
+#endif
+#ifdef IFF_DEBUG
+ INSPECT_BIT(IFF_DEBUG, "DEBUG")
+#endif
+#ifdef IFF_LOOPBACK
+ INSPECT_BIT(IFF_LOOPBACK, "LOOPBACK")
+#endif
+#ifdef IFF_POINTOPOINT
+ INSPECT_BIT(IFF_POINTOPOINT, "POINTOPOINT")
+#endif
+#ifdef IFF_RUNNING
+ INSPECT_BIT(IFF_RUNNING, "RUNNING")
+#endif
+#ifdef IFF_NOARP
+ INSPECT_BIT(IFF_NOARP, "NOARP")
+#endif
+#ifdef IFF_PROMISC
+ INSPECT_BIT(IFF_PROMISC, "PROMISC")
+#endif
+#ifdef IFF_NOTRAILERS
+ INSPECT_BIT(IFF_NOTRAILERS, "NOTRAILERS")
+#endif
+#ifdef IFF_ALLMULTI
+ INSPECT_BIT(IFF_ALLMULTI, "ALLMULTI")
+#endif
+#ifdef IFF_SIMPLEX
+ INSPECT_BIT(IFF_SIMPLEX, "SIMPLEX")
+#endif
+#ifdef IFF_MASTER
+ INSPECT_BIT(IFF_MASTER, "MASTER")
+#endif
+#ifdef IFF_SLAVE
+ INSPECT_BIT(IFF_SLAVE, "SLAVE")
+#endif
+#ifdef IFF_MULTICAST
+ INSPECT_BIT(IFF_MULTICAST, "MULTICAST")
+#endif
+#ifdef IFF_PORTSEL
+ INSPECT_BIT(IFF_PORTSEL, "PORTSEL")
+#endif
+#ifdef IFF_AUTOMEDIA
+ INSPECT_BIT(IFF_AUTOMEDIA, "AUTOMEDIA")
+#endif
+#ifdef IFF_DYNAMIC
+ INSPECT_BIT(IFF_DYNAMIC, "DYNAMIC")
+#endif
+#ifdef IFF_LOWER_UP
+ INSPECT_BIT(IFF_LOWER_UP, "LOWER_UP")
+#endif
+#ifdef IFF_DORMANT
+ INSPECT_BIT(IFF_DORMANT, "DORMANT")
+#endif
+#ifdef IFF_ECHO
+ INSPECT_BIT(IFF_ECHO, "ECHO")
+#endif
+#undef INSPECT_BIT
+ if (flags) {
+ rb_str_catf(result, "%s%#"PRIxIFAFLAGS, sep, flags);
+ }
+}
+
+/*
+ * call-seq:
+ * ifaddr.inspect => string
+ *
+ * Returns a string to show contents of _ifaddr_.
+ */
+
+static VALUE
+ifaddr_inspect(VALUE self)
+{
+ struct ifaddrs *ifa = get_ifaddrs(self);
+ VALUE result;
+
+ result = rb_str_new_cstr("#<");
+
+ rb_str_append(result, rb_class_name(CLASS_OF(self)));
+ rb_str_cat2(result, " ");
+ rb_str_cat2(result, ifa->ifa_name);
+
+ if (ifa->ifa_flags)
+ ifaddr_inspect_flags(ifa->ifa_flags, result);
+
+ if (ifa->ifa_addr) {
+ rb_str_cat2(result, " ");
+ rsock_inspect_sockaddr(ifa->ifa_addr,
+ rsock_sockaddr_len(ifa->ifa_addr),
+ result);
+ }
+ if (ifa->ifa_netmask) {
+ rb_str_cat2(result, " netmask=");
+ rsock_inspect_sockaddr(ifa->ifa_netmask,
+ rsock_sockaddr_len(ifa->ifa_netmask),
+ result);
+ }
+
+ if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
+ rb_str_cat2(result, " broadcast=");
+ rsock_inspect_sockaddr(ifa->ifa_broadaddr,
+ rsock_sockaddr_len(ifa->ifa_broadaddr),
+ result);
+ }
+
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) {
+ rb_str_cat2(result, " dstaddr=");
+ rsock_inspect_sockaddr(ifa->ifa_dstaddr,
+ rsock_sockaddr_len(ifa->ifa_dstaddr),
+ result);
+ }
+
+ rb_str_cat2(result, ">");
+ return result;
+}
+#endif
+
+#ifdef HAVE_GETIFADDRS
+/*
+ * call-seq:
+ * Socket.getifaddrs => [ifaddr1, ...]
+ *
+ * Returns an array of interface addresses.
+ * An element of the array is an instance of Socket::Ifaddr.
+ *
+ * This method can be used to find multicast-enabled interfaces:
+ *
+ * pp Socket.getifaddrs.reject {|ifaddr|
+ * !ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
+ * }.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] }
+ * #=> [["eth0", 2, #<Addrinfo: 221.186.184.67>],
+ * # ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]]
+ *
+ * Example result on GNU/Linux:
+ * pp Socket.getifaddrs
+ * #=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
+ * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:16:3e:95:88:bb] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
+ * # #<Socket::Ifaddr sit0 NOARP PACKET[protocol=0 sit0 hatype=776 HOST hwaddr=00:00:00:00]>,
+ * # #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
+ * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 221.186.184.67 netmask=255.255.255.240 broadcast=221.186.184.79>,
+ * # #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
+ * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::216:3eff:fe95:88bb%eth0 netmask=ffff:ffff:ffff:ffff::>]
+ *
+ * Example result on FreeBSD:
+ * pp Socket.getifaddrs
+ * #=> [#<Socket::Ifaddr usbus0 UP,0x10000 LINK[usbus0]>,
+ * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[re0 3a:d0:40:9a:fe:e8]>,
+ * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 10.250.10.18 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=10.250.10.255>,
+ * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 fe80:2::38d0:40ff:fe9a:fee8 netmask=ffff:ffff:ffff:ffff::>,
+ * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 2001:2e8:408:10::12 netmask=UNSPEC>,
+ * # #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 LINK[plip0]>,
+ * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
+ * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
+ * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80:4::1 netmask=ffff:ffff:ffff:ffff::>,
+ * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.?.?.? (5 bytes for 16 bytes sockaddr_in)>]
+ *
+ */
+
+static VALUE
+socket_s_getifaddrs(VALUE self)
+{
+ return rsock_getifaddrs();
+}
+#else
+#define socket_s_getifaddrs rb_f_notimplement
+#endif
+
+void
+rsock_init_sockifaddr(void)
+{
+#ifdef HAVE_GETIFADDRS
+ /*
+ * Document-class: Socket::Ifaddr
+ *
+ * Socket::Ifaddr represents a result of getifaddrs() function.
+ */
+ rb_cSockIfaddr = rb_define_class_under(rb_cSocket, "Ifaddr", rb_cObject);
+ rb_undef_alloc_func(rb_cSockIfaddr);
+ rb_define_method(rb_cSockIfaddr, "inspect", ifaddr_inspect, 0);
+ rb_define_method(rb_cSockIfaddr, "name", ifaddr_name, 0);
+ rb_define_method(rb_cSockIfaddr, "ifindex", ifaddr_ifindex, 0);
+ rb_define_method(rb_cSockIfaddr, "flags", ifaddr_flags, 0);
+ rb_define_method(rb_cSockIfaddr, "addr", ifaddr_addr, 0);
+ rb_define_method(rb_cSockIfaddr, "netmask", ifaddr_netmask, 0);
+ rb_define_method(rb_cSockIfaddr, "broadaddr", ifaddr_broadaddr, 0);
+ rb_define_method(rb_cSockIfaddr, "dstaddr", ifaddr_dstaddr, 0);
+#ifdef HAVE_STRUCT_IF_DATA_IFI_VHID
+ rb_define_method(rb_cSockIfaddr, "vhid", ifaddr_vhid, 0);
+#endif
+#endif
+
+ rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0);
+}
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 696b62d82a..359696e626 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -10,6 +10,10 @@
#include "rubysocket.h"
+#ifdef _WIN32
+VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
+#endif
+
VALUE rb_cBasicSocket;
VALUE rb_cIPSocket;
VALUE rb_cTCPSocket;
@@ -29,34 +33,39 @@ VALUE rb_cSOCKSSocket;
#endif
int rsock_do_not_reverse_lookup = 1;
+static VALUE sym_wait_readable;
void
rsock_raise_socket_error(const char *reason, int error)
{
#ifdef EAI_SYSTEM
- if (error == EAI_SYSTEM) rb_sys_fail(reason);
+ int e;
+ if (error == EAI_SYSTEM && (e = errno) != 0)
+ rb_syserr_fail(e, reason);
#endif
+#ifdef _WIN32
+ rb_encoding *enc = rb_default_internal_encoding();
+ VALUE msg = rb_sprintf("%s: ", reason);
+ if (!enc) enc = rb_default_internal_encoding();
+ rb_str_concat(msg, rb_w32_conv_from_wchar(gai_strerrorW(error), enc));
+ rb_exc_raise(rb_exc_new_str(rb_eSocket, msg));
+#else
rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
+#endif
}
+#if defined __APPLE__
+# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
+#else
+# define do_write_retry(code) ret = code
+#endif
+
VALUE
rsock_init_sock(VALUE sock, int fd)
{
rb_io_t *fp;
-#ifndef _WIN32
- struct stat sbuf;
- if (fstat(fd, &sbuf) < 0)
- rb_sys_fail(0);
- rb_update_max_fd(fd);
- if (!S_ISSOCK(sbuf.st_mode))
- rb_raise(rb_eArgError, "not a socket file descriptor");
-#else
rb_update_max_fd(fd);
- if (!rb_w32_is_socket(fd))
- rb_raise(rb_eArgError, "not a socket file descriptor");
-#endif
-
MakeOpenFile(sock, fp);
fp->fd = fd;
fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
@@ -74,8 +83,10 @@ rsock_sendto_blocking(void *data)
{
struct rsock_send_arg *arg = data;
VALUE mesg = arg->mesg;
- return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
- arg->flags, arg->to, arg->tolen);
+ ssize_t ret;
+ do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
+ arg->flags, arg->to, arg->tolen));
+ return (VALUE)ret;
}
VALUE
@@ -83,68 +94,107 @@ rsock_send_blocking(void *data)
{
struct rsock_send_arg *arg = data;
VALUE mesg = arg->mesg;
- return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
- arg->flags);
+ ssize_t ret;
+ do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
+ arg->flags));
+ return (VALUE)ret;
}
struct recvfrom_arg {
int fd, flags;
VALUE str;
+ size_t length;
socklen_t alen;
- struct sockaddr_storage buf;
+ union_sockaddr buf;
};
static VALUE
recvfrom_blocking(void *data)
{
struct recvfrom_arg *arg = data;
- return (VALUE)recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
- arg->flags, (struct sockaddr*)&arg->buf, &arg->alen);
+ socklen_t len0 = arg->alen;
+ ssize_t ret;
+ ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), arg->length,
+ arg->flags, &arg->buf.addr, &arg->alen);
+ if (ret != -1 && len0 < arg->alen)
+ arg->alen = len0;
+
+ return (VALUE)ret;
+}
+
+static VALUE
+rsock_strbuf(VALUE str, long buflen)
+{
+ long len;
+
+ if (NIL_P(str)) return rb_str_new(0, buflen);
+
+ StringValue(str);
+ len = RSTRING_LEN(str);
+ if (len >= buflen) {
+ rb_str_modify(str);
+ } else {
+ rb_str_modify_expand(str, buflen - len);
+ }
+ return str;
+}
+
+static VALUE
+recvfrom_locktmp(VALUE v)
+{
+ struct recvfrom_arg *arg = (struct recvfrom_arg *)v;
+
+ return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd);
}
VALUE
-rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
+rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
{
rb_io_t *fptr;
- VALUE str, klass;
+ VALUE str;
struct recvfrom_arg arg;
VALUE len, flg;
long buflen;
long slen;
- rb_scan_args(argc, argv, "11", &len, &flg);
+ rb_scan_args(argc, argv, "12", &len, &flg, &str);
+
+ if (flg == Qnil)
+ arg.flags = 0;
+ else
+ arg.flags = NUM2INT(flg);
- if (flg == Qnil) arg.flags = 0;
- else arg.flags = NUM2INT(flg);
buflen = NUM2INT(len);
+ str = rsock_strbuf(str, buflen);
+
+ RB_IO_POINTER(socket, fptr);
- GetOpenFile(sock, fptr);
if (rb_io_read_pending(fptr)) {
- rb_raise(rb_eIOError, "recv for buffered IO");
+ rb_raise(rb_eIOError, "recv for buffered IO");
}
+
arg.fd = fptr->fd;
arg.alen = (socklen_t)sizeof(arg.buf);
+ arg.str = str;
+ arg.length = buflen;
+
+ while (true) {
+ rb_io_check_closed(fptr);
- arg.str = str = rb_tainted_str_new(0, buflen);
- klass = RBASIC(str)->klass;
- RBASIC(str)->klass = 0;
+#ifdef RSOCK_WAIT_BEFORE_BLOCKING
+ rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
+#endif
+
+ slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp, (VALUE)&arg);
+
+ if (slen >= 0) break;
- while (rb_io_check_closed(fptr),
- rb_thread_wait_fd(arg.fd),
- (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) {
- if (!rb_io_wait_readable(fptr->fd)) {
+ if (!rb_io_maybe_wait_readable(errno, socket, Qnil))
rb_sys_fail("recvfrom(2)");
- }
- if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
- rb_raise(rb_eRuntimeError, "buffer string modified");
- }
}
- RBASIC(str)->klass = klass;
- if (slen < RSTRING_LEN(str)) {
- rb_str_set_len(str, slen);
- }
- rb_obj_taint(str);
+ /* Resize the string to the amount of data received */
+ rb_str_set_len(str, slen);
switch (from) {
case RECV_RECV:
return str;
@@ -155,39 +205,37 @@ rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
}
#endif
if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
- return rb_assoc_new(str, rsock_ipaddr((struct sockaddr*)&arg.buf, fptr->mode & FMODE_NOREVLOOKUP));
+ return rb_assoc_new(str, rsock_ipaddr(&arg.buf.addr, arg.alen, fptr->mode & FMODE_NOREVLOOKUP));
else
return rb_assoc_new(str, Qnil);
#ifdef HAVE_SYS_UN_H
case RECV_UNIX:
- return rb_assoc_new(str, rsock_unixaddr((struct sockaddr_un*)&arg.buf, arg.alen));
+ return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
#endif
case RECV_SOCKET:
- return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, (struct sockaddr*)&arg.buf, arg.alen));
+ return rb_assoc_new(str, rsock_io_socket_addrinfo(socket, &arg.buf.addr, arg.alen));
default:
rb_bug("rsock_s_recvfrom called with bad value");
}
}
VALUE
-rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
+rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+ VALUE ex, enum sock_recv_type from)
{
rb_io_t *fptr;
- VALUE str;
- struct sockaddr_storage buf;
+ union_sockaddr buf;
socklen_t alen = (socklen_t)sizeof buf;
- VALUE len, flg;
long buflen;
long slen;
int fd, flags;
VALUE addr = Qnil;
+ socklen_t len0;
- rb_scan_args(argc, argv, "11", &len, &flg);
-
- if (flg == Qnil) flags = 0;
- else flags = NUM2INT(flg);
+ flags = NUM2INT(flg);
buflen = NUM2INT(len);
+ str = rsock_strbuf(str, buflen);
#ifdef MSG_DONTWAIT
/* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
@@ -201,37 +249,43 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
}
fd = fptr->fd;
- str = rb_tainted_str_new(0, buflen);
-
rb_io_check_closed(fptr);
- rb_io_set_nonblock(fptr);
- slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, (struct sockaddr*)&buf, &alen);
+
+ if (!MSG_DONTWAIT_RELIABLE)
+ rb_io_set_nonblock(fptr);
+
+ len0 = alen;
+ slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, &buf.addr, &alen);
+ if (slen != -1 && len0 < alen)
+ alen = len0;
if (slen < 0) {
- switch (errno) {
+ int e = errno;
+ switch (e) {
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
- rb_mod_sys_fail(rb_mWaitReadable, "recvfrom(2) would block");
+ if (ex == Qfalse)
+ return sym_wait_readable;
+ rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "recvfrom(2) would block");
}
- rb_sys_fail("recvfrom(2)");
+ rb_syserr_fail(e, "recvfrom(2)");
}
- if (slen < RSTRING_LEN(str)) {
+ if (slen != RSTRING_LEN(str)) {
rb_str_set_len(str, slen);
}
- rb_obj_taint(str);
switch (from) {
case RECV_RECV:
return str;
case RECV_IP:
if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
- addr = rsock_ipaddr((struct sockaddr*)&buf, fptr->mode & FMODE_NOREVLOOKUP);
+ addr = rsock_ipaddr(&buf.addr, alen, fptr->mode & FMODE_NOREVLOOKUP);
break;
case RECV_SOCKET:
- addr = rsock_io_socket_addrinfo(sock, (struct sockaddr*)&buf, alen);
+ addr = rsock_io_socket_addrinfo(sock, &buf.addr, alen);
break;
default:
@@ -240,36 +294,136 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
return rb_assoc_new(str, addr);
}
-static int
-rsock_socket0(int domain, int type, int proto)
+#if MSG_DONTWAIT_RELIABLE
+static VALUE sym_wait_writable;
+
+/* copied from io.c :< */
+static long
+read_buffered_data(char *ptr, long len, rb_io_t *fptr)
{
- int ret;
+ int n = fptr->rbuf.len;
+
+ if (n <= 0) return 0;
+ if (n > len) n = (int)len;
+ MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
+ fptr->rbuf.off += n;
+ fptr->rbuf.len -= n;
+ return n;
+}
-#ifdef SOCK_CLOEXEC
- static int try_sock_cloexec = 1;
- if (try_sock_cloexec) {
- ret = socket(domain, type|SOCK_CLOEXEC, proto);
- if (ret == -1 && errno == EINVAL) {
- /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
- ret = socket(domain, type, proto);
- if (ret != -1) {
- try_sock_cloexec = 0;
- }
- }
+/* :nodoc: */
+VALUE
+rsock_read_nonblock(VALUE sock, VALUE length, VALUE buf, VALUE ex)
+{
+ rb_io_t *fptr;
+ long n;
+ long len = NUM2LONG(length);
+ VALUE str = rsock_strbuf(buf, len);
+ char *ptr;
+
+ GetOpenFile(sock, fptr);
+
+ if (len == 0) {
+ rb_str_set_len(str, 0);
+ return str;
}
- else {
- ret = socket(domain, type, proto);
+
+ ptr = RSTRING_PTR(str);
+ n = read_buffered_data(ptr, len, fptr);
+ if (n <= 0) {
+ n = (long)recv(fptr->fd, ptr, len, MSG_DONTWAIT);
+ if (n < 0) {
+ int e = errno;
+ if ((e == EWOULDBLOCK || e == EAGAIN)) {
+ if (ex == Qfalse) return sym_wait_readable;
+ rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
+ e, "read would block");
+ }
+ rb_syserr_fail_path(e, fptr->pathv);
+ }
}
-#else
- ret = socket(domain, type, proto);
+ if (n != RSTRING_LEN(str)) {
+ rb_str_modify(str);
+ rb_str_set_len(str, n);
+ }
+ if (n == 0) {
+ if (ex == Qfalse) return Qnil;
+ rb_eof_error();
+ }
+
+ return str;
+}
+
+/* :nodoc: */
+VALUE
+rsock_write_nonblock(VALUE sock, VALUE str, VALUE ex)
+{
+ rb_io_t *fptr;
+ long n;
+
+ if (!RB_TYPE_P(str, T_STRING))
+ str = rb_obj_as_string(str);
+
+ sock = rb_io_get_write_io(sock);
+ GetOpenFile(sock, fptr);
+ rb_io_check_writable(fptr);
+
+ /*
+ * As with IO#write_nonblock, we may block if somebody is relying on
+ * buffered I/O; but nobody actually hits this because pipes and sockets
+ * are not userspace-buffered in Ruby by default.
+ */
+ if (fptr->wbuf.len > 0) {
+ rb_io_flush(sock);
+ }
+
+#ifdef __APPLE__
+ again:
+#endif
+ n = (long)send(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str), MSG_DONTWAIT);
+ if (n < 0) {
+ int e = errno;
+
+#ifdef __APPLE__
+ if (e == EPROTOTYPE) {
+ goto again;
+ }
#endif
- if (ret == -1)
+ if (e == EWOULDBLOCK || e == EAGAIN) {
+ if (ex == Qfalse) return sym_wait_writable;
+ rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
+ "write would block");
+ }
+ rb_syserr_fail_path(e, fptr->pathv);
+ }
+
+ return LONG2FIX(n);
+}
+#endif /* MSG_DONTWAIT_RELIABLE */
+
+static int
+rsock_socket0(int domain, int type, int proto)
+{
+#ifdef SOCK_CLOEXEC
+ type |= SOCK_CLOEXEC;
+#endif
+
+#ifdef SOCK_NONBLOCK
+ type |= SOCK_NONBLOCK;
+#endif
+
+ int result = socket(domain, type, proto);
+
+ if (result == -1)
return -1;
- rb_fd_fix_cloexec(ret);
+ rb_fd_fix_cloexec(result);
- return ret;
+#ifndef SOCK_NONBLOCK
+ rsock_make_fd_nonblock(result);
+#endif
+ return result;
}
int
@@ -279,8 +433,7 @@ rsock_socket(int domain, int type, int proto)
fd = rsock_socket0(domain, type, proto);
if (fd < 0) {
- if (errno == EMFILE || errno == ENFILE) {
- rb_gc();
+ if (rb_gc_for_fd(errno)) {
fd = rsock_socket0(domain, type, proto);
}
}
@@ -289,68 +442,94 @@ rsock_socket(int domain, int type, int proto)
return fd;
}
+/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(int fd)
+wait_connectable(int fd, struct timeval *timeout)
{
- int sockerr;
+ int sockerr, revents;
socklen_t sockerrlen;
- int revents;
- int ret;
-
- for (;;) {
- /*
- * Stevens book says, succuessful finish turn on RB_WAITFD_OUT and
- * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
- */
- revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
-
- if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) {
- sockerrlen = (socklen_t)sizeof(sockerr);
- ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
-
- /*
- * Solaris getsockopt(SO_ERROR) return -1 and set errno
- * in getsockopt(). Let's return immediately.
- */
- if (ret < 0)
- break;
- if (sockerr == 0)
- continue; /* workaround for winsock */
-
- /* BSD and Linux use sockerr. */
- errno = sockerr;
- ret = -1;
- break;
- }
- if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) {
- ret = 0;
- break;
- }
+ sockerrlen = (socklen_t)sizeof(sockerr);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
+ return -1;
+
+ /* necessary for non-blocking sockets (at least ECONNREFUSED) */
+ switch (sockerr) {
+ case 0:
+ break;
+#ifdef EALREADY
+ case EALREADY:
+#endif
+#ifdef EISCONN
+ case EISCONN:
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED:
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+#endif
+ errno = sockerr;
+ return -1;
}
- return ret;
-}
+ /*
+ * Stevens book says, successful finish turn on RB_WAITFD_OUT and
+ * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
+ * So it's enough to wait only RB_WAITFD_OUT and check the pending error
+ * by getsockopt().
+ *
+ * Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
+ */
+ revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, timeout);
+
+ if (revents < 0)
+ return -1;
+
+ sockerrlen = (socklen_t)sizeof(sockerr);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
+ return -1;
-#ifdef __CYGWIN__
-#define WAIT_IN_PROGRESS 10
+ switch (sockerr) {
+ case 0:
+ /*
+ * be defensive in case some platforms set SO_ERROR on the original,
+ * interrupted connect()
+ */
+
+ /* when the connection timed out, no errno is set and revents is 0. */
+ if (timeout && revents == 0) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ case EINTR:
+#ifdef ERESTART
+ case ERESTART:
#endif
-#ifdef __APPLE__
-#define WAIT_IN_PROGRESS 10
+ case EAGAIN:
+#ifdef EINPROGRESS
+ case EINPROGRESS:
#endif
-#ifdef __linux__
-/* returns correct error */
-#define WAIT_IN_PROGRESS 0
+#ifdef EALREADY
+ case EALREADY:
#endif
-#ifndef WAIT_IN_PROGRESS
-/* BSD origin code apparently has a problem */
-#define WAIT_IN_PROGRESS 1
+#ifdef EISCONN
+ case EISCONN:
#endif
+ return 0; /* success */
+ default:
+ /* likely (but not limited to): ECONNREFUSED, ETIMEDOUT, EHOSTUNREACH */
+ errno = sockerr;
+ return -1;
+ }
+
+ return 0;
+}
struct connect_arg {
int fd;
- const struct sockaddr *sockaddr;
socklen_t len;
+ const struct sockaddr *sockaddr;
};
static VALUE
@@ -370,16 +549,11 @@ socks_connect_blocking(void *data)
#endif
int
-rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
+rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout)
{
int status;
rb_blocking_function_t *func = connect_blocking;
struct connect_arg arg;
-#if WAIT_IN_PROGRESS > 0
- int wait_in_progress = -1;
- int sockerr;
- socklen_t sockerrlen;
-#endif
arg.fd = fd;
arg.sockaddr = sockaddr;
@@ -387,137 +561,88 @@ rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
#if defined(SOCKS) && !defined(SOCKS5)
if (socks) func = socks_connect_blocking;
#endif
- for (;;) {
- status = (int)BLOCKING_REGION_FD(func, &arg);
- if (status < 0) {
- switch (errno) {
- case EINTR:
-#if defined(ERESTART)
- case ERESTART:
-#endif
- continue;
+ status = (int)BLOCKING_REGION_FD(func, &arg);
- case EAGAIN:
-#ifdef EINPROGRESS
- case EINPROGRESS:
-#endif
-#if WAIT_IN_PROGRESS > 0
- sockerrlen = (socklen_t)sizeof(sockerr);
- status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
- if (status) break;
- if (sockerr) {
- status = -1;
- errno = sockerr;
- break;
- }
-#endif
-#ifdef EALREADY
- case EALREADY:
-#endif
-#if WAIT_IN_PROGRESS > 0
- wait_in_progress = WAIT_IN_PROGRESS;
-#endif
- status = wait_connectable(fd);
- if (status) {
- break;
- }
- errno = 0;
- continue;
-
-#if WAIT_IN_PROGRESS > 0
- case EINVAL:
- if (wait_in_progress-- > 0) {
- /*
- * connect() after EINPROGRESS returns EINVAL on
- * some platforms, need to check true error
- * status.
- */
- sockerrlen = (socklen_t)sizeof(sockerr);
- status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen);
- if (!status && !sockerr) {
- struct timeval tv = {0, 100000};
- rb_thread_wait_for(tv);
- continue;
- }
- status = -1;
- errno = sockerr;
- }
- break;
+ if (status < 0) {
+ switch (errno) {
+ case EINTR:
+#ifdef ERESTART
+ case ERESTART:
#endif
-
-#ifdef EISCONN
- case EISCONN:
- status = 0;
- errno = 0;
- break;
+ case EAGAIN:
+#ifdef EINPROGRESS
+ case EINPROGRESS:
#endif
- default:
- break;
- }
- }
- return status;
+ return wait_connectable(fd, timeout);
+ }
}
+ return status;
}
-static void
-make_fd_nonblock(int fd)
+void
+rsock_make_fd_nonblock(int fd)
{
+#ifdef _WIN32
+ return;
+#endif
+
int flags;
#ifdef F_GETFL
flags = fcntl(fd, F_GETFL);
if (flags == -1) {
- rb_sys_fail(0);
+ rb_sys_fail("fnctl(2)");
}
#else
flags = 0;
#endif
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1) {
- rb_sys_fail(0);
+ rb_sys_fail("fnctl(2)");
}
}
static int
cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len)
{
- int ret;
+ socklen_t len0 = 0;
+ if (address_len) len0 = *address_len;
+
#ifdef HAVE_ACCEPT4
- static int try_accept4 = 1;
- if (try_accept4) {
- ret = accept4(socket, address, address_len, SOCK_CLOEXEC);
- /* accept4 is available since Linux 2.6.28, glibc 2.10. */
- if (ret != -1) {
- if (ret <= 2)
- rb_maygvl_fd_fix_cloexec(ret);
- return ret;
- }
- if (errno == ENOSYS) {
- try_accept4 = 0;
- ret = accept(socket, address, address_len);
- }
- }
- else {
- ret = accept(socket, address, address_len);
- }
+ int flags = SOCK_CLOEXEC;
+
+#ifdef SOCK_NONBLOCK
+ flags |= SOCK_NONBLOCK;
+#endif
+
+ int result = accept4(socket, address, address_len, flags);
+ if (result == -1) return -1;
+
+#ifndef SOCK_NONBLOCK
+ rsock_make_fd_nonblock(result);
+#endif
#else
- ret = accept(socket, address, address_len);
+ int result = accept(socket, address, address_len);
+ if (result == -1) return -1;
+
+ rb_maygvl_fd_fix_cloexec(result);
+ rsock_make_fd_nonblock(result);
#endif
- if (ret == -1) return -1;
- rb_maygvl_fd_fix_cloexec(ret);
- return ret;
-}
+ if (address_len && len0 < *address_len) *address_len = len0;
+ return result;
+}
VALUE
-rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
+rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
+ struct sockaddr *sockaddr, socklen_t *len)
{
int fd2;
- rb_secure(3);
rb_io_set_nonblock(fptr);
fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len);
if (fd2 < 0) {
- switch (errno) {
+ int e = errno;
+ switch (e) {
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
@@ -526,12 +651,13 @@ rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, s
#if defined EPROTO
case EPROTO:
#endif
- rb_mod_sys_fail(rb_mWaitReadable, "accept(2) would block");
+ if (ex == Qfalse)
+ return sym_wait_readable;
+ rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE, e, "accept(2) would block");
}
- rb_sys_fail("accept(2)");
+ rb_syserr_fail(e, "accept(2)");
}
rb_update_max_fd(fd2);
- make_fd_nonblock(fd2);
return rsock_init_sock(rb_obj_alloc(klass), fd2);
}
@@ -549,54 +675,85 @@ accept_blocking(void *data)
}
VALUE
-rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
+rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len)
{
- int fd2;
- int retry = 0;
- struct accept_arg arg;
+ rb_io_t *fptr = NULL;
+ RB_IO_POINTER(io, fptr);
+
+ struct accept_arg accept_arg = {
+ .fd = fptr->fd,
+ .sockaddr = sockaddr,
+ .len = len
+ };
+
+ int retry = 0, peer;
- rb_secure(3);
- arg.fd = fd;
- arg.sockaddr = sockaddr;
- arg.len = len;
retry:
- rb_thread_wait_fd(fd);
- fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
- if (fd2 < 0) {
- switch (errno) {
- case EMFILE:
- case ENFILE:
- if (retry) break;
- rb_gc();
- retry = 1;
- goto retry;
- default:
- if (!rb_io_wait_readable(fd)) break;
- retry = 0;
- goto retry;
- }
- rb_sys_fail(0);
+#ifdef RSOCK_WAIT_BEFORE_BLOCKING
+ rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
+#endif
+ peer = (int)BLOCKING_REGION_FD(accept_blocking, &accept_arg);
+ if (peer < 0) {
+ int error = errno;
+
+ switch (error) {
+ case EMFILE:
+ case ENFILE:
+ case ENOMEM:
+ if (retry) break;
+ rb_gc();
+ retry = 1;
+ goto retry;
+ default:
+ if (!rb_io_maybe_wait_readable(error, io, Qnil)) break;
+ retry = 0;
+ goto retry;
+ }
+
+ rb_syserr_fail(error, "accept(2)");
}
- rb_update_max_fd(fd2);
- if (!klass) return INT2NUM(fd2);
- return rsock_init_sock(rb_obj_alloc(klass), fd2);
+
+ rb_update_max_fd(peer);
+
+ if (!klass) return INT2NUM(peer);
+
+ return rsock_init_sock(rb_obj_alloc(klass), peer);
}
int
-rsock_getfamily(int sockfd)
+rsock_getfamily(rb_io_t *fptr)
{
- struct sockaddr_storage ss;
+ union_sockaddr ss;
socklen_t sslen = (socklen_t)sizeof(ss);
+ int cached = fptr->mode & FMODE_SOCK;
+
+ if (cached) {
+ switch (cached) {
+#ifdef AF_UNIX
+ case FMODE_UNIX: return AF_UNIX;
+#endif
+ case FMODE_INET: return AF_INET;
+ case FMODE_INET6: return AF_INET6;
+ }
+ }
- ss.ss_family = AF_UNSPEC;
- if (getsockname(sockfd, (struct sockaddr*)&ss, &sslen) < 0)
+ ss.addr.sa_family = AF_UNSPEC;
+ if (getsockname(fptr->fd, &ss.addr, &sslen) < 0)
return AF_UNSPEC;
- return ss.ss_family;
+ switch (ss.addr.sa_family) {
+#ifdef AF_UNIX
+ case AF_UNIX: fptr->mode |= FMODE_UNIX; break;
+#endif
+ case AF_INET: fptr->mode |= FMODE_INET; break;
+ case AF_INET6: fptr->mode |= FMODE_INET6; break;
+ }
+
+ return ss.addr.sa_family;
}
void
-rsock_init_socket_init()
+rsock_init_socket_init(void)
{
/*
* SocketError is the error class for socket.
@@ -612,5 +769,13 @@ rsock_init_socket_init()
rsock_init_sockopt();
rsock_init_ancdata();
rsock_init_addrinfo();
+ rsock_init_sockifaddr();
rsock_init_socket_constants();
+
+#undef rb_intern
+ sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
+
+#if MSG_DONTWAIT_RELIABLE
+ sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
+#endif
}
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 6ca0c0cc71..b5cdc60080 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -15,21 +15,24 @@ struct inetsock_arg
VALUE sock;
struct {
VALUE host, serv;
- struct addrinfo *res;
+ struct rb_addrinfo *res;
} remote, local;
int type;
int fd;
+ VALUE resolv_timeout;
+ VALUE connect_timeout;
};
static VALUE
-inetsock_cleanup(struct inetsock_arg *arg)
+inetsock_cleanup(VALUE v)
{
+ struct inetsock_arg *arg = (void *)v;
if (arg->remote.res) {
- freeaddrinfo(arg->remote.res);
+ rb_freeaddrinfo(arg->remote.res);
arg->remote.res = 0;
}
if (arg->local.res) {
- freeaddrinfo(arg->local.res);
+ rb_freeaddrinfo(arg->local.res);
arg->local.res = 0;
}
if (arg->fd >= 0) {
@@ -39,33 +42,63 @@ inetsock_cleanup(struct inetsock_arg *arg)
}
static VALUE
-init_inetsock_internal(struct inetsock_arg *arg)
+init_inetsock_internal(VALUE v)
{
+ struct inetsock_arg *arg = (void *)v;
+ int error = 0;
int type = arg->type;
- struct addrinfo *res;
- int fd, status = 0;
+ struct addrinfo *res, *lres;
+ int fd, status = 0, local = 0;
+ int family = AF_UNSPEC;
const char *syscall = 0;
+ VALUE connect_timeout = arg->connect_timeout;
+ struct timeval tv_storage;
+ struct timeval *tv = NULL;
+
+ if (!NIL_P(connect_timeout)) {
+ tv_storage = rb_time_interval(connect_timeout);
+ tv = &tv_storage;
+ }
+
+ arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
+ family, SOCK_STREAM,
+ (type == INET_SERVER) ? AI_PASSIVE : 0);
+
- arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0);
/*
* Maybe also accept a local address
*/
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
- arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0);
+ arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
+ family, SOCK_STREAM, 0);
}
arg->fd = fd = -1;
- for (res = arg->remote.res; res; res = res->ai_next) {
+ for (res = arg->remote.res->ai; res; res = res->ai_next) {
#if !defined(INET6) && defined(AF_INET6)
if (res->ai_family == AF_INET6)
continue;
#endif
+ lres = NULL;
+ if (arg->local.res) {
+ for (lres = arg->local.res->ai; lres; lres = lres->ai_next) {
+ if (lres->ai_family == res->ai_family)
+ break;
+ }
+ if (!lres) {
+ if (res->ai_next || status < 0)
+ continue;
+ /* Use a different family local address if no choice, this
+ * will cause EAFNOSUPPORT. */
+ lres = arg->local.res->ai;
+ }
+ }
status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
syscall = "socket(2)";
fd = status;
if (fd < 0) {
+ error = errno;
continue;
}
arg->fd = fd;
@@ -79,19 +112,26 @@ init_inetsock_internal(struct inetsock_arg *arg)
syscall = "bind(2)";
}
else {
- if (arg->local.res) {
- status = bind(fd, arg->local.res->ai_addr, arg->local.res->ai_addrlen);
+ if (lres) {
+#if !defined(_WIN32) && !defined(__CYGWIN__)
+ status = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char*)&status, (socklen_t)sizeof(status));
+#endif
+ status = bind(fd, lres->ai_addr, lres->ai_addrlen);
+ local = status;
syscall = "bind(2)";
}
if (status >= 0) {
status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
- (type == INET_SOCKS));
+ (type == INET_SOCKS), tv);
syscall = "connect(2)";
}
}
if (status < 0) {
+ error = errno;
close(fd);
arg->fd = fd = -1;
continue;
@@ -99,7 +139,17 @@ init_inetsock_internal(struct inetsock_arg *arg)
break;
}
if (status < 0) {
- rb_sys_fail(syscall);
+ VALUE host, port;
+
+ if (local < 0) {
+ host = arg->local.host;
+ port = arg->local.serv;
+ } else {
+ host = arg->remote.host;
+ port = arg->remote.serv;
+ }
+
+ rsock_syserr_fail_host_port(error, syscall, host, port);
}
arg->fd = -1;
@@ -107,8 +157,9 @@ init_inetsock_internal(struct inetsock_arg *arg)
if (type == INET_SERVER) {
status = listen(fd, SOMAXCONN);
if (status < 0) {
+ error = errno;
close(fd);
- rb_sys_fail("listen(2)");
+ rb_syserr_fail(error, "listen(2)");
}
}
@@ -118,7 +169,8 @@ init_inetsock_internal(struct inetsock_arg *arg)
VALUE
rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
- VALUE local_host, VALUE local_serv, int type)
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout)
{
struct inetsock_arg arg;
arg.sock = sock;
@@ -130,6 +182,8 @@ rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
arg.local.res = 0;
arg.type = type;
arg.fd = -1;
+ arg.resolv_timeout = resolv_timeout;
+ arg.connect_timeout = connect_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
}
@@ -159,6 +213,43 @@ rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
/*
* call-seq:
+ * ipsocket.inspect -> string
+ *
+ * Return a string describing this IPSocket object.
+ */
+static VALUE
+ip_inspect(VALUE sock)
+{
+ VALUE str = rb_call_super(0, 0);
+ rb_io_t *fptr = RFILE(sock)->fptr;
+ union_sockaddr addr;
+ socklen_t len = (socklen_t)sizeof addr;
+ ID id;
+ if (fptr && fptr->fd >= 0 &&
+ getsockname(fptr->fd, &addr.addr, &len) >= 0 &&
+ (id = rsock_intern_family(addr.addr.sa_family)) != 0) {
+ VALUE family = rb_id2str(id);
+ char hbuf[1024], pbuf[1024];
+ long slen = RSTRING_LEN(str);
+ const char last = (slen > 1 && RSTRING_PTR(str)[slen - 1] == '>') ?
+ (--slen, '>') : 0;
+ str = rb_str_subseq(str, 0, slen);
+ rb_str_cat_cstr(str, ", ");
+ rb_str_append(str, family);
+ if (!rb_getnameinfo(&addr.addr, len, hbuf, sizeof(hbuf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
+ rb_str_cat_cstr(str, ", ");
+ rb_str_cat_cstr(str, hbuf);
+ rb_str_cat_cstr(str, ", ");
+ rb_str_cat_cstr(str, pbuf);
+ }
+ if (last) rb_str_cat(str, &last, 1);
+ }
+ return str;
+}
+
+/*
+ * call-seq:
* ipsocket.addr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
*
* Returns the local address as an array which contains
@@ -167,8 +258,8 @@ rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
* If +reverse_lookup+ is +true+ or +:hostname+,
* hostname is obtained from numeric_address using reverse lookup.
* Or if it is +false+, or +:numeric+,
- * hostname is same as numeric_address.
- * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
+ * hostname is the same as numeric_address.
+ * Or if it is +nil+ or omitted, obeys to +ipsocket.do_not_reverse_lookup+.
* See +Socket.getaddrinfo+ also.
*
* TCPSocket.open("www.ruby-lang.org", 80) {|sock|
@@ -184,7 +275,7 @@ static VALUE
ip_addr(int argc, VALUE *argv, VALUE sock)
{
rb_io_t *fptr;
- struct sockaddr_storage addr;
+ union_sockaddr addr;
socklen_t len = (socklen_t)sizeof addr;
int norevlookup;
@@ -192,9 +283,9 @@ ip_addr(int argc, VALUE *argv, VALUE sock)
if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
- if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
+ if (getsockname(fptr->fd, &addr.addr, &len) < 0)
rb_sys_fail("getsockname(2)");
- return rsock_ipaddr((struct sockaddr*)&addr, norevlookup);
+ return rsock_ipaddr(&addr.addr, len, norevlookup);
}
/*
@@ -208,13 +299,13 @@ ip_addr(int argc, VALUE *argv, VALUE sock)
* If +reverse_lookup+ is +true+ or +:hostname+,
* hostname is obtained from numeric_address using reverse lookup.
* Or if it is +false+, or +:numeric+,
- * hostname is same as numeric_address.
- * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
+ * hostname is the same as numeric_address.
+ * Or if it is +nil+ or omitted, obeys to +ipsocket.do_not_reverse_lookup+.
* See +Socket.getaddrinfo+ also.
*
* TCPSocket.open("www.ruby-lang.org", 80) {|sock|
* p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
- * p sock.peeraddr(true) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
+ * p sock.peeraddr(true) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
* p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
* p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
* p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
@@ -225,7 +316,7 @@ static VALUE
ip_peeraddr(int argc, VALUE *argv, VALUE sock)
{
rb_io_t *fptr;
- struct sockaddr_storage addr;
+ union_sockaddr addr;
socklen_t len = (socklen_t)sizeof addr;
int norevlookup;
@@ -233,9 +324,9 @@ ip_peeraddr(int argc, VALUE *argv, VALUE sock)
if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
- if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
+ if (getpeername(fptr->fd, &addr.addr, &len) < 0)
rb_sys_fail("getpeername(2)");
- return rsock_ipaddr((struct sockaddr*)&addr, norevlookup);
+ return rsock_ipaddr(&addr.addr, len, norevlookup);
}
/*
@@ -250,7 +341,7 @@ ip_peeraddr(int argc, VALUE *argv, VALUE sock)
*
* _flags_ should be a bitwise OR of Socket::MSG_* constants.
*
- * ipaddr is same as IPSocket#{peeraddr,addr}.
+ * ipaddr is the same as IPSocket#{peeraddr,addr}.
*
* u1 = UDPSocket.new
* u1.bind("127.0.0.1", 4913)
@@ -271,6 +362,8 @@ ip_recvfrom(int argc, VALUE *argv, VALUE sock)
*
* Lookups the IP address of _host_.
*
+ * require 'socket'
+ *
* IPSocket.getaddress("localhost") #=> "127.0.0.1"
* IPSocket.getaddress("ip6-localhost") #=> "::1"
*
@@ -278,14 +371,15 @@ ip_recvfrom(int argc, VALUE *argv, VALUE sock)
static VALUE
ip_s_getaddress(VALUE obj, VALUE host)
{
- struct sockaddr_storage addr;
- struct addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0);
+ union_sockaddr addr;
+ struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0);
+ socklen_t len = res->ai->ai_addrlen;
/* just take the first one */
- memcpy(&addr, res->ai_addr, res->ai_addrlen);
- freeaddrinfo(res);
+ memcpy(&addr, res->ai->ai_addr, len);
+ rb_freeaddrinfo(res);
- return rsock_make_ipaddr((struct sockaddr*)&addr);
+ return rsock_make_ipaddr(&addr.addr, len);
}
void
@@ -297,6 +391,7 @@ rsock_init_ipsocket(void)
* IPSocket is the super class of TCPSocket and UDPSocket.
*/
rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
+ rb_define_method(rb_cIPSocket, "inspect", ip_inspect, 0);
rb_define_method(rb_cIPSocket, "addr", ip_addr, -1);
rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, -1);
rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 10ab13b953..d756a32a5a 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -1,4 +1,7 @@
+# frozen_string_literal: true
+
require 'socket.so'
+require 'io/wait'
class Addrinfo
# creates an Addrinfo object from the arguments.
@@ -50,30 +53,31 @@ class Addrinfo
sock.ipv6only! if self.ipv6?
sock.bind local_addrinfo if local_addrinfo
if timeout
- begin
- sock.connect_nonblock(self)
- rescue IO::WaitWritable
- if !IO.select(nil, [sock], nil, timeout)
+ case sock.connect_nonblock(self, exception: false)
+ when 0 # success or EISCONN, other errors raise
+ break
+ when :wait_writable
+ sock.wait_writable(timeout) or
raise Errno::ETIMEDOUT, 'user specified timeout'
- end
- begin
- sock.connect_nonblock(self) # check connection failure
- rescue Errno::EISCONN
- end
- end
+ end while true
else
sock.connect(self)
end
- if block_given?
+ rescue Exception
+ sock.close
+ raise
+ end
+ if block_given?
+ begin
yield sock
- else
- sock
+ ensure
+ sock.close
end
- ensure
- sock.close if !sock.closed? && (block_given? || $!)
+ else
+ sock
end
end
- private :connect_internal
+ protected :connect_internal
# :call-seq:
# addrinfo.connect_from([local_addr_args], [opts]) {|socket| ... }
@@ -106,10 +110,8 @@ class Addrinfo
# puts s.read
# }
#
- def connect_from(*args, &block)
- opts = Hash === args.last ? args.pop : {}
- local_addr_args = args
- connect_internal(family_addrinfo(*local_addr_args), opts[:timeout], &block)
+ def connect_from(*args, timeout: nil, &block)
+ connect_internal(family_addrinfo(*args), timeout, &block)
end
# :call-seq:
@@ -131,8 +133,8 @@ class Addrinfo
# puts s.read
# }
#
- def connect(opts={}, &block)
- connect_internal(nil, opts[:timeout], &block)
+ def connect(timeout: nil, &block)
+ connect_internal(nil, timeout, &block)
end
# :call-seq:
@@ -154,11 +156,9 @@ class Addrinfo
# puts s.read
# }
#
- def connect_to(*args, &block)
- opts = Hash === args.last ? args.pop : {}
- remote_addr_args = args
- remote_addrinfo = family_addrinfo(*remote_addr_args)
- remote_addrinfo.send(:connect_internal, self, opts[:timeout], &block)
+ def connect_to(*args, timeout: nil, &block)
+ remote_addrinfo = family_addrinfo(*args)
+ remote_addrinfo.connect_internal(self, timeout, &block)
end
# creates a socket bound to self.
@@ -177,13 +177,18 @@ class Addrinfo
sock.ipv6only! if self.ipv6?
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
sock.bind(self)
- if block_given?
+ rescue Exception
+ sock.close
+ raise
+ end
+ if block_given?
+ begin
yield sock
- else
- sock
+ ensure
+ sock.close
end
- ensure
- sock.close if !sock.closed? && (block_given? || $!)
+ else
+ sock
end
end
@@ -195,13 +200,18 @@ class Addrinfo
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
sock.bind(self)
sock.listen(backlog)
- if block_given?
+ rescue Exception
+ sock.close
+ raise
+ end
+ if block_given?
+ begin
yield sock
- else
- sock
+ ensure
+ sock.close
end
- ensure
- sock.close if !sock.closed? && (block_given? || $!)
+ else
+ sock
end
end
@@ -213,8 +223,8 @@ class Addrinfo
# # #<Addrinfo: [::1]:80 TCP (:80)>
# # #<Addrinfo: [::1]:80 UDP (:80)>
#
- def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, &block)
- Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags).each(&block)
+ def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, timeout: nil, &block)
+ Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags, timeout: timeout).each(&block)
end
end
@@ -260,6 +270,192 @@ class BasicSocket < IO
end
addr
end
+
+ # call-seq:
+ # basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
+ #
+ # sendmsg sends a message using sendmsg(2) system call in blocking manner.
+ #
+ # _mesg_ is a string to send.
+ #
+ # _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
+ #
+ # _dest_sockaddr_ is a destination socket address for connection-less socket.
+ # It should be a sockaddr such as a result of Socket.sockaddr_in.
+ # An Addrinfo object can be used too.
+ #
+ # _controls_ is a list of ancillary data.
+ # The element of _controls_ should be Socket::AncillaryData or
+ # 3-elements array.
+ # The 3-element array should contains cmsg_level, cmsg_type and data.
+ #
+ # The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
+ #
+ # sendmsg can be used to implement send_io as follows:
+ #
+ # # use Socket::AncillaryData.
+ # ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
+ # sock.sendmsg("a", 0, nil, ancdata)
+ #
+ # # use 3-element array.
+ # ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
+ # sock.sendmsg("\0", 0, nil, ancdata)
+ def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls)
+ __sendmsg(mesg, flags, dest_sockaddr, controls)
+ end
+
+ # call-seq:
+ # basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent
+ #
+ # sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
+ #
+ # It is similar to BasicSocket#sendmsg
+ # but the non-blocking flag is set before the system call
+ # and it doesn't retry the system call.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that sendmsg_nonblock should not raise an IO::WaitWritable exception, but
+ # return the symbol +:wait_writable+ instead.
+ def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls,
+ exception: true)
+ __sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception)
+ end
+
+ # call-seq:
+ # basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
+ #
+ # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The result, _mesg_, is the data received.
+ #
+ # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+ #
+ # === Parameters
+ # * +maxlen+ - the number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ # * +buf+ - destination String buffer
+ # * +options+ - keyword hash, supporting `exception: false`
+ #
+ # === Example
+ # serv = TCPServer.new("127.0.0.1", 0)
+ # af, port, host, addr = serv.addr
+ # c = TCPSocket.new(addr, port)
+ # s = serv.accept
+ # c.send "aaa", 0
+ # begin # emulate blocking recv.
+ # p s.recv_nonblock(10) #=> "aaa"
+ # rescue IO::WaitReadable
+ # IO.select([s])
+ # retry
+ # end
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recv_nonblock_ fails.
+ #
+ # BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that recv_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recv_nonblock(len, flag = 0, str = nil, exception: true)
+ __recv_nonblock(len, flag, str, exception)
+ end
+
+ # call-seq:
+ # basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
+ #
+ # recvmsg receives a message using recvmsg(2) system call in blocking manner.
+ #
+ # _maxmesglen_ is the maximum length of mesg to receive.
+ #
+ # _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
+ #
+ # _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
+ #
+ # _opts_ is option hash.
+ # Currently :scm_rights=>bool is the only option.
+ #
+ # :scm_rights option specifies that application expects SCM_RIGHTS control message.
+ # If the value is nil or false, application don't expects SCM_RIGHTS control message.
+ # In this case, recvmsg closes the passed file descriptors immediately.
+ # This is the default behavior.
+ #
+ # If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
+ # In this case, recvmsg creates IO objects for each file descriptors for
+ # Socket::AncillaryData#unix_rights method.
+ #
+ # The return value is 4-elements array.
+ #
+ # _mesg_ is a string of the received message.
+ #
+ # _sender_addrinfo_ is a sender socket address for connection-less socket.
+ # It is an Addrinfo object.
+ # For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
+ #
+ # _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
+ # It will be nil if the system uses 4.3BSD style old recvmsg system call.
+ #
+ # _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
+ #
+ # #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
+ #
+ # _maxmesglen_ and _maxcontrollen_ can be nil.
+ # In that case, the buffer will be grown until the message is not truncated.
+ # Internally, MSG_PEEK is used.
+ # Buffer full and MSG_CTRUNC are checked for truncation.
+ #
+ # recvmsg can be used to implement recv_io as follows:
+ #
+ # mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
+ # controls.each {|ancdata|
+ # if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
+ # return ancdata.unix_rights[0]
+ # end
+ # }
+ def recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false)
+ __recvmsg(dlen, flags, clen, scm_rights)
+ end
+
+ # call-seq:
+ # basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
+ #
+ # recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
+ #
+ # It is similar to BasicSocket#recvmsg
+ # but non-blocking flag is set before the system call
+ # and it doesn't retry the system call.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that recvmsg_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ def recvmsg_nonblock(dlen = nil, flags = 0, clen = nil,
+ scm_rights: false, exception: true)
+ __recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
+ end
+
+ # Linux-specific optimizations to avoid fcntl for IO#read_nonblock
+ # and IO#write_nonblock using MSG_DONTWAIT
+ # Do other platforms support MSG_DONTWAIT reliably?
+ if RUBY_PLATFORM =~ /linux/ && Socket.const_defined?(:MSG_DONTWAIT)
+ def read_nonblock(len, str = nil, exception: true) # :nodoc:
+ __read_nonblock(len, str, exception)
+ end
+
+ def write_nonblock(buf, exception: true) # :nodoc:
+ __write_nonblock(buf, exception)
+ end
+ end
end
class Socket < BasicSocket
@@ -270,6 +466,133 @@ class Socket < BasicSocket
end
end
+ # call-seq:
+ # socket.recvfrom_nonblock(maxlen[, flags[, outbuf[, opts]]]) => [mesg, sender_addrinfo]
+ #
+ # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The first element of the results, _mesg_, is the data received.
+ # The second element, _sender_addrinfo_, contains protocol-specific address
+ # information of the sender.
+ #
+ # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+ #
+ # === Parameters
+ # * +maxlen+ - the maximum number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ # * +outbuf+ - destination String buffer
+ # * +opts+ - keyword hash, supporting `exception: false`
+ #
+ # === Example
+ # # In one file, start this first
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.bind(sockaddr)
+ # socket.listen(5)
+ # client, client_addrinfo = socket.accept
+ # begin # emulate blocking recvfrom
+ # pair = client.recvfrom_nonblock(20)
+ # rescue IO::WaitReadable
+ # IO.select([client])
+ # retry
+ # end
+ # data = pair[0].chomp
+ # puts "I only received 20 bytes '#{data}'"
+ # sleep 1
+ # socket.close
+ #
+ # # In another file, start this second
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.connect(sockaddr)
+ # socket.puts "Watch this get cut short!"
+ # socket.close
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recvfrom_nonblock_ fails.
+ #
+ # Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying
+ # recvfrom_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that recvfrom_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+ __recvfrom_nonblock(len, flag, str, exception)
+ end
+
+ # call-seq:
+ # socket.accept_nonblock([options]) => [client_socket, client_addrinfo]
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an array containing the accepted socket
+ # for the incoming connection, _client_socket_,
+ # and an Addrinfo, _client_addrinfo_.
+ #
+ # === Example
+ # # In one script, start this first
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.bind(sockaddr)
+ # socket.listen(5)
+ # begin # emulate blocking accept
+ # client_socket, client_addrinfo = socket.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([socket])
+ # retry
+ # end
+ # puts "The client said, '#{client_socket.readline.chomp}'"
+ # client_socket.puts "Hello from script one!"
+ # socket.close
+ #
+ # # In another script, start this second
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(2200, 'localhost')
+ # socket.connect(sockaddr)
+ # socket.puts "Hello from script 2."
+ # puts "The server said, '#{socket.readline.chomp}'"
+ # socket.close
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to _accept_nonblock_ fails.
+ #
+ # Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
+
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
@@ -283,16 +606,12 @@ class Socket < BasicSocket
# _opts_ may have following options:
#
# [:connect_timeout] specify the timeout in seconds.
+ # [:resolv_timeout] specify the name resolution timeout in seconds.
#
# If a block is given, the block is called with the socket.
# The value of the block is returned.
# The socket is closed when this method returns.
#
- # The optional last argument _opts_ is options represented by a hash.
- # _opts_ may have following options:
- #
- # [:timeout] specify the timeout in seconds.
- #
# If no block is given, the socket is returned.
#
# Socket.tcp("www.ruby-lang.org", 80) {|sock|
@@ -301,31 +620,26 @@ class Socket < BasicSocket
# puts sock.read
# }
#
- def self.tcp(host, port, *rest) # :yield: socket
- opts = Hash === rest.last ? rest.pop : {}
- raise ArgumentError, "wrong number of arguments (#{rest.length} for 2)" if 2 < rest.length
- local_host, local_port = rest
+ def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil) # :yield: socket
last_error = nil
ret = nil
- connect_timeout = opts[:connect_timeout]
-
local_addr_list = nil
if local_host != nil || local_port != nil
local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
end
- Addrinfo.foreach(host, port, nil, :STREAM) {|ai|
+ Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai|
if local_addr_list
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
- next if !local_addr
+ next unless local_addr
else
local_addr = nil
end
begin
sock = local_addr ?
- ai.connect_from(local_addr, :timeout => connect_timeout) :
- ai.connect(:timeout => connect_timeout)
+ ai.connect_from(local_addr, timeout: connect_timeout) :
+ ai.connect(timeout: connect_timeout)
rescue SystemCallError
last_error = $!
next
@@ -333,7 +647,7 @@ class Socket < BasicSocket
ret = sock
break
}
- if !ret
+ unless ret
if last_error
raise last_error
else
@@ -344,7 +658,7 @@ class Socket < BasicSocket
begin
yield ret
ensure
- ret.close if !ret.closed?
+ ret.close
end
else
ret
@@ -353,8 +667,9 @@ class Socket < BasicSocket
# :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
+ sockets = []
begin
- sockets = []
+ sockets.clear
port = nil
ai_list.each {|ai|
begin
@@ -367,7 +682,7 @@ class Socket < BasicSocket
if reuseaddr
s.setsockopt(:SOCKET, :REUSEADDR, 1)
end
- if !port
+ unless port
s.bind(ai)
port = s.local_address.ip_port
else
@@ -375,14 +690,13 @@ class Socket < BasicSocket
end
}
rescue Errno::EADDRINUSE
- sockets.each {|s|
- s.close
- }
+ sockets.each(&:close)
retry
+ rescue Exception
+ sockets.each(&:close)
+ raise
end
sockets
- ensure
- sockets.each {|s| s.close if !s.closed? } if $!
end
class << self
private :ip_sockets_port0
@@ -391,12 +705,15 @@ class Socket < BasicSocket
def self.tcp_server_sockets_port0(host)
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
sockets = ip_sockets_port0(ai_list, true)
- sockets.each {|s|
- s.listen(Socket::SOMAXCONN)
- }
+ begin
+ sockets.each {|s|
+ s.listen(Socket::SOMAXCONN)
+ }
+ rescue Exception
+ sockets.each(&:close)
+ raise
+ end
sockets
- ensure
- sockets.each {|s| s.close if !s.closed? } if $! && sockets
end
class << self
private :tcp_server_sockets_port0
@@ -413,7 +730,7 @@ class Socket < BasicSocket
# The value of the block is returned.
# The socket is closed when this method returns.
#
- # If _port_ is 0, actual port number is choosen dynamically.
+ # If _port_ is 0, actual port number is chosen dynamically.
# However all sockets in the result has same port number.
#
# # tcp_server_sockets returns two sockets.
@@ -425,7 +742,7 @@ class Socket < BasicSocket
# #=> #<Addrinfo: [::]:1296 TCP>
# # #<Addrinfo: 0.0.0.0:1296 TCP>
#
- # # IPv6 and IPv4 socket has same port number, 53114, even if it is choosen dynamically.
+ # # IPv6 and IPv4 socket has same port number, 53114, even if it is chosen dynamically.
# sockets = Socket.tcp_server_sockets(0)
# sockets.each {|s| p s.local_address }
# #=> #<Addrinfo: [::]:53114 TCP>
@@ -440,9 +757,9 @@ class Socket < BasicSocket
if port == 0
sockets = tcp_server_sockets_port0(host)
else
+ last_error = nil
+ sockets = []
begin
- last_error = nil
- sockets = []
Addrinfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai|
begin
s = ai.listen
@@ -455,15 +772,16 @@ class Socket < BasicSocket
if sockets.empty?
raise last_error
end
- ensure
- sockets.each {|s| s.close if !s.closed? } if $!
+ rescue Exception
+ sockets.each(&:close)
+ raise
end
end
if block_given?
begin
yield sockets
ensure
- sockets.each {|s| s.close if !s.closed? }
+ sockets.each(&:close)
end
else
sockets
@@ -487,11 +805,8 @@ class Socket < BasicSocket
loop {
readable, _, _ = IO.select(sockets)
readable.each {|r|
- begin
- sock, addr = r.accept_nonblock
- rescue IO::WaitReadable
- next
- end
+ sock, addr = r.accept_nonblock(exception: false)
+ next if sock == :wait_readable
yield sock, addr
}
}
@@ -555,8 +870,8 @@ class Socket < BasicSocket
# The value of the block is returned.
# The sockets are closed when this method returns.
#
- # If _port_ is zero, some port is choosen.
- # But the choosen port is used for the all sockets.
+ # If _port_ is zero, some port is chosen.
+ # But the chosen port is used for the all sockets.
#
# # UDP/IP echo server
# Socket.udp_server_sockets(0) {|sockets|
@@ -585,18 +900,19 @@ class Socket < BasicSocket
Addrinfo.foreach(host, port, nil, :DGRAM, nil, Socket::AI_PASSIVE) {|ai|
if ai.ipv4? && ai.ip_address == "0.0.0.0"
local_addrs.each {|a|
- next if !a.ipv4?
+ next unless a.ipv4?
ip_list << Addrinfo.new(a.to_sockaddr, :INET, :DGRAM, 0);
}
elsif ai.ipv6? && ai.ip_address == "::" && !ipv6_recvpktinfo
local_addrs.each {|a|
- next if !a.ipv6?
+ next unless a.ipv6?
ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
}
else
ip_list << ai
end
}
+ ip_list.uniq!(&:to_sockaddr)
if port == 0
sockets = ip_sockets_port0(ip_list, false)
@@ -627,7 +943,7 @@ class Socket < BasicSocket
begin
yield sockets
ensure
- sockets.each {|s| s.close if !s.closed? } if sockets
+ sockets.each(&:close) if sockets
end
else
sockets
@@ -655,11 +971,8 @@ class Socket < BasicSocket
#
def self.udp_server_recv(sockets)
sockets.each {|r|
- begin
- msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock
- rescue IO::WaitReadable
- next
- end
+ msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock(exception: false)
+ next if msg == :wait_readable
ai = r.local_address
if ai.ipv6? and pktinfo = controls.find {|c| c.cmsg_is?(:IPV6, :PKTINFO) }
ai = Addrinfo.udp(pktinfo.ipv6_pktinfo_addr.ip_address, ai.ip_port)
@@ -718,9 +1031,9 @@ class Socket < BasicSocket
# UDP/IP address information used by Socket.udp_server_loop.
class UDPSource
- # +remote_adress+ is an Addrinfo object.
+ # +remote_address+ is an Addrinfo object.
#
- # +local_adress+ is an Addrinfo object.
+ # +local_address+ is an Addrinfo object.
#
# +reply_proc+ is a Proc used to send reply back to the source.
def initialize(remote_address, local_address, &reply_proc)
@@ -736,7 +1049,7 @@ class Socket < BasicSocket
attr_reader :local_address
def inspect # :nodoc:
- "\#<#{self.class}: #{@remote_address.inspect_sockaddr} to #{@local_address.inspect_sockaddr}>"
+ "\#<#{self.class}: #{@remote_address.inspect_sockaddr} to #{@local_address.inspect_sockaddr}>".dup
end
# Sends the String +msg+ to the source
@@ -767,7 +1080,7 @@ class Socket < BasicSocket
begin
yield sock
ensure
- sock.close if !sock.closed?
+ sock.close
end
else
sock
@@ -791,26 +1104,38 @@ class Socket < BasicSocket
# }
#
def self.unix_server_socket(path)
- begin
- st = File.lstat(path)
- rescue Errno::ENOENT
- end
- if st && st.socket? && st.owned?
- File.unlink path
+ unless unix_socket_abstract_name?(path)
+ begin
+ st = File.lstat(path)
+ rescue Errno::ENOENT
+ end
+ if st&.socket? && st.owned?
+ File.unlink path
+ end
end
s = Addrinfo.unix(path).listen
if block_given?
begin
yield s
ensure
- s.close if !s.closed?
- File.unlink path
+ s.close
+ unless unix_socket_abstract_name?(path)
+ File.unlink path
+ end
end
else
s
end
end
+ class << self
+ private
+
+ def unix_socket_abstract_name?(path)
+ /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
+ end
+ end
+
# creates a UNIX socket server on _path_.
# It calls the block for each socket accepted.
#
@@ -841,5 +1166,192 @@ class Socket < BasicSocket
}
end
+ # call-seq:
+ # socket.connect_nonblock(remote_sockaddr, [options]) => 0
+ #
+ # Requests a connection to be made on the given +remote_sockaddr+ after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # Returns 0 if successful, otherwise an exception is raised.
+ #
+ # === Parameter
+ # # +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
+ #
+ # === Example:
+ # # Pull down Google's web page
+ # require 'socket'
+ # include Socket::Constants
+ # socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+ # sockaddr = Socket.sockaddr_in(80, 'www.google.com')
+ # begin # emulate blocking connect
+ # socket.connect_nonblock(sockaddr)
+ # rescue IO::WaitWritable
+ # IO.select(nil, [socket]) # wait 3-way handshake completion
+ # begin
+ # socket.connect_nonblock(sockaddr) # check connection failure
+ # rescue Errno::EISCONN
+ # end
+ # end
+ # socket.write("GET / HTTP/1.0\r\n\r\n")
+ # results = socket.read
+ #
+ # Refer to Socket#connect for the exceptions that may be thrown if the call
+ # to _connect_nonblock_ fails.
+ #
+ # Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
+ # including Errno::EINPROGRESS.
+ #
+ # If the exception is Errno::EINPROGRESS,
+ # it is extended by IO::WaitWritable.
+ # So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that connect_nonblock should not raise an IO::WaitWritable exception, but
+ # return the symbol +:wait_writable+ instead.
+ #
+ # === See
+ # # Socket#connect
+ def connect_nonblock(addr, exception: true)
+ __connect_nonblock(addr, exception)
+ end
+end
+
+class UDPSocket < IPSocket
+
+ # call-seq:
+ # udpsocket.recvfrom_nonblock(maxlen [, flags[, outbuf [, options]]]) => [mesg, sender_inet_addr]
+ #
+ # Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # _flags_ is zero or more of the +MSG_+ options.
+ # The first element of the results, _mesg_, is the data received.
+ # The second element, _sender_inet_addr_, is an array to represent the sender address.
+ #
+ # When recvfrom(2) returns 0,
+ # Socket#recvfrom_nonblock returns an empty string as data.
+ # It means an empty packet.
+ #
+ # === Parameters
+ # * +maxlen+ - the number of bytes to receive from the socket
+ # * +flags+ - zero or more of the +MSG_+ options
+ # * +outbuf+ - destination String buffer
+ # * +options+ - keyword hash, supporting `exception: false`
+ #
+ # === Example
+ # require 'socket'
+ # s1 = UDPSocket.new
+ # s1.bind("127.0.0.1", 0)
+ # s2 = UDPSocket.new
+ # s2.bind("127.0.0.1", 0)
+ # s2.connect(*s1.addr.values_at(3,1))
+ # s1.connect(*s2.addr.values_at(3,1))
+ # s1.send "aaa", 0
+ # begin # emulate blocking recvfrom
+ # p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
+ # rescue IO::WaitReadable
+ # IO.select([s2])
+ # retry
+ # end
+ #
+ # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+ # to _recvfrom_nonblock_ fails.
+ #
+ # UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that recvfrom_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * Socket#recvfrom
+ def recvfrom_nonblock(len, flag = 0, outbuf = nil, exception: true)
+ __recvfrom_nonblock(len, flag, outbuf, exception)
+ end
+end
+
+class TCPServer < TCPSocket
+
+ # call-seq:
+ # tcpserver.accept_nonblock([options]) => tcpsocket
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an accepted TCPSocket for the incoming connection.
+ #
+ # === Example
+ # require 'socket'
+ # serv = TCPServer.new(2202)
+ # begin # emulate blocking accept
+ # sock = serv.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([serv])
+ # retry
+ # end
+ # # sock is an accepted socket.
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to TCPServer#accept_nonblock fails.
+ #
+ # TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * TCPServer#accept
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
end
+class UNIXServer < UNIXSocket
+ # call-seq:
+ # unixserver.accept_nonblock([options]) => unixsocket
+ #
+ # Accepts an incoming connection using accept(2) after
+ # O_NONBLOCK is set for the underlying file descriptor.
+ # It returns an accepted UNIXSocket for the incoming connection.
+ #
+ # === Example
+ # require 'socket'
+ # serv = UNIXServer.new("/tmp/sock")
+ # begin # emulate blocking accept
+ # sock = serv.accept_nonblock
+ # rescue IO::WaitReadable, Errno::EINTR
+ # IO.select([serv])
+ # retry
+ # end
+ # # sock is an accepted socket.
+ #
+ # Refer to Socket#accept for the exceptions that may be thrown if the call
+ # to UNIXServer#accept_nonblock fails.
+ #
+ # UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
+ # including Errno::EWOULDBLOCK.
+ #
+ # If the exception is Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED or Errno::EPROTO,
+ # it is extended by IO::WaitReadable.
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
+ #
+ # By specifying a keyword argument _exception_ to +false+, you can indicate
+ # that accept_nonblock should not raise an IO::WaitReadable exception, but
+ # return the symbol +:wait_readable+ instead.
+ #
+ # === See
+ # * UNIXServer#accept
+ # * Socket#accept
+ def accept_nonblock(exception: true)
+ __accept_nonblock(exception)
+ end
+end if defined?(UNIXSocket)
diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb
index 3b63c39eff..577958a358 100644
--- a/ext/socket/mkconstants.rb
+++ b/ext/socket/mkconstants.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'optparse'
require 'erb'
@@ -56,17 +57,12 @@ DEFS = h.to_a
def each_const
DEFS.each {|name, default_value|
- if name =~ /\AINADDR_/
- make_value = "UINT2NUM"
- else
- make_value = "INT2NUM"
- end
guard = nil
if /\A(AF_INET6|PF_INET6|IPV6_.*)\z/ =~ name
- # IPv6 is not supported although AF_INET6 is defined on bcc32/mingw
+ # IPv6 is not supported although AF_INET6 is defined on mingw
guard = "defined(INET6)"
end
- yield guard, make_value, name, default_value
+ yield guard, name, default_value
}
end
@@ -77,8 +73,16 @@ def each_name(pat)
}
end
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
-% each_const {|guard, make_value, name, default_value|
+erb_new = lambda do |src, safe, trim|
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
+ ERB.new(src, trim_mode: trim)
+ else
+ ERB.new(src, safe, trim)
+ end
+end
+
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
+% each_const {|guard, name, default_value|
#if !defined(<%=name%>)
# if defined(HAVE_CONST_<%=name.upcase%>)
# define <%=name%> <%=name%>
@@ -91,23 +95,23 @@ ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
% }
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_defs_in_guard(make_value, name, default_value)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs_in_guard(name, default_value)")
#if defined(<%=name%>)
/* <%= COMMENTS[name] %> */
- rb_define_const(rb_cSocket, <%=c_str name%>, <%=make_value%>(<%=name%>));
+ rb_define_const(rb_cSocket, <%=c_str name%>, INTEGER2NUM(<%=name%>));
/* <%= COMMENTS[name] %> */
- rb_define_const(rb_mSockConst, <%=c_str name%>, <%=make_value%>(<%=name%>));
+ rb_define_const(rb_mSockConst, <%=c_str name%>, INTEGER2NUM(<%=name%>));
#endif
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_defs")
-% each_const {|guard, make_value, name, default_value|
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs")
+% each_const {|guard, name, default_value|
% if guard
#if <%=guard%>
-<%= gen_const_defs_in_guard(make_value, name, default_value).chomp %>
+<%= gen_const_defs_in_guard(name, default_value).chomp %>
#endif
% else
-<%= gen_const_defs_in_guard(make_value, name, default_value).chomp %>
+<%= gen_const_defs_in_guard(name, default_value).chomp %>
% end
% }
EOS
@@ -150,7 +154,7 @@ def each_names_with_len(pat, prefix_optional=nil)
}
end
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_decl(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_decl(funcname, pat, prefix_optional, guard=nil)")
%if guard
#ifdef <%=guard%>
int <%=funcname%>(const char *str, long len, int *valp);
@@ -160,7 +164,7 @@ int <%=funcname%>(const char *str, long len, int *valp);
%end
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard=nil)")
int
<%=funcname%>(const char *str, long len, int *valp)
{
@@ -176,12 +180,13 @@ int
% }
default:
+ if (!str || !valp) {/* wrong argument */}
return -1;
}
}
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func(funcname, pat, prefix_optional, guard=nil)")
%if guard
#ifdef <%=guard%>
<%=gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard)%>
@@ -210,7 +215,7 @@ def reverse_each_name_with_prefix_optional(pat, prefix_pat)
end
end
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_hash(hash_var, pat, prefix_pat)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_hash(hash_var, pat, prefix_pat)")
<%=hash_var%> = st_init_numtable();
% reverse_each_name_with_prefix_optional(pat, prefix_pat) {|n,s|
#ifdef <%=n%>
@@ -219,7 +224,7 @@ ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_hash(hash_var, pa
% }
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_func(func_name, hash_var)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_func(func_name, hash_var)")
ID
<%=func_name%>(int val)
{
@@ -230,7 +235,7 @@ ID
}
EOS
-ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_decl(func_name, hash_var)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_decl(func_name, hash_var)")
ID <%=func_name%>(int val);
EOS
@@ -279,11 +284,23 @@ def_intern('rsock_intern_udp_optname', /\AUDP_/, "UDP_")
def_intern('rsock_intern_scm_optname', /\ASCM_/, "SCM_")
def_intern('rsock_intern_local_optname', /\ALOCAL_/, "LOCAL_")
-result = ERB.new(<<'EOS', nil, '%').result(binding)
+result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= INTERN_DEFS.map {|vardef, gen_hash, decl, func| vardef }.join("\n") %>
+#ifdef HAVE_LONG_LONG
+#define INTEGER2NUM(n) \
+ (FIXNUM_MAX < (n) ? ULL2NUM(n) : \
+ FIXNUM_MIN > (LONG_LONG)(n) ? LL2NUM(n) : \
+ LONG2FIX(n))
+#else
+#define INTEGER2NUM(n) \
+ (FIXNUM_MAX < (n) ? ULONG2NUM(n) : \
+ FIXNUM_MIN > (long)(n) ? LONG2NUM(n) : \
+ LONG2FIX(n))
+#endif
+
static void
init_constants(void)
{
@@ -310,7 +327,7 @@ init_constants(void)
EOS
-header_result = ERB.new(<<'EOS', nil, '%').result(binding)
+header_result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= gen_const_decls %>
<%= NAME_TO_INT_DEFS.map {|decl, func| decl }.join("\n") %>
@@ -341,6 +358,8 @@ SOCK_RAW nil A raw socket provides low-level access for direct access or impleme
SOCK_RDM nil A reliable datagram socket provides reliable delivery of messages
SOCK_SEQPACKET nil A sequential packet socket provides sequenced, reliable two-way connection for datagrams
SOCK_PACKET nil Device-level packet access
+SOCK_NONBLOCK nil Set the O_NONBLOCK file status flag on the open file description (see open(2)) referred to by the new file descriptor.
+SOCK_CLOEXEC nil Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor.
AF_UNSPEC nil Unspecified protocol, any supported address family
PF_UNSPEC nil Unspecified protocol, any supported address family
@@ -380,6 +399,8 @@ AF_SNA nil IBM SNA protocol
PF_SNA nil IBM SNA protocol
AF_DEC nil DECnet protocol
PF_DEC nil DECnet protocol
+AF_DECnet nil DECnet protocol
+PF_DECnet nil DECnet protocol
AF_DLI nil DEC Direct Data Link Interface protocol
PF_DLI nil DEC Direct Data Link Interface protocol
AF_LAT nil Local Area Transport protocol
@@ -421,7 +442,34 @@ AF_E164 nil CCITT (ITU-T) E.164 recommendation
PF_XTP nil eXpress Transfer Protocol
PF_RTIP
PF_PIP
-PF_KEY
+AF_KEY nil Key management protocol, originally developed for usage with IPsec
+PF_KEY nil Key management protocol, originally developed for usage with IPsec
+AF_NETLINK nil Kernel user interface device
+PF_NETLINK nil Kernel user interface device
+AF_RDS nil Reliable Datagram Sockets (RDS) protocol
+PF_RDS nil Reliable Datagram Sockets (RDS) protocol
+AF_PPPOX nil Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
+PF_PPPOX nil Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
+AF_LLC nil Logical link control (IEEE 802.2 LLC) protocol
+PF_LLC nil Logical link control (IEEE 802.2 LLC) protocol
+AF_IB nil InfiniBand native addressing
+PF_IB nil InfiniBand native addressing
+AF_MPLS nil Multiprotocol Label Switching
+PF_MPLS nil Multiprotocol Label Switching
+AF_CAN nil Controller Area Network automotive bus protocol
+PF_CAN nil Controller Area Network automotive bus protocol
+AF_TIPC nil TIPC, "cluster domain sockets" protocol
+PF_TIPC nil TIPC, "cluster domain sockets" protocol
+AF_BLUETOOTH nil Bluetooth low-level socket protocol
+PF_BLUETOOTH nil Bluetooth low-level socket protocol
+AF_ALG nil Interface to kernel crypto API
+PF_ALG nil Interface to kernel crypto API
+AF_VSOCK nil VSOCK (originally "VMWare VSockets") protocol for hypervisor-guest communication
+PF_VSOCK nil VSOCK (originally "VMWare VSockets") protocol for hypervisor-guest communication
+AF_KCM nil KCM (kernel connection multiplexor) interface
+PF_KCM nil KCM (kernel connection multiplexor) interface
+AF_XDP nil XDP (express data path) interface
+PF_XDP nil XDP (express data path) interface
MSG_OOB nil Process out-of-band data
MSG_PEEK nil Peek at incoming message
@@ -446,6 +494,7 @@ MSG_RST
MSG_ERRQUEUE nil Fetch message from error queue
MSG_NOSIGNAL nil Do not generate SIGPIPE
MSG_MORE nil Sender will send more
+MSG_FASTOPEN nil Reduce step of the handshake process
SOL_SOCKET nil Socket-level options
SOL_IP nil IP socket options
@@ -532,6 +581,7 @@ IP_FREEBIND nil Allow binding to nonexistent IP addresses
IP_IPSEC_POLICY nil IPsec security policy
IP_XFRM_POLICY
IP_PASSSEC nil Retrieve security context with datagram
+IP_TRANSPARENT nil Transparent proxy
IP_PMTUDISC_DONT nil Never send DF frames
IP_PMTUDISC_WANT nil Use per-route hints
IP_PMTUDISC_DO nil Always send DF frames
@@ -560,6 +610,8 @@ SO_DONTROUTE nil Use interface addresses
SO_BROADCAST nil Permit sending of broadcast messages
SO_SNDBUF nil Send buffer size
SO_RCVBUF nil Receive buffer size
+SO_SNDBUFFORCE nil Send buffer size without wmem_max limit (Linux 2.6.14)
+SO_RCVBUFFORCE nil Receive buffer size without rmem_max limit (Linux 2.6.14)
SO_KEEPALIVE nil Keep connections alive
SO_OOBINLINE nil Leave received out-of-band data in-line
SO_NO_CHECK nil Disable checksums
@@ -586,6 +638,7 @@ SO_SECURITY_ENCRYPTION_NETWORK
SO_BINDTODEVICE nil Only send packets from the given interface
SO_ATTACH_FILTER nil Attach an accept filter
SO_DETACH_FILTER nil Detach an accept filter
+SO_GET_FILTER nil Obtain filter set by SO_ATTACH_FILTER (Linux 3.8)
SO_PEERNAME nil Name of the connecting user
SO_TIMESTAMP nil Receive timestamp with datagrams (timeval)
SO_TIMESTAMPNS nil Receive nanosecond timestamp with datagrams (timespec)
@@ -593,6 +646,21 @@ SO_BINTIME nil Receive timestamp with datagrams (bintime)
SO_RECVUCRED nil Receive user credentials with datagram
SO_MAC_EXEMPT nil Mandatory Access Control exemption for unlabeled peers
SO_ALLZONES nil Bypass zone boundaries
+SO_PEERSEC nil Obtain the security credentials (Linux 2.6.2)
+SO_PASSSEC nil Toggle security context passing (Linux 2.6.18)
+SO_MARK nil Set the mark for mark-based routing (Linux 2.6.25)
+SO_TIMESTAMPING nil Time stamping of incoming and outgoing packets (Linux 2.6.30)
+SO_PROTOCOL nil Protocol given for socket() (Linux 2.6.32)
+SO_DOMAIN nil Domain given for socket() (Linux 2.6.32)
+SO_RXQ_OVFL nil Toggle cmsg for number of packets dropped (Linux 2.6.33)
+SO_WIFI_STATUS nil Toggle cmsg for wifi status (Linux 3.3)
+SO_PEEK_OFF nil Set the peek offset (Linux 3.4)
+SO_NOFCS nil Set netns of a socket (Linux 3.4)
+SO_LOCK_FILTER nil Lock the filter attached to a socket (Linux 3.9)
+SO_SELECT_ERR_QUEUE nil Make select() detect socket error queue with errorfds (Linux 3.10)
+SO_BUSY_POLL nil Set the threshold in microseconds for low latency polling (Linux 3.11)
+SO_MAX_PACING_RATE nil Cap the rate computed by transport layer. [bytes per second] (Linux 3.13)
+SO_BPF_EXTENSIONS nil Query supported BPF extensions (Linux 3.14)
SOPRI_INTERACTIVE nil Interactive socket priority
SOPRI_NORMAL nil Normal socket priority
@@ -602,21 +670,32 @@ IPX_TYPE
TCP_NODELAY nil Don't delay sending to coalesce packets
TCP_MAXSEG nil Set maximum segment size
-TCP_CORK nil Don't send partial frames
-TCP_DEFER_ACCEPT nil Don't notify a listening socket until data is ready
-TCP_INFO nil Retrieve information about this socket
-TCP_KEEPCNT nil Maximum number of keepalive probes allowed before dropping a connection
-TCP_KEEPIDLE nil Idle time before keepalive probes are sent
-TCP_KEEPINTVL nil Time between keepalive probes
-TCP_LINGER2 nil Lifetime of orphaned FIN_WAIT2 sockets
-TCP_MD5SIG nil Use MD5 digests (RFC2385)
+TCP_CORK nil Don't send partial frames (Linux 2.2, glibc 2.2)
+TCP_DEFER_ACCEPT nil Don't notify a listening socket until data is ready (Linux 2.4, glibc 2.2)
+TCP_INFO nil Retrieve information about this socket (Linux 2.4, glibc 2.2)
+TCP_KEEPCNT nil Maximum number of keepalive probes allowed before dropping a connection (Linux 2.4, glibc 2.2)
+TCP_KEEPIDLE nil Idle time before keepalive probes are sent (Linux 2.4, glibc 2.2)
+TCP_KEEPINTVL nil Time between keepalive probes (Linux 2.4, glibc 2.2)
+TCP_LINGER2 nil Lifetime of orphaned FIN_WAIT2 sockets (Linux 2.4, glibc 2.2)
+TCP_MD5SIG nil Use MD5 digests (RFC2385, Linux 2.6.20, glibc 2.7)
TCP_NOOPT nil Don't use TCP options
TCP_NOPUSH nil Don't push the last block of write
-TCP_QUICKACK nil Enable quickack mode
-TCP_SYNCNT nil Number of SYN retransmits before a connection is dropped
-TCP_WINDOW_CLAMP nil Clamp the size of the advertised window
-
-UDP_CORK nil Don't send partial frames
+TCP_QUICKACK nil Enable quickack mode (Linux 2.4.4, glibc 2.3)
+TCP_SYNCNT nil Number of SYN retransmits before a connection is dropped (Linux 2.4, glibc 2.2)
+TCP_WINDOW_CLAMP nil Clamp the size of the advertised window (Linux 2.4, glibc 2.2)
+TCP_FASTOPEN nil Reduce step of the handshake process (Linux 3.7, glibc 2.18)
+TCP_CONGESTION nil TCP congestion control algorithm (Linux 2.6.13, glibc 2.6)
+TCP_COOKIE_TRANSACTIONS nil TCP Cookie Transactions (Linux 2.6.33, glibc 2.18)
+TCP_QUEUE_SEQ nil Sequence of a queue for repair mode (Linux 3.5, glibc 2.18)
+TCP_REPAIR nil Repair mode (Linux 3.5, glibc 2.18)
+TCP_REPAIR_OPTIONS nil Options for repair mode (Linux 3.5, glibc 2.18)
+TCP_REPAIR_QUEUE nil Queue for repair mode (Linux 3.5, glibc 2.18)
+TCP_THIN_DUPACK nil Duplicated acknowledgments handling for thin-streams (Linux 2.6.34, glibc 2.18)
+TCP_THIN_LINEAR_TIMEOUTS nil Linear timeouts for thin-streams (Linux 2.6.34, glibc 2.18)
+TCP_TIMESTAMP nil TCP timestamp (Linux 3.9, glibc 2.18)
+TCP_USER_TIMEOUT nil Max timeout before a TCP connection is aborted (Linux 2.6.37, glibc 2.18)
+
+UDP_CORK nil Don't send partial frames (Linux 2.5.44, glibc 2.11)
EAI_ADDRFAMILY nil Address family for hostname not supported
EAI_AGAIN nil Temporary failure in name resolution
@@ -695,11 +774,72 @@ SOMAXCONN 5 Maximum connection requests that may be queued for a socket
SCM_RIGHTS nil Access rights
SCM_TIMESTAMP nil Timestamp (timeval)
SCM_TIMESTAMPNS nil Timespec (timespec)
+SCM_TIMESTAMPING nil Timestamp (timespec list) (Linux 2.6.30)
SCM_BINTIME nil Timestamp (bintime)
SCM_CREDENTIALS nil The sender's credentials
SCM_CREDS nil Process credentials
SCM_UCRED nil User credentials
+SCM_WIFI_STATUS nil Wifi status (Linux 3.3)
LOCAL_PEERCRED nil Retrieve peer credentials
LOCAL_CREDS nil Pass credentials to receiver
LOCAL_CONNWAIT nil Connect blocks until accepted
+
+IFF_802_1Q_VLAN nil 802.1Q VLAN device
+IFF_ALLMULTI nil receive all multicast packets
+IFF_ALTPHYS nil use alternate physical connection
+IFF_AUTOMEDIA nil auto media select active
+IFF_BONDING nil bonding master or slave
+IFF_BRIDGE_PORT nil device used as bridge port
+IFF_BROADCAST nil broadcast address valid
+IFF_CANTCONFIG nil unconfigurable using ioctl(2)
+IFF_DEBUG nil turn on debugging
+IFF_DISABLE_NETPOLL nil disable netpoll at run-time
+IFF_DONT_BRIDGE nil disallow bridging this ether dev
+IFF_DORMANT nil driver signals dormant
+IFF_DRV_OACTIVE nil tx hardware queue is full
+IFF_DRV_RUNNING nil resources allocated
+IFF_DYING nil interface is winding down
+IFF_DYNAMIC nil dialup device with changing addresses
+IFF_EBRIDGE nil ethernet bridging device
+IFF_ECHO nil echo sent packets
+IFF_ISATAP nil ISATAP interface (RFC4214)
+IFF_LINK0 nil per link layer defined bit 0
+IFF_LINK1 nil per link layer defined bit 1
+IFF_LINK2 nil per link layer defined bit 2
+IFF_LIVE_ADDR_CHANGE nil hardware address change when it's running
+IFF_LOOPBACK nil loopback net
+IFF_LOWER_UP nil driver signals L1 up
+IFF_MACVLAN_PORT nil device used as macvlan port
+IFF_MASTER nil master of a load balancer
+IFF_MASTER_8023AD nil bonding master, 802.3ad.
+IFF_MASTER_ALB nil bonding master, balance-alb.
+IFF_MASTER_ARPMON nil bonding master, ARP mon in use
+IFF_MONITOR nil user-requested monitor mode
+IFF_MULTICAST nil supports multicast
+IFF_NOARP nil no address resolution protocol
+IFF_NOTRAILERS nil avoid use of trailers
+IFF_OACTIVE nil transmission in progress
+IFF_OVS_DATAPATH nil device used as Open vSwitch datapath port
+IFF_POINTOPOINT nil point-to-point link
+IFF_PORTSEL nil can set media type
+IFF_PPROMISC nil user-requested promisc mode
+IFF_PROMISC nil receive all packets
+IFF_RENAMING nil interface is being renamed
+IFF_ROUTE nil routing entry installed
+IFF_RUNNING nil resources allocated
+IFF_SIMPLEX nil can't hear own transmissions
+IFF_SLAVE nil slave of a load balancer
+IFF_SLAVE_INACTIVE nil bonding slave not the curr. active
+IFF_SLAVE_NEEDARP nil need ARPs for validation
+IFF_SMART nil interface manages own routes
+IFF_STATICARP nil static ARP
+IFF_SUPP_NOFCS nil sending custom FCS
+IFF_TEAM_PORT nil used as team port
+IFF_TX_SKB_SHARING nil sharing skbs on transmit
+IFF_UNICAST_FLT nil unicast filtering
+IFF_UP nil interface is up
+IFF_WAN_HDLC nil WAN HDLC device
+IFF_XMIT_DST_RELEASE nil dev_hard_start_xmit() is allowed to release skb->dst
+IFF_VOLATILE nil volatile flags
+IFF_CANTCHANGE nil flags not changeable
diff --git a/ext/socket/option.c b/ext/socket/option.c
index e3e59cf0c5..4b33b3f1d3 100644
--- a/ext/socket/option.c
+++ b/ext/socket/option.c
@@ -2,6 +2,51 @@
VALUE rb_cSockOpt;
+#define pack_var(v) rb_str_new((const char *)&(v), sizeof(v))
+
+#define CAT(x,y) x##y
+#define XCAT(x,y) CAT(x,y)
+
+#if defined(__linux__) || \
+ defined(__GNU__) /* GNU/Hurd */ || \
+ defined(__FreeBSD__) || \
+ defined(__DragonFly__) || \
+ defined(__APPLE__) || \
+ defined(_WIN32) || \
+ defined(__CYGWIN__)
+# define TYPE_IP_MULTICAST_LOOP int
+# define TYPE_IP_MULTICAST_TTL int
+#else
+/* The original IP multicast implementation by Steve Deering
+ * NetBSD
+ * OpenBSD
+ * SunOS
+ */
+# define TYPE_IP_MULTICAST_LOOP byte
+# define TYPE_IP_MULTICAST_TTL byte
+# define USE_INSPECT_BYTE 1
+#endif
+
+#define check_size(len, size) \
+ ((len) == (size) ? \
+ (void)0 : \
+ rb_raise(rb_eTypeError, "size differ. expected as "#size"=%d but %ld", \
+ (int)size, (long)(len)))
+
+static VALUE
+sockopt_pack_byte(VALUE value)
+{
+ char i = NUM2CHR(rb_to_int(value));
+ return pack_var(i);
+}
+
+static VALUE
+sockopt_pack_int(VALUE value)
+{
+ int i = NUM2INT(rb_to_int(value));
+ return pack_var(i);
+}
+
static VALUE
constant_to_sym(int constant, ID (*intern_const)(int))
{
@@ -21,7 +66,7 @@ optname_to_sym(int level, int optname)
return constant_to_sym(optname, rsock_intern_so_optname);
case IPPROTO_IP:
return constant_to_sym(optname, rsock_intern_ip_optname);
-#ifdef INET6
+#ifdef IPPROTO_IPV6
case IPPROTO_IPV6:
return constant_to_sym(optname, rsock_intern_ipv6_optname);
#endif
@@ -61,9 +106,9 @@ sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALU
VALUE
rsock_sockopt_new(int family, int level, int optname, VALUE data)
{
- NEWOBJ_OF(obj, struct RObject, rb_cSockOpt, T_OBJECT);
+ VALUE obj = rb_obj_alloc(rb_cSockOpt);
StringValue(data);
- sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
+ sockopt_initialize(obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
return (VALUE)obj;
}
@@ -127,6 +172,7 @@ sockopt_optname_m(VALUE self)
/*
* call-seq:
* sockopt.data => string
+ * sockopt.to_s => string
*
* returns the socket option data as a string.
*
@@ -143,6 +189,42 @@ sockopt_data(VALUE self)
/*
* call-seq:
+ * Socket::Option.byte(family, level, optname, integer) => sockopt
+ *
+ * Creates a new Socket::Option object which contains a byte as data.
+ *
+ * p Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1)
+ * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
+ */
+static VALUE
+sockopt_s_byte(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
+{
+ int family = rsock_family_arg(vfamily);
+ int level = rsock_level_arg(family, vlevel);
+ int optname = rsock_optname_arg(family, level, voptname);
+ return rsock_sockopt_new(family, level, optname, sockopt_pack_byte(vint));
+}
+
+/*
+ * call-seq:
+ * sockopt.byte => integer
+ *
+ * Returns the data in _sockopt_ as an byte.
+ *
+ * sockopt = Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1)
+ * p sockopt.byte => 1
+ */
+static VALUE
+sockopt_byte(VALUE self)
+{
+ VALUE data = sockopt_data(self);
+ StringValue(data);
+ check_size(RSTRING_LEN(data), sizeof(char));
+ return CHR2FIX(*RSTRING_PTR(data));
+}
+
+/*
+ * call-seq:
* Socket::Option.int(family, level, optname, integer) => sockopt
*
* Creates a new Socket::Option object which contains an int as data.
@@ -158,8 +240,7 @@ sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vi
int family = rsock_family_arg(vfamily);
int level = rsock_level_arg(family, vlevel);
int optname = rsock_optname_arg(family, level, voptname);
- int i = NUM2INT(vint);
- return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
+ return rsock_sockopt_new(family, level, optname, sockopt_pack_int(vint));
}
/*
@@ -179,9 +260,7 @@ sockopt_int(VALUE self)
int i;
VALUE data = sockopt_data(self);
StringValue(data);
- if (RSTRING_LEN(data) != sizeof(int))
- rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
- (int)sizeof(int), (long)RSTRING_LEN(data));
+ check_size(RSTRING_LEN(data), sizeof(int));
memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
return INT2NUM(i);
}
@@ -193,6 +272,8 @@ sockopt_int(VALUE self)
* Creates a new Socket::Option object which contains boolean as data.
* Actually 0 or 1 as int is used.
*
+ * require 'socket'
+ *
* p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
* #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
*
@@ -207,7 +288,7 @@ sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE v
int level = rsock_level_arg(family, vlevel);
int optname = rsock_optname_arg(family, level, voptname);
int i = RTEST(vbool) ? 1 : 0;
- return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
+ return rsock_sockopt_new(family, level, optname, pack_var(i));
}
/*
@@ -223,12 +304,15 @@ static VALUE
sockopt_bool(VALUE self)
{
int i;
+ long len;
VALUE data = sockopt_data(self);
StringValue(data);
- if (RSTRING_LEN(data) != sizeof(int))
- rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
- (int)sizeof(int), (long)RSTRING_LEN(data));
- memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
+ len = RSTRING_LEN(data);
+ if (len == 1) {
+ return *RSTRING_PTR(data) == 0 ? Qfalse : Qtrue;
+ }
+ check_size(len, sizeof(int));
+ memcpy((char*)&i, RSTRING_PTR(data), len);
return i == 0 ? Qfalse : Qtrue;
}
@@ -257,7 +341,7 @@ sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
else
l.l_onoff = RTEST(vonoff) ? 1 : 0;
l.l_linger = NUM2INT(vsecs);
- return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
+ return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, pack_var(l));
}
/*
@@ -280,9 +364,7 @@ sockopt_linger(VALUE self)
if (level != SOL_SOCKET || optname != SO_LINGER)
rb_raise(rb_eTypeError, "linger socket option expected");
- if (RSTRING_LEN(data) != sizeof(l))
- rb_raise(rb_eTypeError, "size differ. expected as sizeof(struct linger)=%d but %ld",
- (int)sizeof(struct linger), (long)RSTRING_LEN(data));
+ check_size(RSTRING_LEN(data), sizeof(struct linger));
memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
switch (l.l_onoff) {
case 0: vonoff = Qfalse; break;
@@ -293,6 +375,112 @@ sockopt_linger(VALUE self)
return rb_assoc_new(vonoff, vsecs);
}
+/*
+ * call-seq:
+ * Socket::Option.ipv4_multicast_loop(integer) => sockopt
+ *
+ * Creates a new Socket::Option object for IP_MULTICAST_LOOP.
+ *
+ * The size is dependent on the platform.
+ *
+ * sockopt = Socket::Option.int(:INET, :IPPROTO_IP, :IP_MULTICAST_LOOP, 1)
+ * p sockopt.int => 1
+ *
+ * p Socket::Option.ipv4_multicast_loop(10)
+ * #=> #<Socket::Option: INET IP MULTICAST_LOOP 10>
+ *
+ */
+static VALUE
+sockopt_s_ipv4_multicast_loop(VALUE klass, VALUE value)
+{
+
+#if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
+ VALUE o = XCAT(sockopt_pack_,TYPE_IP_MULTICAST_LOOP)(value);
+ return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_LOOP, o);
+#else
+# error IPPROTO_IP or IP_MULTICAST_LOOP is not implemented
+#endif
+}
+
+/*
+ * call-seq:
+ * sockopt.ipv4_multicast_loop => integer
+ *
+ * Returns the ipv4_multicast_loop data in _sockopt_ as an integer.
+ *
+ * sockopt = Socket::Option.ipv4_multicast_loop(10)
+ * p sockopt.ipv4_multicast_loop => 10
+ */
+static VALUE
+sockopt_ipv4_multicast_loop(VALUE self)
+{
+ int family = NUM2INT(sockopt_family_m(self));
+ int level = sockopt_level(self);
+ int optname = sockopt_optname(self);
+
+#if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
+ if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_LOOP) {
+ return XCAT(sockopt_,TYPE_IP_MULTICAST_LOOP)(self);
+ }
+#endif
+ rb_raise(rb_eTypeError, "ipv4_multicast_loop socket option expected");
+ UNREACHABLE_RETURN(Qnil);
+}
+
+#define inspect_ipv4_multicast_loop(a,b,c,d) \
+ XCAT(inspect_,TYPE_IP_MULTICAST_LOOP)(a,b,c,d)
+
+/*
+ * call-seq:
+ * Socket::Option.ipv4_multicast_ttl(integer) => sockopt
+ *
+ * Creates a new Socket::Option object for IP_MULTICAST_TTL.
+ *
+ * The size is dependent on the platform.
+ *
+ * p Socket::Option.ipv4_multicast_ttl(10)
+ * #=> #<Socket::Option: INET IP MULTICAST_TTL 10>
+ *
+ */
+static VALUE
+sockopt_s_ipv4_multicast_ttl(VALUE klass, VALUE value)
+{
+#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
+ VALUE o = XCAT(sockopt_pack_,TYPE_IP_MULTICAST_TTL)(value);
+ return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_TTL, o);
+#else
+# error IPPROTO_IP or IP_MULTICAST_TTL is not implemented
+#endif
+}
+
+/*
+ * call-seq:
+ * sockopt.ipv4_multicast_ttl => integer
+ *
+ * Returns the ipv4_multicast_ttl data in _sockopt_ as an integer.
+ *
+ * sockopt = Socket::Option.ipv4_multicast_ttl(10)
+ * p sockopt.ipv4_multicast_ttl => 10
+ */
+static VALUE
+sockopt_ipv4_multicast_ttl(VALUE self)
+{
+ int family = NUM2INT(sockopt_family_m(self));
+ int level = sockopt_level(self);
+ int optname = sockopt_optname(self);
+
+#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
+ if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_TTL) {
+ return XCAT(sockopt_,TYPE_IP_MULTICAST_TTL)(self);
+ }
+#endif
+ rb_raise(rb_eTypeError, "ipv4_multicast_ttl socket option expected");
+ UNREACHABLE_RETURN(Qnil);
+}
+
+#define inspect_ipv4_multicast_ttl(a,b,c,d) \
+ XCAT(inspect_,TYPE_IP_MULTICAST_TTL)(a,b,c,d)
+
static int
inspect_int(int level, int optname, VALUE data, VALUE ret)
{
@@ -307,6 +495,20 @@ inspect_int(int level, int optname, VALUE data, VALUE ret)
}
}
+#ifdef USE_INSPECT_BYTE
+static int
+inspect_byte(int level, int optname, VALUE data, VALUE ret)
+{
+ if (RSTRING_LEN(data) == sizeof(unsigned char)) {
+ rb_str_catf(ret, " %d", (unsigned char)*RSTRING_PTR(data));
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+#endif
+
static int
inspect_errno(int level, int optname, VALUE data, VALUE ret)
{
@@ -403,6 +605,15 @@ inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
* (MULTICAST 1.2 Release)
* http://www.kohala.com/start/mcast.api.txt
*
+ * There are 2 socket options which takes a u_char (unsigned char).
+ *
+ * IP_MULTICAST_TTL
+ * IP_MULTICAST_LOOP
+ *
+ * However Linux and FreeBSD setsockname accepts int argument
+ * as well as u_char.
+ * Their getsockname returns int.
+ *
* There are 3 socket options which takes a struct.
*
* IP_MULTICAST_IF: struct in_addr
@@ -435,8 +646,8 @@ inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
* it is not distinguishable by the size.
*/
-#ifndef HAVE_INET_NTOP
-static const char *
+#if !defined HAVE_INET_NTOP && ! defined _WIN32
+const char *
inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
{
#ifdef HAVE_INET_NTOA
@@ -451,8 +662,6 @@ inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
#endif
return numaddr;
}
-#elif defined __MINGW64__
-# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
#endif
/* Although the buffer size needed depends on the prefixes, "%u" may generate "4294967295". */
@@ -601,6 +810,333 @@ inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
}
#endif
+#if defined(IPPROTO_TCP) && defined(TCP_INFO) && defined(HAVE_TYPE_STRUCT_TCP_INFO)
+
+#ifdef __FreeBSD__
+# ifndef HAVE_CONST_TCP_ESTABLISHED
+# define TCP_ESTABLISHED TCPS_ESTABLISHED
+# endif
+# ifndef HAVE_CONST_TCP_SYN_SENT
+# define TCP_SYN_SENT TCPS_SYN_SENT
+# endif
+# ifndef HAVE_CONST_TCP_SYN_RECV
+# define TCP_SYN_RECV TCPS_SYN_RECEIVED
+# endif
+# ifndef HAVE_CONST_TCP_FIN_WAIT1
+# define TCP_FIN_WAIT1 TCPS_FIN_WAIT_1
+# endif
+# ifndef HAVE_CONST_TCP_FIN_WAIT2
+# define TCP_FIN_WAIT2 TCPS_FIN_WAIT_2
+# endif
+# ifndef HAVE_CONST_TCP_TIME_WAIT
+# define TCP_TIME_WAIT TCPS_TIME_WAIT
+# endif
+# ifndef HAVE_CONST_TCP_CLOSE
+# define TCP_CLOSE TCPS_CLOSED
+# endif
+# ifndef HAVE_CONST_TCP_CLOSE_WAIT
+# define TCP_CLOSE_WAIT TCPS_CLOSE_WAIT
+# endif
+# ifndef HAVE_CONST_TCP_LAST_ACK
+# define TCP_LAST_ACK TCPS_LAST_ACK
+# endif
+# ifndef HAVE_CONST_TCP_LISTEN
+# define TCP_LISTEN TCPS_LISTEN
+# endif
+# ifndef HAVE_CONST_TCP_CLOSING
+# define TCP_CLOSING TCPS_CLOSING
+# endif
+#endif
+
+#if defined(HAVE_CONST_TCP_ESTABLISHED) && !defined(TCP_ESTABLISHED)
+# define TCP_ESTABLISHED TCP_ESTABLISHED
+#endif
+#if defined(HAVE_CONST_TCP_SYN_SENT) && !defined(TCP_SYN_SENT)
+# define TCP_SYN_SENT TCP_SYN_SENT
+#endif
+#if defined(HAVE_CONST_TCP_SYN_RECV) && !defined(TCP_SYN_RECV)
+# define TCP_SYN_RECV TCP_SYN_RECV
+#endif
+#if defined(HAVE_CONST_TCP_FIN_WAIT1) && !defined(TCP_FIN_WAIT1)
+# define TCP_FIN_WAIT1 TCP_FIN_WAIT1
+#endif
+#if defined(HAVE_CONST_TCP_FIN_WAIT2) && !defined(TCP_FIN_WAIT2)
+# define TCP_FIN_WAIT2 TCP_FIN_WAIT2
+#endif
+#if defined(HAVE_CONST_TCP_TIME_WAIT) && !defined(TCP_TIME_WAIT)
+# define TCP_TIME_WAIT TCP_TIME_WAIT
+#endif
+#if defined(HAVE_CONST_TCP_CLOSE) && !defined(TCP_CLOSE)
+# define TCP_CLOSE TCP_CLOSE
+#endif
+#if defined(HAVE_CONST_TCP_CLOSE_WAIT) && !defined(TCP_CLOSE_WAIT)
+# define TCP_CLOSE_WAIT TCP_CLOSE_WAIT
+#endif
+#if defined(HAVE_CONST_TCP_LAST_ACK) && !defined(TCP_LAST_ACK)
+# define TCP_LAST_ACK TCP_LAST_ACK
+#endif
+#if defined(HAVE_CONST_TCP_LISTEN) && !defined(TCP_LISTEN)
+# define TCP_LISTEN TCP_LISTEN
+#endif
+#if defined(HAVE_CONST_TCP_CLOSING) && !defined(TCP_CLOSING)
+# define TCP_CLOSING TCP_CLOSING
+#endif
+
+static void
+inspect_tcpi_options(VALUE ret, uint8_t options)
+{
+ int sep = '=';
+
+ rb_str_cat2(ret, " options");
+#define INSPECT_TCPI_OPTION(optval, name) \
+ if (options & (optval)) { \
+ options &= ~(uint8_t)(optval); \
+ rb_str_catf(ret, "%c%s", sep, name); \
+ sep = ','; \
+ }
+#ifdef TCPI_OPT_TIMESTAMPS /* GNU/Linux, FreeBSD */
+ INSPECT_TCPI_OPTION(TCPI_OPT_TIMESTAMPS, "TIMESTAMPS");
+#endif
+#ifdef TCPI_OPT_SACK /* GNU/Linux, FreeBSD */
+ INSPECT_TCPI_OPTION(TCPI_OPT_SACK, "SACK");
+#endif
+#ifdef TCPI_OPT_WSCALE /* GNU/Linux, FreeBSD */
+ INSPECT_TCPI_OPTION(TCPI_OPT_WSCALE, "WSCALE");
+#endif
+#ifdef TCPI_OPT_ECN /* GNU/Linux, FreeBSD */
+ INSPECT_TCPI_OPTION(TCPI_OPT_ECN, "ECN");
+#endif
+#ifdef TCPI_OPT_ECN_SEEN /* GNU/Linux */
+ INSPECT_TCPI_OPTION(TCPI_OPT_ECN_SEEN, "ECN_SEEN");
+#endif
+#ifdef TCPI_OPT_SYN_DATA /* GNU/Linux */
+ INSPECT_TCPI_OPTION(TCPI_OPT_SYN_DATA, "SYN_DATA");
+#endif
+#ifdef TCPI_OPT_TOE /* FreeBSD */
+ INSPECT_TCPI_OPTION(TCPI_OPT_TOE, "TOE");
+#endif
+#undef INSPECT_TCPI_OPTION
+
+ if (options || sep == '=') {
+ rb_str_catf(ret, "%c%u", sep, options);
+ }
+}
+
+static void
+inspect_tcpi_usec(VALUE ret, const char *prefix, uint32_t t)
+{
+ rb_str_catf(ret, "%s%u.%06us", prefix, t / 1000000, t % 1000000);
+}
+
+#if !defined __FreeBSD__ && ( \
+ defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_SENT || \
+ defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_RECV || \
+ defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_SENT || \
+ defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_RECV || \
+ 0)
+static void
+inspect_tcpi_msec(VALUE ret, const char *prefix, uint32_t t)
+{
+ rb_str_catf(ret, "%s%u.%03us", prefix, t / 1000, t % 1000);
+}
+#endif
+
+#ifdef __FreeBSD__
+# define inspect_tcpi_rto(ret, t) inspect_tcpi_usec(ret, " rto=", t)
+# define inspect_tcpi_last_data_recv(ret, t) inspect_tcpi_usec(ret, " last_data_recv=", t)
+# define inspect_tcpi_rtt(ret, t) inspect_tcpi_usec(ret, " rtt=", t)
+# define inspect_tcpi_rttvar(ret, t) inspect_tcpi_usec(ret, " rttvar=", t)
+#else
+# define inspect_tcpi_rto(ret, t) inspect_tcpi_usec(ret, " rto=", t)
+# define inspect_tcpi_ato(ret, t) inspect_tcpi_usec(ret, " ato=", t)
+# define inspect_tcpi_last_data_sent(ret, t) inspect_tcpi_msec(ret, " last_data_sent=", t)
+# define inspect_tcpi_last_data_recv(ret, t) inspect_tcpi_msec(ret, " last_data_recv=", t)
+# define inspect_tcpi_last_ack_sent(ret, t) inspect_tcpi_msec(ret, " last_ack_sent=", t)
+# define inspect_tcpi_last_ack_recv(ret, t) inspect_tcpi_msec(ret, " last_ack_recv=", t)
+# define inspect_tcpi_rtt(ret, t) inspect_tcpi_usec(ret, " rtt=", t)
+# define inspect_tcpi_rttvar(ret, t) inspect_tcpi_usec(ret, " rttvar=", t)
+# define inspect_tcpi_rcv_rtt(ret, t) inspect_tcpi_usec(ret, " rcv_rtt=", t)
+#endif
+
+static int
+inspect_tcp_info(int level, int optname, VALUE data, VALUE ret)
+{
+ size_t actual_size = RSTRING_LEN(data);
+ if (sizeof(struct tcp_info) <= actual_size) {
+ struct tcp_info s;
+ memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_STATE
+ switch (s.tcpi_state) {
+# ifdef TCP_ESTABLISHED
+ case TCP_ESTABLISHED: rb_str_cat_cstr(ret, " state=ESTABLISHED"); break;
+# endif
+# ifdef TCP_SYN_SENT
+ case TCP_SYN_SENT: rb_str_cat_cstr(ret, " state=SYN_SENT"); break;
+# endif
+# ifdef TCP_SYN_RECV
+ case TCP_SYN_RECV: rb_str_cat_cstr(ret, " state=SYN_RECV"); break;
+# endif
+# ifdef TCP_FIN_WAIT1
+ case TCP_FIN_WAIT1: rb_str_cat_cstr(ret, " state=FIN_WAIT1"); break;
+# endif
+# ifdef TCP_FIN_WAIT2
+ case TCP_FIN_WAIT2: rb_str_cat_cstr(ret, " state=FIN_WAIT2"); break;
+# endif
+# ifdef TCP_TIME_WAIT
+ case TCP_TIME_WAIT: rb_str_cat_cstr(ret, " state=TIME_WAIT"); break;
+# endif
+# ifdef TCP_CLOSE
+ case TCP_CLOSE: rb_str_cat_cstr(ret, " state=CLOSED"); break; /* RFC 793 uses "CLOSED", not "CLOSE" */
+# endif
+# ifdef TCP_CLOSE_WAIT
+ case TCP_CLOSE_WAIT: rb_str_cat_cstr(ret, " state=CLOSE_WAIT"); break;
+# endif
+# ifdef TCP_LAST_ACK
+ case TCP_LAST_ACK: rb_str_cat_cstr(ret, " state=LAST_ACK"); break;
+# endif
+# ifdef TCP_LISTEN
+ case TCP_LISTEN: rb_str_cat_cstr(ret, " state=LISTEN"); break;
+# endif
+# ifdef TCP_CLOSING
+ case TCP_CLOSING: rb_str_cat_cstr(ret, " state=CLOSING"); break;
+# endif
+ default: rb_str_catf(ret, " state=%u", s.tcpi_state); break;
+ }
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_CA_STATE
+ switch (s.tcpi_ca_state) {
+ case TCP_CA_Open: rb_str_cat_cstr(ret, " ca_state=Open"); break;
+ case TCP_CA_Disorder: rb_str_cat_cstr(ret, " ca_state=Disorder"); break;
+ case TCP_CA_CWR: rb_str_cat_cstr(ret, " ca_state=CWR"); break;
+ case TCP_CA_Recovery: rb_str_cat_cstr(ret, " ca_state=Recovery"); break;
+ case TCP_CA_Loss: rb_str_cat_cstr(ret, " ca_state=Loss"); break;
+ default: rb_str_catf(ret, " ca_state=%u", s.tcpi_ca_state); break;
+ }
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RETRANSMITS
+ rb_str_catf(ret, " retransmits=%u", s.tcpi_retransmits);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_PROBES
+ rb_str_catf(ret, " probes=%u", s.tcpi_probes);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_BACKOFF
+ rb_str_catf(ret, " backoff=%u", s.tcpi_backoff);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_OPTIONS
+ inspect_tcpi_options(ret, s.tcpi_options);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_WSCALE
+ rb_str_catf(ret, " snd_wscale=%u", s.tcpi_snd_wscale);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_WSCALE
+ rb_str_catf(ret, " rcv_wscale=%u", s.tcpi_rcv_wscale);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTO
+ inspect_tcpi_rto(ret, s.tcpi_rto);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_ATO
+ inspect_tcpi_ato(ret, s.tcpi_ato);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_MSS
+ rb_str_catf(ret, " snd_mss=%u", s.tcpi_snd_mss);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_MSS
+ rb_str_catf(ret, " rcv_mss=%u", s.tcpi_rcv_mss);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_UNACKED
+ rb_str_catf(ret, " unacked=%u", s.tcpi_unacked);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SACKED
+ rb_str_catf(ret, " sacked=%u", s.tcpi_sacked);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_LOST
+ rb_str_catf(ret, " lost=%u", s.tcpi_lost);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RETRANS
+ rb_str_catf(ret, " retrans=%u", s.tcpi_retrans);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_FACKETS
+ rb_str_catf(ret, " fackets=%u", s.tcpi_fackets);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_SENT
+ inspect_tcpi_last_data_sent(ret, s.tcpi_last_data_sent);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_SENT
+ inspect_tcpi_last_ack_sent(ret, s.tcpi_last_ack_sent);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_RECV
+ inspect_tcpi_last_data_recv(ret, s.tcpi_last_data_recv);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_RECV
+ inspect_tcpi_last_ack_recv(ret, s.tcpi_last_ack_recv);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_PMTU
+ rb_str_catf(ret, " pmtu=%u", s.tcpi_pmtu);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_SSTHRESH
+ rb_str_catf(ret, " rcv_ssthresh=%u", s.tcpi_rcv_ssthresh);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTT
+ inspect_tcpi_rtt(ret, s.tcpi_rtt);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTTVAR
+ inspect_tcpi_rttvar(ret, s.tcpi_rttvar);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_SSTHRESH
+ rb_str_catf(ret, " snd_ssthresh=%u", s.tcpi_snd_ssthresh);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
+ rb_str_catf(ret, " snd_cwnd=%u", s.tcpi_snd_cwnd);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_ADVMSS
+ rb_str_catf(ret, " advmss=%u", s.tcpi_advmss);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_REORDERING
+ rb_str_catf(ret, " reordering=%u", s.tcpi_reordering);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_RTT
+ inspect_tcpi_rcv_rtt(ret, s.tcpi_rcv_rtt);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_SPACE
+ rb_str_catf(ret, " rcv_space=%u", s.tcpi_rcv_space);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_TOTAL_RETRANS
+ rb_str_catf(ret, " total_retrans=%u", s.tcpi_total_retrans);
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_WND
+ rb_str_catf(ret, " snd_wnd=%u", s.tcpi_snd_wnd); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_BWND
+ rb_str_catf(ret, " snd_bwnd=%u", s.tcpi_snd_bwnd); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_NXT
+ rb_str_catf(ret, " snd_nxt=%u", s.tcpi_snd_nxt); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_NXT
+ rb_str_catf(ret, " rcv_nxt=%u", s.tcpi_rcv_nxt); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_TOE_TID
+ rb_str_catf(ret, " toe_tid=%u", s.tcpi_toe_tid); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_REXMITPACK
+ rb_str_catf(ret, " snd_rexmitpack=%u", s.tcpi_snd_rexmitpack); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_OOOPACK
+ rb_str_catf(ret, " rcv_ooopack=%u", s.tcpi_rcv_ooopack); /* FreeBSD */
+#endif
+#ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_ZEROWIN
+ rb_str_catf(ret, " snd_zerowin=%u", s.tcpi_snd_zerowin); /* FreeBSD */
+#endif
+ if (sizeof(struct tcp_info) < actual_size)
+ rb_str_catf(ret, " (%u bytes too long)", (unsigned)(actual_size - sizeof(struct tcp_info)));
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+#endif
+
#if defined(SOL_SOCKET) && defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */
#if defined(__OpenBSD__)
#define RUBY_SOCK_PEERCRED struct sockpeercred
@@ -713,7 +1249,7 @@ sockopt_inspect(VALUE self)
v = optname_to_sym(level, optname);
if (SYMBOL_P(v))
- rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
+ rb_str_catf(ret, " %"PRIsVALUE, rb_sym2str(v));
else
rb_str_catf(ret, " optname:%d", optname);
}
@@ -804,6 +1340,12 @@ sockopt_inspect(VALUE self)
# if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
# endif
+# if defined(IP_MULTICAST_LOOP) /* 4.4BSD, GNU/Linux */
+ case IP_MULTICAST_LOOP: inspected = inspect_ipv4_multicast_loop(level, optname, data, ret); break;
+# endif
+# if defined(IP_MULTICAST_TTL) /* 4.4BSD, GNU/Linux */
+ case IP_MULTICAST_TTL: inspected = inspect_ipv4_multicast_ttl(level, optname, data, ret); break;
+# endif
}
break;
# endif
@@ -842,6 +1384,9 @@ sockopt_inspect(VALUE self)
# if defined(TCP_NODELAY) /* POSIX */
case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
# endif
+# if defined(TCP_INFO) && defined(HAVE_TYPE_STRUCT_TCP_INFO) /* Linux, FreeBSD */
+ case TCP_INFO: inspected = inspect_tcp_info(level, optname, data, ret); break;
+# endif
}
break;
# endif
@@ -911,14 +1456,22 @@ rsock_init_sockopt(void)
rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4);
rb_define_method(rb_cSockOpt, "int", sockopt_int, 0);
+ rb_define_singleton_method(rb_cSockOpt, "byte", sockopt_s_byte, 4);
+ rb_define_method(rb_cSockOpt, "byte", sockopt_byte, 0);
+
rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4);
rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0);
rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2);
rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0);
+ rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_s_ipv4_multicast_ttl, 1);
+ rb_define_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_ipv4_multicast_ttl, 0);
+
+ rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_s_ipv4_multicast_loop, 1);
+ rb_define_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_ipv4_multicast_loop, 0);
+
rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */
}
-
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 6a5129efa8..d94e96a2bc 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -1,6 +1,6 @@
/************************************************
- ainfo.c -
+ raddrinfo.c -
created at: Thu Mar 31 12:21:29 JST 1994
@@ -145,6 +145,34 @@ ruby_getaddrinfo__darwin(const char *nodename, const char *servname,
#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__darwin((node),(serv),(hints),(res))
#endif
+#ifdef HAVE_INET_PTON
+static int
+parse_numeric_port(const char *service, int *portp)
+{
+ unsigned long u;
+
+ if (!service) {
+ *portp = 0;
+ return 1;
+ }
+
+ if (strspn(service, "0123456789") != strlen(service))
+ return 0;
+
+ errno = 0;
+ u = STRTOUL(service, NULL, 10);
+ if (errno)
+ return 0;
+
+ if (0x10000 <= u)
+ return 0;
+
+ *portp = (int)u;
+
+ return 1;
+}
+#endif
+
#ifndef GETADDRINFO_EMU
struct getaddrinfo_arg
{
@@ -157,30 +185,121 @@ struct getaddrinfo_arg
static void *
nogvl_getaddrinfo(void *arg)
{
+ int ret;
struct getaddrinfo_arg *ptr = arg;
- return (void *)(VALUE)getaddrinfo(ptr->node, ptr->service,
- ptr->hints, ptr->res);
+ ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
+#ifdef __linux__
+ /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
+ * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
+ */
+ if (ret == EAI_SYSTEM && errno == ENOENT)
+ ret = EAI_NONAME;
+#endif
+ return (void *)(VALUE)ret;
}
#endif
-int
-rb_getaddrinfo(const char *node, const char *service,
- const struct addrinfo *hints,
- struct addrinfo **res)
+static int
+numeric_getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
{
-#ifdef GETADDRINFO_EMU
- return getaddrinfo(node, service, hints, res);
-#else
- struct getaddrinfo_arg arg;
- int ret;
- MEMZERO(&arg, sizeof arg, 1);
- arg.node = node;
- arg.service = service;
- arg.hints = hints;
- arg.res = res;
- ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
- return ret;
+#ifdef HAVE_INET_PTON
+# if defined __MINGW64__
+# define inet_pton(f,s,d) rb_w32_inet_pton(f,s,d)
+# endif
+
+ int port;
+
+ if (node && parse_numeric_port(service, &port)) {
+ static const struct {
+ int socktype;
+ int protocol;
+ } list[] = {
+ { SOCK_STREAM, IPPROTO_TCP },
+ { SOCK_DGRAM, IPPROTO_UDP },
+ { SOCK_RAW, 0 }
+ };
+ struct addrinfo *ai = NULL;
+ int hint_family = hints ? hints->ai_family : PF_UNSPEC;
+ int hint_socktype = hints ? hints->ai_socktype : 0;
+ int hint_protocol = hints ? hints->ai_protocol : 0;
+ char ipv4addr[4];
+#ifdef AF_INET6
+ char ipv6addr[16];
+ if ((hint_family == PF_UNSPEC || hint_family == PF_INET6) &&
+ strspn(node, "0123456789abcdefABCDEF.:") == strlen(node) &&
+ inet_pton(AF_INET6, node, ipv6addr)) {
+ int i;
+ for (i = numberof(list)-1; 0 <= i; i--) {
+ if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
+ (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
+ struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
+ struct sockaddr_in6 *sa = xmalloc(sizeof(struct sockaddr_in6));
+ INIT_SOCKADDR_IN6(sa, sizeof(struct sockaddr_in6));
+ memcpy(&sa->sin6_addr, ipv6addr, sizeof(ipv6addr));
+ sa->sin6_port = htons(port);
+ ai0->ai_family = PF_INET6;
+ ai0->ai_socktype = list[i].socktype;
+ ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
+ ai0->ai_addrlen = sizeof(struct sockaddr_in6);
+ ai0->ai_addr = (struct sockaddr *)sa;
+ ai0->ai_canonname = NULL;
+ ai0->ai_next = ai;
+ ai = ai0;
+ }
+ }
+ }
+ else
+#endif
+ if ((hint_family == PF_UNSPEC || hint_family == PF_INET) &&
+ strspn(node, "0123456789.") == strlen(node) &&
+ inet_pton(AF_INET, node, ipv4addr)) {
+ int i;
+ for (i = numberof(list)-1; 0 <= i; i--) {
+ if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
+ (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
+ struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo));
+ struct sockaddr_in *sa = xmalloc(sizeof(struct sockaddr_in));
+ INIT_SOCKADDR_IN(sa, sizeof(struct sockaddr_in));
+ memcpy(&sa->sin_addr, ipv4addr, sizeof(ipv4addr));
+ sa->sin_port = htons(port);
+ ai0->ai_family = PF_INET;
+ ai0->ai_socktype = list[i].socktype;
+ ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
+ ai0->ai_addrlen = sizeof(struct sockaddr_in);
+ ai0->ai_addr = (struct sockaddr *)sa;
+ ai0->ai_canonname = NULL;
+ ai0->ai_next = ai;
+ ai = ai0;
+ }
+ }
+ }
+ if (ai) {
+ *res = ai;
+ return 0;
+ }
+ }
#endif
+ return EAI_FAIL;
+}
+
+void
+rb_freeaddrinfo(struct rb_addrinfo *ai)
+{
+ if (!ai->allocated_by_malloc)
+ freeaddrinfo(ai->ai);
+ else {
+ struct addrinfo *ai1, *ai2;
+ ai1 = ai->ai;
+ while (ai1) {
+ ai2 = ai1->ai_next;
+ xfree(ai1->ai_addr);
+ xfree(ai1);
+ ai1 = ai2;
+ }
+ }
+ xfree(ai);
}
#ifndef GETADDRINFO_EMU
@@ -188,11 +307,11 @@ struct getnameinfo_arg
{
const struct sockaddr *sa;
socklen_t salen;
+ int flags;
char *host;
size_t hostlen;
char *serv;
size_t servlen;
- int flags;
};
static void *
@@ -229,35 +348,33 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
}
static void
-make_ipaddr0(struct sockaddr *addr, char *buf, size_t len)
+make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
{
int error;
- error = rb_getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST);
+ error = rb_getnameinfo(addr, addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
}
}
VALUE
-rsock_make_ipaddr(struct sockaddr *addr)
+rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
{
char hbuf[1024];
- make_ipaddr0(addr, hbuf, sizeof(hbuf));
+ make_ipaddr0(addr, addrlen, hbuf, sizeof(hbuf));
return rb_str_new2(hbuf);
}
static void
-make_inetaddr(unsigned int host, char *buf, size_t len)
+make_inetaddr(unsigned int host, char *buf, size_t buflen)
{
struct sockaddr_in sin;
- MEMZERO(&sin, struct sockaddr_in, 1);
- sin.sin_family = AF_INET;
- SET_SIN_LEN(&sin, sizeof(sin));
+ INIT_SOCKADDR_IN(&sin, sizeof(sin));
sin.sin_addr.s_addr = host;
- make_ipaddr0((struct sockaddr*)&sin, buf, len);
+ make_ipaddr0((struct sockaddr*)&sin, sizeof(sin), buf, buflen);
}
static int
@@ -266,17 +383,21 @@ str_is_number(const char *p)
char *ep;
if (!p || *p == '\0')
- return 0;
+ return 0;
ep = NULL;
(void)STRTOUL(p, &ep, 10);
if (ep && *ep == '\0')
- return 1;
+ return 1;
else
- return 0;
+ return 0;
}
+#define str_equal(ptr, len, name) \
+ ((ptr)[0] == name[0] && \
+ rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 0)
+
static char*
-host_str(VALUE host, char *hbuf, size_t len, int *flags_ptr)
+host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
{
if (NIL_P(host)) {
return NULL;
@@ -284,67 +405,122 @@ host_str(VALUE host, char *hbuf, size_t len, int *flags_ptr)
else if (rb_obj_is_kind_of(host, rb_cInteger)) {
unsigned int i = NUM2UINT(host);
- make_inetaddr(htonl(i), hbuf, len);
+ make_inetaddr(htonl(i), hbuf, hbuflen);
if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
return hbuf;
}
else {
- char *name;
+ const char *name;
+ size_t len;
- SafeStringValue(host);
- name = RSTRING_PTR(host);
- if (!name || *name == 0 || (name[0] == '<' && strcmp(name, "<any>") == 0)) {
- make_inetaddr(INADDR_ANY, hbuf, len);
+ StringValueCStr(host);
+ RSTRING_GETMEM(host, name, len);
+ if (!len || str_equal(name, len, "<any>")) {
+ make_inetaddr(INADDR_ANY, hbuf, hbuflen);
if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
}
- else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
- make_inetaddr(INADDR_BROADCAST, hbuf, len);
+ else if (str_equal(name, len, "<broadcast>")) {
+ make_inetaddr(INADDR_BROADCAST, hbuf, hbuflen);
if (flags_ptr) *flags_ptr |= AI_NUMERICHOST;
}
- else if (strlen(name) >= len) {
+ else if (len >= hbuflen) {
rb_raise(rb_eArgError, "hostname too long (%"PRIuSIZE")",
- strlen(name));
+ len);
}
else {
- strcpy(hbuf, name);
+ memcpy(hbuf, name, len);
+ hbuf[len] = '\0';
}
return hbuf;
}
}
static char*
-port_str(VALUE port, char *pbuf, size_t len, int *flags_ptr)
+port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
{
if (NIL_P(port)) {
return 0;
}
else if (FIXNUM_P(port)) {
- snprintf(pbuf, len, "%ld", FIX2LONG(port));
+ snprintf(pbuf, pbuflen, "%ld", FIX2LONG(port));
#ifdef AI_NUMERICSERV
if (flags_ptr) *flags_ptr |= AI_NUMERICSERV;
#endif
return pbuf;
}
else {
- char *serv;
+ const char *serv;
+ size_t len;
- SafeStringValue(port);
- serv = RSTRING_PTR(port);
- if (strlen(serv) >= len) {
+ StringValueCStr(port);
+ RSTRING_GETMEM(port, serv, len);
+ if (len >= pbuflen) {
rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
- strlen(serv));
+ len);
}
- strcpy(pbuf, serv);
+ memcpy(pbuf, serv, len);
+ pbuf[len] = '\0';
return pbuf;
}
}
-struct addrinfo*
+static int
+rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
+ const struct addrinfo *hints, struct rb_addrinfo **res)
+{
+ int error, res_allocated = 0, _additional_flags = 0;
+ long i, len;
+ struct addrinfo *ai, *ai_tail = NULL;
+ char *hostp;
+ char _hbuf[NI_MAXHOST];
+ VALUE ip_addresses_array, ip_address;
+
+ ip_addresses_array = rb_fiber_scheduler_address_resolve(scheduler, host);
+
+ if (ip_addresses_array == Qundef) {
+ // Returns EAI_FAIL if the scheduler hook is not implemented:
+ return EAI_FAIL;
+ } else if (ip_addresses_array == Qnil) {
+ len = 0;
+ } else {
+ len = RARRAY_LEN(ip_addresses_array);
+ }
+
+ for(i=0; i<len; i++) {
+ ip_address = rb_ary_entry(ip_addresses_array, i);
+ hostp = host_str(ip_address, _hbuf, sizeof(_hbuf), &_additional_flags);
+ error = numeric_getaddrinfo(hostp, service, hints, &ai);
+ if (error == 0) {
+ if (!res_allocated) {
+ res_allocated = 1;
+ *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
+ (*res)->allocated_by_malloc = 1;
+ (*res)->ai = ai;
+ ai_tail = ai;
+ } else {
+ while (ai_tail->ai_next) {
+ ai_tail = ai_tail->ai_next;
+ }
+ ai_tail->ai_next = ai;
+ ai_tail = ai;
+ }
+ }
+ }
+
+ if (res_allocated) { // At least one valid result.
+ return 0;
+ } else {
+ return EAI_NONAME;
+ }
+}
+
+struct rb_addrinfo*
rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
{
- struct addrinfo* res = NULL;
+ struct rb_addrinfo* res = NULL;
+ struct addrinfo *ai;
char *hostp, *portp;
- int error;
+ int error = 0;
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int additional_flags = 0;
@@ -352,11 +528,47 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
- hints->ai_socktype = SOCK_DGRAM;
+ hints->ai_socktype = SOCK_DGRAM;
}
hints->ai_flags |= additional_flags;
- error = rb_getaddrinfo(hostp, portp, hints, &res);
+ error = numeric_getaddrinfo(hostp, portp, hints, &ai);
+ if (error == 0) {
+ res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
+ res->allocated_by_malloc = 1;
+ res->ai = ai;
+ } else {
+ VALUE scheduler = rb_fiber_scheduler_current();
+ int resolved = 0;
+
+ if (scheduler != Qnil && hostp && !(hints->ai_flags & AI_NUMERICHOST)) {
+ error = rb_scheduler_getaddrinfo(scheduler, host, portp, hints, &res);
+
+ if (error != EAI_FAIL) {
+ resolved = 1;
+ }
+ }
+
+ if (!resolved) {
+#ifdef GETADDRINFO_EMU
+ error = getaddrinfo(hostp, portp, hints, &ai);
+#else
+ struct getaddrinfo_arg arg;
+ MEMZERO(&arg, struct getaddrinfo_arg, 1);
+ arg.node = hostp;
+ arg.service = portp;
+ arg.hints = hints;
+ arg.res = &ai;
+ error = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
+#endif
+ if (error == 0) {
+ res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
+ res->allocated_by_malloc = 0;
+ res->ai = ai;
+ }
+ }
+ }
+
if (error) {
if (hostp && hostp[strlen(hostp)-1] == '\n') {
rb_raise(rb_eSocket, "newline at the end of hostname");
@@ -367,20 +579,33 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
return res;
}
-struct addrinfo*
-rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
+int
+rsock_fd_family(int fd)
+{
+ struct sockaddr sa = { 0 };
+ socklen_t sa_len = sizeof(sa);
+
+ if (fd < 0 || getsockname(fd, &sa, &sa_len) != 0 ||
+ (size_t)sa_len < offsetof(struct sockaddr, sa_family) + sizeof(sa.sa_family)) {
+ return AF_UNSPEC;
+ }
+ return sa.sa_family;
+}
+
+struct rb_addrinfo*
+rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
{
struct addrinfo hints;
MEMZERO(&hints, struct addrinfo, 1);
- hints.ai_family = AF_UNSPEC;
+ hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_flags = flags;
return rsock_getaddrinfo(host, port, &hints, 1);
}
VALUE
-rsock_ipaddr(struct sockaddr *sockaddr, int norevlookup)
+rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
{
VALUE family, port, addr1, addr2;
VALUE ary;
@@ -399,13 +624,13 @@ rsock_ipaddr(struct sockaddr *sockaddr, int norevlookup)
addr1 = Qnil;
if (!norevlookup) {
- error = rb_getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
+ error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
NULL, 0, 0);
if (! error) {
addr1 = rb_str_new2(hbuf);
}
}
- error = rb_getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
+ error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
@@ -421,16 +646,21 @@ rsock_ipaddr(struct sockaddr *sockaddr, int norevlookup)
}
#ifdef HAVE_SYS_UN_H
-VALUE
-rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len)
+static long
+unixsocket_len(const struct sockaddr_un *su, socklen_t socklen)
{
- char *s, *e;
- s = sockaddr->sun_path;
- e = (char *)sockaddr + len;
+ const char *s = su->sun_path, *e = (const char*)su + socklen;
while (s < e && *(e-1) == '\0')
e--;
- if (s <= e)
- return rb_str_new(s, e-s);
+ return e - s;
+}
+
+VALUE
+rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len)
+{
+ long n = unixsocket_len(sockaddr, len);
+ if (n >= 0)
+ return rb_str_new(sockaddr->sun_path, n);
else
return rb_str_new2("");
}
@@ -441,20 +671,44 @@ rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len)
return rb_assoc_new(rb_str_new2("AF_UNIX"),
rsock_unixpath_str(sockaddr, len));
}
+
+socklen_t
+rsock_unix_sockaddr_len(VALUE path)
+{
+#ifdef __linux__
+ if (RSTRING_LEN(path) == 0) {
+ /* autobind; see unix(7) for details. */
+ return (socklen_t) sizeof(sa_family_t);
+ }
+ else if (RSTRING_PTR(path)[0] == '\0') {
+ /* abstract namespace; see unix(7) for details. */
+ if (SOCKLEN_MAX - offsetof(struct sockaddr_un, sun_path) < (size_t)RSTRING_LEN(path))
+ rb_raise(rb_eArgError, "Linux abstract socket too long");
+ return (socklen_t) offsetof(struct sockaddr_un, sun_path) +
+ RSTRING_SOCKLEN(path);
+ }
+ else {
+#endif
+ return (socklen_t) sizeof(struct sockaddr_un);
+#ifdef __linux__
+ }
+#endif
+}
#endif
struct hostent_arg {
VALUE host;
- struct addrinfo* addr;
- VALUE (*ipaddr)(struct sockaddr*, size_t);
+ struct rb_addrinfo* addr;
+ VALUE (*ipaddr)(struct sockaddr*, socklen_t);
};
static VALUE
-make_hostent_internal(struct hostent_arg *arg)
+make_hostent_internal(VALUE v)
{
+ struct hostent_arg *arg = (void *)v;
VALUE host = arg->host;
- struct addrinfo* addr = arg->addr;
- VALUE (*ipaddr)(struct sockaddr*, size_t) = arg->ipaddr;
+ struct addrinfo* addr = arg->addr->ai;
+ VALUE (*ipaddr)(struct sockaddr*, socklen_t) = arg->ipaddr;
struct addrinfo *ai;
struct hostent *h;
@@ -472,7 +726,8 @@ make_hostent_internal(struct hostent_arg *arg)
}
rb_ary_push(ary, rb_str_new2(hostp));
- if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) {
+ if (addr->ai_canonname && strlen(addr->ai_canonname) < NI_MAXHOST &&
+ (h = gethostbyname(addr->ai_canonname))) {
names = rb_ary_new();
if (h->h_aliases != NULL) {
for (pch = h->h_aliases; *pch; pch++) {
@@ -493,14 +748,15 @@ make_hostent_internal(struct hostent_arg *arg)
}
VALUE
-rsock_freeaddrinfo(struct addrinfo *addr)
+rsock_freeaddrinfo(VALUE arg)
{
- freeaddrinfo(addr);
+ struct rb_addrinfo *addr = (struct rb_addrinfo *)arg;
+ rb_freeaddrinfo(addr);
return Qnil;
}
VALUE
-rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, size_t))
+rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t))
{
struct hostent_arg arg;
@@ -518,17 +774,15 @@ typedef struct {
int socktype;
int protocol;
socklen_t sockaddr_len;
- struct sockaddr_storage addr;
+ union_sockaddr addr;
} rb_addrinfo_t;
static void
addrinfo_mark(void *ptr)
{
rb_addrinfo_t *rai = ptr;
- if (rai) {
- rb_gc_mark(rai->inspectname);
- rb_gc_mark(rai->canonname);
- }
+ rb_gc_mark(rai->inspectname);
+ rb_gc_mark(rai->canonname);
}
#define addrinfo_free RUBY_TYPED_DEFAULT_FREE
@@ -536,7 +790,7 @@ addrinfo_mark(void *ptr)
static size_t
addrinfo_memsize(const void *ptr)
{
- return ptr ? sizeof(rb_addrinfo_t) : 0;
+ return sizeof(rb_addrinfo_t);
}
static const rb_data_type_t addrinfo_type = {
@@ -570,10 +824,9 @@ get_addrinfo(VALUE self)
static rb_addrinfo_t *
-alloc_addrinfo()
+alloc_addrinfo(void)
{
- rb_addrinfo_t *rai = ALLOC(rb_addrinfo_t);
- memset(rai, 0, sizeof(rb_addrinfo_t));
+ rb_addrinfo_t *rai = ZALLOC(rb_addrinfo_t);
rai->inspectname = Qnil;
rai->canonname = Qnil;
return rai;
@@ -610,12 +863,13 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
return a;
}
-static struct addrinfo *
+static struct rb_addrinfo *
call_getaddrinfo(VALUE node, VALUE service,
VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
- int socktype_hack)
+ int socktype_hack, VALUE timeout)
{
- struct addrinfo hints, *res;
+ struct addrinfo hints;
+ struct rb_addrinfo *res;
MEMZERO(&hints, struct addrinfo, 1);
hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
@@ -629,6 +883,7 @@ call_getaddrinfo(VALUE node, VALUE service,
if (!NIL_P(flags)) {
hints.ai_flags = NUM2INT(flags);
}
+
res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
if (res == NULL)
@@ -643,21 +898,21 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
VALUE inspectnode, VALUE inspectservice)
{
- struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1);
+ struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1, Qnil);
VALUE canonname;
- VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res);
+ VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res->ai);
canonname = Qnil;
- if (res->ai_canonname) {
- canonname = rb_tainted_str_new_cstr(res->ai_canonname);
+ if (res->ai->ai_canonname) {
+ canonname = rb_str_new_cstr(res->ai->ai_canonname);
OBJ_FREEZE(canonname);
}
- init_addrinfo(rai, res->ai_addr, res->ai_addrlen,
+ init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
canonname, inspectname);
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
}
static VALUE
@@ -699,8 +954,6 @@ make_inspectname(VALUE node, VALUE service, struct addrinfo *res)
rb_str_catf(inspectname, ":%d", FIX2INT(service));
}
if (!NIL_P(inspectname)) {
- OBJ_INFECT(inspectname, node);
- OBJ_INFECT(inspectname, service);
OBJ_FREEZE(inspectname);
}
return inspectname;
@@ -713,42 +966,43 @@ addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype,
VALUE canonname;
VALUE inspectname;
- struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
+ struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0, Qnil);
- inspectname = make_inspectname(node, service, res);
+ inspectname = make_inspectname(node, service, res->ai);
canonname = Qnil;
- if (res->ai_canonname) {
- canonname = rb_tainted_str_new_cstr(res->ai_canonname);
+ if (res->ai->ai_canonname) {
+ canonname = rb_str_new_cstr(res->ai->ai_canonname);
OBJ_FREEZE(canonname);
}
- ret = rsock_addrinfo_new(res->ai_addr, res->ai_addrlen,
- res->ai_family, res->ai_socktype, res->ai_protocol,
+ ret = rsock_addrinfo_new(res->ai->ai_addr, res->ai->ai_addrlen,
+ res->ai->ai_family, res->ai->ai_socktype,
+ res->ai->ai_protocol,
canonname, inspectname);
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
return ret;
}
static VALUE
-addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags)
+addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags, VALUE timeout)
{
VALUE ret;
struct addrinfo *r;
VALUE inspectname;
- struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0);
+ struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0, timeout);
- inspectname = make_inspectname(node, service, res);
+ inspectname = make_inspectname(node, service, res->ai);
ret = rb_ary_new();
- for (r = res; r; r = r->ai_next) {
+ for (r = res->ai; r; r = r->ai_next) {
VALUE addr;
VALUE canonname = Qnil;
if (r->ai_canonname) {
- canonname = rb_tainted_str_new_cstr(r->ai_canonname);
+ canonname = rb_str_new_cstr(r->ai_canonname);
OBJ_FREEZE(canonname);
}
@@ -759,7 +1013,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE
rb_ary_push(ret, addr);
}
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
return ret;
}
@@ -769,6 +1023,7 @@ static void
init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
{
struct sockaddr_un un;
+ socklen_t len;
StringValue(path);
@@ -777,14 +1032,19 @@ init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
"too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)RSTRING_LEN(path), sizeof(un.sun_path));
- MEMZERO(&un, struct sockaddr_un, 1);
-
- un.sun_family = AF_UNIX;
+ INIT_SOCKADDR_UN(&un, sizeof(struct sockaddr_un));
memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
- init_addrinfo(rai, (struct sockaddr *)&un, (socklen_t)sizeof(un),
+ len = rsock_unix_sockaddr_len(path);
+ init_addrinfo(rai, (struct sockaddr *)&un, len,
PF_UNIX, socktype, 0, Qnil, Qnil);
}
+
+static long
+rai_unixsocket_len(const rb_addrinfo_t *rai)
+{
+ return unixsocket_len(&rai->addr.un, rai->sockaddr_len);
+}
#endif
/*
@@ -904,7 +1164,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
else {
StringValue(sockaddr_arg);
sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
- sockaddr_len = RSTRING_LENINT(sockaddr_arg);
+ sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
i_pfamily, i_socktype, i_protocol,
canonname, inspectname);
@@ -914,52 +1174,80 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
}
static int
-get_afamily(struct sockaddr *addr, socklen_t len)
+get_afamily(const struct sockaddr *addr, socklen_t len)
{
- if ((socklen_t)((char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr) <= len)
+ if ((socklen_t)((const char*)&addr->sa_family + sizeof(addr->sa_family) - (char*)addr) <= len)
return addr->sa_family;
else
return AF_UNSPEC;
}
static int
-ai_get_afamily(rb_addrinfo_t *rai)
+ai_get_afamily(const rb_addrinfo_t *rai)
{
- return get_afamily((struct sockaddr *)&rai->addr, rai->sockaddr_len);
+ return get_afamily(&rai->addr.addr, rai->sockaddr_len);
}
static VALUE
inspect_sockaddr(VALUE addrinfo, VALUE ret)
{
rb_addrinfo_t *rai = get_addrinfo(addrinfo);
+ union_sockaddr *sockaddr = &rai->addr;
+ socklen_t socklen = rai->sockaddr_len;
+ return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret);
+}
- if (rai->sockaddr_len == 0) {
+VALUE
+rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
+{
+ union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg;
+ if (socklen == 0) {
rb_str_cat2(ret, "empty-sockaddr");
}
- else if ((long)rai->sockaddr_len < ((char*)&rai->addr.ss_family + sizeof(rai->addr.ss_family)) - (char*)&rai->addr)
+ else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr)
rb_str_cat2(ret, "too-short-sockaddr");
else {
- switch (rai->addr.ss_family) {
+ switch (sockaddr->addr.sa_family) {
+ case AF_UNSPEC:
+ {
+ rb_str_cat2(ret, "UNSPEC");
+ break;
+ }
+
case AF_INET:
{
struct sockaddr_in *addr;
int port;
- if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in)) {
- rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
- }
- else {
- addr = (struct sockaddr_in *)&rai->addr;
- rb_str_catf(ret, "%d.%d.%d.%d",
- ((unsigned char*)&addr->sin_addr)[0],
- ((unsigned char*)&addr->sin_addr)[1],
- ((unsigned char*)&addr->sin_addr)[2],
- ((unsigned char*)&addr->sin_addr)[3]);
- port = ntohs(addr->sin_port);
- if (port)
- rb_str_catf(ret, ":%d", port);
- if ((socklen_t)sizeof(struct sockaddr_in) < rai->sockaddr_len)
- rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in)));
- }
+ addr = &sockaddr->in;
+ if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+0+1) <= socklen)
+ rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
+ else
+ rb_str_cat2(ret, "?");
+ if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+1+1) <= socklen)
+ rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
+ else
+ rb_str_cat2(ret, ".?");
+ if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+2+1) <= socklen)
+ rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]);
+ else
+ rb_str_cat2(ret, ".?");
+ if ((socklen_t)(((char*)&addr->sin_addr)-(char*)addr+3+1) <= socklen)
+ rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]);
+ else
+ rb_str_cat2(ret, ".?");
+
+ if ((socklen_t)(((char*)&addr->sin_port)-(char*)addr+(int)sizeof(addr->sin_port)) < socklen) {
+ port = ntohs(addr->sin_port);
+ if (port)
+ rb_str_catf(ret, ":%d", port);
+ }
+ else {
+ rb_str_cat2(ret, ":?");
+ }
+ if ((socklen_t)sizeof(struct sockaddr_in) != socklen)
+ rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)",
+ (int)socklen,
+ (int)sizeof(struct sockaddr_in));
break;
}
@@ -970,16 +1258,16 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
char hbuf[1024];
int port;
int error;
- if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in6)) {
- rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
+ if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
+ rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
}
else {
- addr = (struct sockaddr_in6 *)&rai->addr;
+ addr = &sockaddr->in6;
/* use getnameinfo for scope_id.
* RFC 4007: IPv6 Scoped Address Architecture
* draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
*/
- error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
+ error = getnameinfo(&sockaddr->addr, socklen,
hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
@@ -992,8 +1280,8 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
port = ntohs(addr->sin6_port);
rb_str_catf(ret, "[%s]:%d", hbuf, port);
}
- if ((socklen_t)sizeof(struct sockaddr_in6) < rai->sockaddr_len)
- rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
+ if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
+ rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
}
break;
}
@@ -1002,18 +1290,17 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
#ifdef HAVE_SYS_UN_H
case AF_UNIX:
{
- struct sockaddr_un *addr = (struct sockaddr_un *)&rai->addr;
+ struct sockaddr_un *addr = &sockaddr->un;
char *p, *s, *e;
+ long len = unixsocket_len(addr, socklen);
s = addr->sun_path;
- e = (char*)addr + rai->sockaddr_len;
- while (s < e && *(e-1) == '\0')
- e--;
- if (e < s)
+ if (len < 0)
rb_str_cat2(ret, "too-short-AF_UNIX-sockaddr");
- else if (s == e)
+ else if (len == 0)
rb_str_cat2(ret, "empty-path-AF_UNIX-sockaddr");
else {
int printable_only = 1;
+ e = s + len;
p = s;
while (p < e) {
printable_only = printable_only && ISPRINT(*p) && !ISSPACE(*p);
@@ -1021,27 +1308,170 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
}
if (printable_only) { /* only printable, no space */
if (s[0] != '/') /* relative path */
- rb_str_cat2(ret, "AF_UNIX ");
+ rb_str_cat2(ret, "UNIX ");
rb_str_cat(ret, s, p - s);
}
else {
- rb_str_cat2(ret, "AF_UNIX");
+ rb_str_cat2(ret, "UNIX");
while (s < e)
rb_str_catf(ret, ":%02x", (unsigned char)*s++);
}
- if (addr->sun_path + sizeof(addr->sun_path) < (char*)&rai->addr + rai->sockaddr_len)
- rb_str_catf(ret, "(sockaddr %d bytes too long)",
- (int)(rai->sockaddr_len - (addr->sun_path + sizeof(addr->sun_path) - (char*)&rai->addr)));
}
break;
}
#endif
+#if defined(AF_PACKET) && defined(__linux__)
+ /* GNU/Linux */
+ case AF_PACKET:
+ {
+ struct sockaddr_ll *addr;
+ const char *sep = "[";
+#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
+
+ addr = (struct sockaddr_ll *)sockaddr;
+
+ rb_str_cat2(ret, "PACKET");
+
+ if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= (size_t)socklen) {
+ CATSEP;
+ rb_str_catf(ret, "protocol=%d", ntohs(addr->sll_protocol));
+ }
+ if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= (size_t)socklen) {
+ char buf[IFNAMSIZ];
+ CATSEP;
+ if (if_indextoname(addr->sll_ifindex, buf) == NULL)
+ rb_str_catf(ret, "ifindex=%d", addr->sll_ifindex);
+ else
+ rb_str_catf(ret, "%s", buf);
+ }
+ if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= (size_t)socklen) {
+ CATSEP;
+ rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
+ }
+ if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= (size_t)socklen) {
+ CATSEP;
+ if (addr->sll_pkttype == PACKET_HOST)
+ rb_str_cat2(ret, "HOST");
+ else if (addr->sll_pkttype == PACKET_BROADCAST)
+ rb_str_cat2(ret, "BROADCAST");
+ else if (addr->sll_pkttype == PACKET_MULTICAST)
+ rb_str_cat2(ret, "MULTICAST");
+ else if (addr->sll_pkttype == PACKET_OTHERHOST)
+ rb_str_cat2(ret, "OTHERHOST");
+ else if (addr->sll_pkttype == PACKET_OUTGOING)
+ rb_str_cat2(ret, "OUTGOING");
+ else
+ rb_str_catf(ret, "pkttype=%d", addr->sll_pkttype);
+ }
+ if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) {
+ CATSEP;
+ if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= (size_t)socklen) {
+ rb_str_catf(ret, "halen=%d", addr->sll_halen);
+ }
+ }
+ if (offsetof(struct sockaddr_ll, sll_addr) < (size_t)socklen) {
+ socklen_t len, i;
+ CATSEP;
+ rb_str_cat2(ret, "hwaddr");
+ len = addr->sll_halen;
+ if ((size_t)socklen < offsetof(struct sockaddr_ll, sll_addr) + len)
+ len = socklen - offsetof(struct sockaddr_ll, sll_addr);
+ for (i = 0; i < len; i++) {
+ rb_str_cat2(ret, i == 0 ? "=" : ":");
+ rb_str_catf(ret, "%02x", addr->sll_addr[i]);
+ }
+ }
+
+ if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) ||
+ (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) {
+ CATSEP;
+ rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
+ (int)socklen, (int)sizeof(struct sockaddr_ll));
+ }
+
+ rb_str_cat2(ret, "]");
+#undef CATSEP
+
+ break;
+ }
+#endif
+
+#if defined(AF_LINK) && defined(HAVE_TYPE_STRUCT_SOCKADDR_DL)
+ /* AF_LINK is defined in 4.4BSD derivations since Net2.
+ link_ntoa is also defined at Net2.
+ However Debian GNU/kFreeBSD defines AF_LINK but
+ don't have link_ntoa. */
+ case AF_LINK:
+ {
+ /*
+ * Simple implementation using link_ntoa():
+ * This doesn't work on Debian GNU/kFreeBSD 6.0.7 (squeeze).
+ * Also, the format is bit different.
+ *
+ * rb_str_catf(ret, "LINK %s", link_ntoa(&sockaddr->dl));
+ * break;
+ */
+ struct sockaddr_dl *addr = &sockaddr->dl;
+ char *np = NULL, *ap = NULL, *endp;
+ int nlen = 0, alen = 0;
+ int i, off;
+ const char *sep = "[";
+#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
+
+ rb_str_cat2(ret, "LINK");
+
+ endp = ((char *)addr) + socklen;
+
+ if (offsetof(struct sockaddr_dl, sdl_data) < socklen) {
+ np = addr->sdl_data;
+ nlen = addr->sdl_nlen;
+ if (endp - np < nlen)
+ nlen = (int)(endp - np);
+ }
+ off = addr->sdl_nlen;
+
+ if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) {
+ ap = addr->sdl_data + off;
+ alen = addr->sdl_alen;
+ if (endp - ap < alen)
+ alen = (int)(endp - ap);
+ }
+
+ CATSEP;
+ if (np)
+ rb_str_catf(ret, "%.*s", nlen, np);
+ else
+ rb_str_cat2(ret, "?");
+
+ if (ap && 0 < alen) {
+ CATSEP;
+ for (i = 0; i < alen; i++)
+ rb_str_catf(ret, "%s%02x", i == 0 ? "" : ":", (unsigned char)ap[i]);
+ }
+
+ if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) ||
+ socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) ||
+ socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) ||
+ /* longer length is possible behavior because struct sockaddr_dl has "minimum work area, can be larger" as the last field.
+ * cf. Net2:/usr/src/sys/net/if_dl.h. */
+ socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) {
+ CATSEP;
+ rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
+ (int)socklen, (int)sizeof(struct sockaddr_dl));
+ }
+
+ rb_str_cat2(ret, "]");
+#undef CATSEP
+ break;
+ }
+#endif
+
default:
{
- ID id = rsock_intern_family(rai->addr.ss_family);
+ ID id = rsock_intern_family(sockaddr->addr.sa_family);
if (id == 0)
- rb_str_catf(ret, "unknown address family %d", rai->addr.ss_family);
+ rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family);
else
rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
break;
@@ -1142,8 +1572,8 @@ addrinfo_inspect(VALUE self)
* Addrinfo.unix("/tmp/sock").inspect_sockaddr #=> "/tmp/sock"
*
*/
-static VALUE
-addrinfo_inspect_sockaddr(VALUE self)
+VALUE
+rsock_addrinfo_inspect_sockaddr(VALUE self)
{
return inspect_sockaddr(self, rb_str_new("", 0));
}
@@ -1196,13 +1626,7 @@ addrinfo_mdump(VALUE self)
#ifdef HAVE_SYS_UN_H
case AF_UNIX:
{
- struct sockaddr_un *su = (struct sockaddr_un *)&rai->addr;
- char *s, *e;
- s = su->sun_path;
- e = (char*)su + rai->sockaddr_len;
- while (s < e && *(e-1) == '\0')
- e--;
- sockaddr = rb_str_new(s, e-s);
+ sockaddr = rb_str_new(rai->addr.un.sun_path, rai_unixsocket_len(rai));
break;
}
#endif
@@ -1211,7 +1635,7 @@ addrinfo_mdump(VALUE self)
{
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int error;
- error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
@@ -1232,7 +1656,7 @@ addrinfo_mload(VALUE self, VALUE ary)
VALUE v;
VALUE canonname, inspectname;
int afamily, pfamily, socktype, protocol;
- struct sockaddr_storage ss;
+ union_sockaddr ss;
socklen_t len;
rb_addrinfo_t *rai;
@@ -1296,8 +1720,7 @@ addrinfo_mload(VALUE self, VALUE ary)
case AF_UNIX:
{
struct sockaddr_un uaddr;
- MEMZERO(&uaddr, struct sockaddr_un, 1);
- uaddr.sun_family = AF_UNIX;
+ INIT_SOCKADDR_UN(&uaddr, sizeof(struct sockaddr_un));
StringValue(v);
if (sizeof(uaddr.sun_path) < (size_t)RSTRING_LEN(v))
@@ -1314,23 +1737,24 @@ addrinfo_mload(VALUE self, VALUE ary)
default:
{
VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
- struct addrinfo *res;
+ struct rb_addrinfo *res;
int flags = AI_NUMERICHOST;
#ifdef AI_NUMERICSERV
flags |= AI_NUMERICSERV;
#endif
res = call_getaddrinfo(rb_ary_entry(pair, 0), rb_ary_entry(pair, 1),
INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol),
- INT2NUM(flags), 1);
+ INT2NUM(flags), 1, Qnil);
- len = res->ai_addrlen;
- memcpy(&ss, res->ai_addr, res->ai_addrlen);
+ len = res->ai->ai_addrlen;
+ memcpy(&ss, res->ai->ai_addr, res->ai->ai_addrlen);
+ rb_freeaddrinfo(res);
break;
}
}
DATA_PTR(self) = rai = alloc_addrinfo();
- init_addrinfo(rai, (struct sockaddr *)&ss, len,
+ init_addrinfo(rai, &ss.addr, len,
pfamily, socktype, protocol,
canonname, inspectname);
return self;
@@ -1417,7 +1841,6 @@ addrinfo_to_sockaddr(VALUE self)
rb_addrinfo_t *rai = get_addrinfo(self);
VALUE ret;
ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
- OBJ_INFECT(ret, self);
return ret;
}
@@ -1425,7 +1848,7 @@ addrinfo_to_sockaddr(VALUE self)
* call-seq:
* addrinfo.canonname => string or nil
*
- * returns the canonical name as an string.
+ * returns the canonical name as a string.
*
* nil is returned if no canonical name.
*
@@ -1558,7 +1981,7 @@ addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
if (rai->socktype == SOCK_DGRAM)
flags |= NI_DGRAM;
- error = getnameinfo((struct sockaddr *)&rai->addr, rai->sockaddr_len,
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
flags);
if (error) {
@@ -1649,14 +2072,14 @@ addrinfo_ip_port(VALUE self)
case AF_INET:
if (rai->sockaddr_len != sizeof(struct sockaddr_in))
rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
- port = ntohs(((struct sockaddr_in *)&rai->addr)->sin_port);
+ port = ntohs(rai->addr.in.sin_port);
break;
#ifdef AF_INET6
case AF_INET6:
if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
- port = ntohs(((struct sockaddr_in6 *)&rai->addr)->sin6_port);
+ port = ntohs(rai->addr.in6.sin6_port);
break;
#endif
@@ -1673,7 +2096,7 @@ extract_in_addr(VALUE self, uint32_t *addrp)
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
if (family != AF_INET) return 0;
- *addrp = ntohl(((struct sockaddr_in *)&rai->addr)->sin_addr.s_addr);
+ *addrp = ntohl(rai->addr.in.sin_addr.s_addr);
return 1;
}
@@ -1729,7 +2152,7 @@ extract_in6_addr(VALUE self)
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
if (family != AF_INET6) return NULL;
- return &((struct sockaddr_in6 *)&rai->addr)->sin6_addr;
+ return &rai->addr.in6.sin6_addr;
}
/*
@@ -1905,12 +2328,10 @@ addrinfo_ipv6_to_ipv4(VALUE self)
struct in6_addr *addr;
int family = ai_get_afamily(rai);
if (family != AF_INET6) return Qnil;
- addr = &((struct sockaddr_in6 *)&rai->addr)->sin6_addr;
+ addr = &rai->addr.in6.sin6_addr;
if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
struct sockaddr_in sin4;
- MEMZERO(&sin4, struct sockaddr_in, 1);
- sin4.sin_family = AF_INET;
- SET_SIN_LEN(&sin4, sizeof(sin4));
+ INIT_SOCKADDR_IN(&sin4, sizeof(sin4));
memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
PF_INET, rai->socktype, rai->protocol,
@@ -1938,28 +2359,27 @@ addrinfo_unix_path(VALUE self)
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
struct sockaddr_un *addr;
- char *s, *e;
+ long n;
if (family != AF_UNIX)
rb_raise(rb_eSocket, "need AF_UNIX address");
- addr = (struct sockaddr_un *)&rai->addr;
+ addr = &rai->addr.un;
- s = addr->sun_path;
- e = (char*)addr + rai->sockaddr_len;
- if (e < s)
+ n = rai_unixsocket_len(rai);
+ if (n < 0)
rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
- (size_t)rai->sockaddr_len, (size_t)(s - (char *)addr));
- if (addr->sun_path + sizeof(addr->sun_path) < e)
+ (size_t)rai->sockaddr_len, offsetof(struct sockaddr_un, sun_path));
+ if ((long)sizeof(addr->sun_path) < n)
rb_raise(rb_eSocket,
"too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
- (size_t)(e - addr->sun_path), sizeof(addr->sun_path));
- while (s < e && *(e-1) == '\0')
- e--;
- return rb_str_new(s, e-s);
+ (size_t)n, sizeof(addr->sun_path));
+ return rb_str_new(addr->sun_path, n);
}
#endif
+static ID id_timeout;
+
/*
* call-seq:
* Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags) => [addrinfo, ...]
@@ -2006,10 +2426,16 @@ addrinfo_unix_path(VALUE self)
static VALUE
addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
{
- VALUE node, service, family, socktype, protocol, flags;
+ VALUE node, service, family, socktype, protocol, flags, opts, timeout;
- rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags);
- return addrinfo_list_new(node, service, family, socktype, protocol, flags);
+ rb_scan_args(argc, argv, "24:", &node, &service, &family, &socktype,
+ &protocol, &flags, &opts);
+ rb_get_kwargs(opts, &id_timeout, 0, 1, &timeout);
+ if (timeout == Qundef) {
+ timeout = Qnil;
+ }
+
+ return addrinfo_list_new(node, service, family, socktype, protocol, flags, timeout);
}
/*
@@ -2097,7 +2523,6 @@ addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
addr = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(addr) = rai = alloc_addrinfo();
init_unix_addrinfo(rai, path, socktype);
- OBJ_INFECT(addr, path);
return addr;
}
@@ -2114,6 +2539,19 @@ rsock_sockaddr_string_value(volatile VALUE *v)
return *v;
}
+VALUE
+rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *rai_ret)
+{
+ VALUE val = *v;
+ *rai_ret = Qnil;
+ if (IS_ADDRINFO(val)) {
+ *v = addrinfo_to_sockaddr(val);
+ *rai_ret = val;
+ }
+ StringValue(*v);
+ return *v;
+}
+
char *
rsock_sockaddr_string_value_ptr(volatile VALUE *v)
{
@@ -2168,7 +2606,7 @@ rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
rb_raise(rb_eTypeError, "neither IO nor file descriptor");
}
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
}
/*
@@ -2181,11 +2619,13 @@ rsock_init_addrinfo(void)
* The Addrinfo class maps <tt>struct addrinfo</tt> to ruby. This
* structure identifies an Internet host and a service.
*/
- rb_cAddrinfo = rb_define_class("Addrinfo", rb_cData);
+ id_timeout = rb_intern("timeout");
+
+ rb_cAddrinfo = rb_define_class("Addrinfo", rb_cObject);
rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
rb_define_method(rb_cAddrinfo, "inspect", addrinfo_inspect, 0);
- rb_define_method(rb_cAddrinfo, "inspect_sockaddr", addrinfo_inspect_sockaddr, 0);
+ rb_define_method(rb_cAddrinfo, "inspect_sockaddr", rsock_addrinfo_inspect_sockaddr, 0);
rb_define_singleton_method(rb_cAddrinfo, "getaddrinfo", addrinfo_s_getaddrinfo, -1);
rb_define_singleton_method(rb_cAddrinfo, "ip", addrinfo_s_ip, 1);
rb_define_singleton_method(rb_cAddrinfo, "tcp", addrinfo_s_tcp, 2);
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 33cb51a5c9..c0d40addca 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -1,93 +1,168 @@
#ifndef RUBY_SOCKET_H
#define RUBY_SOCKET_H 1
-#include "ruby/ruby.h"
-#include "ruby/io.h"
-#include "ruby/thread.h"
-#include "ruby/util.h"
-#include "internal.h"
+#include "ruby/config.h"
+#include RUBY_EXTCONF_H
+
+#if defined(__sun) || defined(_AIX)
+/* (Recent?) Solaris' <nfs/nfs.h> have conflicting definition of T_DATA. Let
+ * us honour system definition by undefining ours.
+ *
+ * See also [ruby-core:4261]
+ */
+# include "ruby/ruby.h"
+# undef T_DATA
+#endif
+
+#include <errno.h>
#include <stdio.h>
+
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
#ifdef HAVE_SYS_UIO_H
-#include <sys/uio.h>
+# include <sys/uio.h>
#endif
#ifdef HAVE_XTI_H
-#include <xti.h>
+# include <xti.h>
#endif
-#ifndef _WIN32
-#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
-# include <net/socket.h>
+#ifdef _WIN32
+# if defined(_MSC_VER)
+# undef HAVE_TYPE_STRUCT_SOCKADDR_DL
+# endif
#else
-# include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_NETINET_IN_SYSTM_H
-# include <netinet/in_systm.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# ifdef HAVE_NETINET_IN_SYSTM_H
+# include <netinet/in_systm.h>
+# endif
+# ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+# endif
+# ifdef HAVE_NETINET_TCP_FSM_H
+# include <netinet/tcp_fsm.h>
+# endif
+# ifdef HAVE_NETINET_UDP_H
+# include <netinet/udp.h>
+# endif
+# ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+# endif
+# include <netdb.h>
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+# include <netpacket/packet.h>
+#endif
+
+#ifdef HAVE_NET_ETHERNET_H
+# include <net/ethernet.h>
#endif
-#ifdef HAVE_NETINET_TCP_H
-# include <netinet/tcp.h>
-#endif
-#ifdef HAVE_NETINET_UDP_H
-# include <netinet/udp.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-#include <netdb.h>
-#endif
-#include <errno.h>
+
#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
+# include <sys/un.h>
#endif
#if defined(HAVE_FCNTL)
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# endif
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+# endif
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# endif
+# ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+# endif
#endif
#ifdef HAVE_IFADDRS_H
-#include <ifaddrs.h>
+# ifdef __HAIKU__
+# define _BSD_SOURCE
+# endif
+# include <ifaddrs.h>
#endif
+
#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
+# include <sys/ioctl.h>
#endif
+
#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h>
+# include <sys/sockio.h>
#endif
+
#ifdef HAVE_NET_IF_H
-#include <net/if.h>
+# include <net/if.h>
#endif
#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
+# include <sys/param.h>
#endif
+
#ifdef HAVE_SYS_UCRED_H
-#include <sys/ucred.h>
+# include <sys/ucred.h>
#endif
+
#ifdef HAVE_UCRED_H
-#include <ucred.h>
+# include <ucred.h>
+#endif
+
+#ifdef HAVE_NET_IF_DL_H
+# include <net/if_dl.h>
+#endif
+
+#ifdef SOCKS5
+# include <socks.h>
+#endif
+
+#ifndef HAVE_GETADDRINFO
+# include "addrinfo.h"
+#endif
+
+#include "internal.h"
+#include "internal/array.h"
+#include "internal/error.h"
+#include "internal/gc.h"
+#include "internal/io.h"
+#include "internal/thread.h"
+#include "internal/vm.h"
+#include "ruby/io.h"
+#include "ruby/ruby.h"
+#include "ruby/thread.h"
+#include "ruby/util.h"
+#include "sockport.h"
+#include "ruby/fiber/scheduler.h"
+
+#ifndef HAVE_TYPE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifdef NEED_IF_INDEXTONAME_DECL
+char *if_indextoname(unsigned int, char *);
+#endif
+#ifdef NEED_IF_NAMETOINDEX_DECL
+unsigned int if_nametoindex(const char *);
+#endif
+
+#define SOCKLEN_MAX \
+ (0 < (socklen_t)-1 ? \
+ ~(socklen_t)0 : \
+ (((((socklen_t)1) << (sizeof(socklen_t) * CHAR_BIT - 2)) - 1) * 2 + 1))
+
+#ifndef RSTRING_SOCKLEN
+# define RSTRING_SOCKLEN (socklen_t)RSTRING_LENINT
#endif
#ifndef EWOULDBLOCK
-#define EWOULDBLOCK EAGAIN
+# define EWOULDBLOCK EAGAIN
#endif
/*
@@ -99,73 +174,80 @@
*/
#define pseudo_AF_FTIP pseudo_AF_RTIP
-#ifndef HAVE_GETADDRINFO
-#include "addrinfo.h"
-#endif
-#include "sockport.h"
#ifndef NI_MAXHOST
-# define NI_MAXHOST 1025
+# define NI_MAXHOST 1025
#endif
#ifndef NI_MAXSERV
-# define NI_MAXSERV 32
+# define NI_MAXSERV 32
#endif
#ifdef AF_INET6
-# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6)
+# define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6)
#else
-# define IS_IP_FAMILY(af) ((af) == AF_INET)
+# define IS_IP_FAMILY(af) ((af) == AF_INET)
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
-# define IN6_IS_ADDR_UNIQUE_LOCAL(a) (((a)->s6_addr[0] == 0xfc) || ((a)->s6_addr[0] == 0xfd))
+# define IN6_IS_ADDR_UNIQUE_LOCAL(a) (((a)->s6_addr[0] == 0xfc) || ((a)->s6_addr[0] == 0xfd))
#endif
-#ifndef HAVE_SOCKADDR_STORAGE
+#ifndef HAVE_TYPE_STRUCT_SOCKADDR_STORAGE
/*
* RFC 2553: protocol-independent placeholder for socket addresses
*/
-#define _SS_MAXSIZE 128
-#define _SS_ALIGNSIZE (sizeof(double))
-#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2)
-#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \
+# define _SS_MAXSIZE 128
+# define _SS_ALIGNSIZE (sizeof(double))
+# define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) * 2)
+# define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \
_SS_PAD1SIZE - _SS_ALIGNSIZE)
struct sockaddr_storage {
-#ifdef HAVE_SA_LEN
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
unsigned char ss_len; /* address length */
unsigned char ss_family; /* address family */
-#else
+# else
unsigned short ss_family;
-#endif
+# endif
char __ss_pad1[_SS_PAD1SIZE];
double __ss_align; /* force desired structure storage alignment */
char __ss_pad2[_SS_PAD2SIZE];
};
#endif
+typedef union {
+ struct sockaddr addr;
+ struct sockaddr_in in;
+#ifdef AF_INET6
+ struct sockaddr_in6 in6;
+#endif
+#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+#ifdef HAVE_TYPE_STRUCT_SOCKADDR_DL
+ struct sockaddr_dl dl; /* AF_LINK */
+#endif
+ struct sockaddr_storage storage;
+ char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */
+} union_sockaddr;
+
#ifdef __APPLE__
/*
* CMSG_ macros are broken on 64bit darwin, because __DARWIN_ALIGN
* aligns up to __darwin_size_t which is 64bit, but CMSG_DATA is
* 32bit-aligned.
*/
-#undef __DARWIN_ALIGNBYTES
-#define __DARWIN_ALIGNBYTES (sizeof(unsigned int) - 1)
+# undef __DARWIN_ALIGNBYTES
+# define __DARWIN_ALIGNBYTES (sizeof(unsigned int) - 1)
#endif
#if defined(_AIX)
-#ifndef CMSG_SPACE
-# define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
-#endif
-#ifndef CMSG_LEN
-# define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
-#endif
-#endif
-
-#ifdef __BEOS__
-#undef close
-#define close closesocket
+# ifndef CMSG_SPACE
+# define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
+# endif
+# ifndef CMSG_LEN
+# define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+# endif
#endif
#define INET_CLIENT 0
@@ -175,6 +257,12 @@ struct sockaddr_storage {
extern int rsock_do_not_reverse_lookup;
#define FMODE_NOREVLOOKUP 0x100
+/* common socket families only */
+#define FMODE_UNIX 0x00200000
+#define FMODE_INET 0x00400000
+#define FMODE_INET6 0x00800000
+#define FMODE_SOCK (FMODE_UNIX|FMODE_INET|FMODE_INET6)
+
extern VALUE rb_cBasicSocket;
extern VALUE rb_cIPSocket;
extern VALUE rb_cTCPSocket;
@@ -192,23 +280,23 @@ extern VALUE rb_eSocket;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
-#ifdef SOCKS5
-#include <socks.h>
-#else
+# ifndef SOCKS5
void SOCKSinit();
int Rconnect();
-#endif
+# endif
#endif
#include "constdefs.h"
-#define BLOCKING_REGION(func, arg) (long)rb_thread_blocking_region((func), (arg), RUBY_UBF_IO, 0)
#define BLOCKING_REGION_FD(func, arg) (long)rb_thread_io_blocking_region((func), (arg), (arg)->fd)
#define SockAddrStringValue(v) rsock_sockaddr_string_value(&(v))
#define SockAddrStringValuePtr(v) rsock_sockaddr_string_value_ptr(&(v))
+#define SockAddrStringValueWithAddrinfo(v, rai_ret) rsock_sockaddr_string_value_with_addrinfo(&(v), &(rai_ret))
VALUE rsock_sockaddr_string_value(volatile VALUE *);
char *rsock_sockaddr_string_value_ptr(volatile VALUE *);
+VALUE rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *ai_ret);
+
VALUE rb_check_sockaddr_string_type(VALUE);
NORETURN(void rsock_raise_socket_error(const char *, int));
@@ -220,32 +308,45 @@ int rsock_optname_arg(int family, int level, VALUE optname);
int rsock_cmsg_type_arg(int family, int level, VALUE type);
int rsock_shutdown_how_arg(VALUE how);
-int rsock_getfamily(int sockfd);
+int rsock_getfamily(rb_io_t *fptr);
-int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+struct rb_addrinfo {
+ struct addrinfo *ai;
+ int allocated_by_malloc;
+};
+void rb_freeaddrinfo(struct rb_addrinfo *ai);
+VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
-struct addrinfo *rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags);
-struct addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+int rsock_fd_family(int fd);
+struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags);
+struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
VALUE rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, int family, int socktype, int protocol, VALUE canonname, VALUE inspectname);
+VALUE rsock_addrinfo_inspect_sockaddr(VALUE rai);
-VALUE rsock_make_ipaddr(struct sockaddr *addr);
-VALUE rsock_ipaddr(struct sockaddr *sockaddr, int norevlookup);
-VALUE rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, size_t));
+VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen);
+VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup);
+VALUE rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t));
+VALUE rsock_inspect_sockaddr(struct sockaddr *addr, socklen_t socklen, VALUE ret);
+socklen_t rsock_sockaddr_len(struct sockaddr *addr);
+VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len);
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);
#ifdef HAVE_SYS_UN_H
VALUE rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len);
VALUE rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len);
+socklen_t rsock_unix_sockaddr_len(VALUE path);
#endif
int rsock_socket(int domain, int type, int proto);
+int rsock_detect_cloexec(int fd);
VALUE rsock_init_sock(VALUE sock, int fd);
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
-VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type);
+VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout);
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
struct rsock_send_arg {
@@ -266,34 +367,41 @@ enum sock_recv_type {
RECV_SOCKET /* Socket#recvfrom */
};
-VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
+VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+ VALUE ex, enum sock_recv_type from);
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
-int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
+int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout);
-VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
-VALUE rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len);
+VALUE rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len);
+VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
+ struct sockaddr *sockaddr, socklen_t *len);
VALUE rsock_sock_listen(VALUE sock, VALUE log);
VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data);
#if defined(HAVE_SENDMSG)
-VALUE rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock);
-VALUE rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock);
+VALUE rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags,
+ VALUE dest_sockaddr, VALUE controls);
+VALUE rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags,
+ VALUE dest_sockaddr, VALUE controls, VALUE ex);
#else
#define rsock_bsock_sendmsg rb_f_notimplement
#define rsock_bsock_sendmsg_nonblock rb_f_notimplement
#endif
+
#if defined(HAVE_RECVMSG)
-VALUE rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock);
-VALUE rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock);
+VALUE rsock_bsock_recvmsg(VALUE sock, VALUE dlen, VALUE clen, VALUE flags,
+ VALUE scm_rights);
+VALUE rsock_bsock_recvmsg_nonblock(VALUE sock, VALUE dlen, VALUE clen,
+ VALUE flags, VALUE scm_rights, VALUE ex);
ssize_t rsock_recvmsg(int socket, struct msghdr *message, int flags);
#else
#define rsock_bsock_recvmsg rb_f_notimplement
#define rsock_bsock_recvmsg_nonblock rb_f_notimplement
#endif
-#ifdef HAVE_ST_MSG_CONTROL
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
void rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p);
#endif
@@ -309,6 +417,46 @@ void rsock_init_socket_constants(void);
void rsock_init_ancdata(void);
void rsock_init_addrinfo(void);
void rsock_init_sockopt(void);
+void rsock_init_sockifaddr(void);
void rsock_init_socket_init(void);
+NORETURN(void rsock_syserr_fail_host_port(int err, const char *, VALUE, VALUE));
+NORETURN(void rsock_syserr_fail_path(int err, const char *, VALUE));
+NORETURN(void rsock_syserr_fail_sockaddr(int err, const char *mesg, struct sockaddr *addr, socklen_t len));
+NORETURN(void rsock_syserr_fail_raddrinfo(int err, const char *mesg, VALUE rai));
+NORETURN(void rsock_syserr_fail_raddrinfo_or_sockaddr(int err, const char *mesg, VALUE addr, VALUE rai));
+
+NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE));
+NORETURN(void rsock_sys_fail_path(const char *, VALUE));
+NORETURN(void rsock_sys_fail_sockaddr(const char *, struct sockaddr *addr, socklen_t len));
+NORETURN(void rsock_sys_fail_raddrinfo(const char *, VALUE rai));
+NORETURN(void rsock_sys_fail_raddrinfo_or_sockaddr(const char *, VALUE addr, VALUE rai));
+
+#if defined(__MINGW32__) || defined(_WIN32)
+#define RSOCK_WAIT_BEFORE_BLOCKING
+#endif
+
+/*
+ * some OSes may support MSG_DONTWAIT inconsistently depending on socket
+ * type, we only expect Linux to support it consistently for all socket types.
+ */
+#if defined(MSG_DONTWAIT) && defined(__linux__)
+# define MSG_DONTWAIT_RELIABLE 1
+#else
+# define MSG_DONTWAIT_RELIABLE 0
+#endif
+
+VALUE rsock_read_nonblock(VALUE sock, VALUE length, VALUE buf, VALUE ex);
+VALUE rsock_write_nonblock(VALUE sock, VALUE buf, VALUE ex);
+
+void rsock_make_fd_nonblock(int fd);
+
+#if !defined HAVE_INET_NTOP && ! defined _WIN32
+const char *inet_ntop(int, const void *, char *, size_t);
+#elif defined __MINGW32__
+# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
+#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90
+const char *WSAAPI inet_ntop(int, const void *, char *, size_t);
+#endif
+
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 09c22d6d69..ccf990d11f 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -10,6 +10,100 @@
#include "rubysocket.h"
+static VALUE sym_wait_writable;
+
+static VALUE sock_s_unpack_sockaddr_in(VALUE, VALUE);
+
+void
+rsock_sys_fail_host_port(const char *mesg, VALUE host, VALUE port)
+{
+ rsock_syserr_fail_host_port(errno, mesg, host, port);
+}
+
+void
+rsock_syserr_fail_host_port(int err, const char *mesg, VALUE host, VALUE port)
+{
+ VALUE message;
+
+ message = rb_sprintf("%s for %+"PRIsVALUE" port % "PRIsVALUE"",
+ mesg, host, port);
+
+ rb_syserr_fail_str(err, message);
+}
+
+void
+rsock_sys_fail_path(const char *mesg, VALUE path)
+{
+ rsock_syserr_fail_path(errno, mesg, path);
+}
+
+void
+rsock_syserr_fail_path(int err, const char *mesg, VALUE path)
+{
+ VALUE message;
+
+ if (RB_TYPE_P(path, T_STRING)) {
+ message = rb_sprintf("%s for % "PRIsVALUE"", mesg, path);
+ rb_syserr_fail_str(err, message);
+ }
+ else {
+ rb_syserr_fail(err, mesg);
+ }
+}
+
+void
+rsock_sys_fail_sockaddr(const char *mesg, struct sockaddr *addr, socklen_t len)
+{
+ rsock_syserr_fail_sockaddr(errno, mesg, addr, len);
+}
+
+void
+rsock_syserr_fail_sockaddr(int err, const char *mesg, struct sockaddr *addr, socklen_t len)
+{
+ VALUE rai;
+
+ rai = rsock_addrinfo_new(addr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
+
+ rsock_syserr_fail_raddrinfo(err, mesg, rai);
+}
+
+void
+rsock_sys_fail_raddrinfo(const char *mesg, VALUE rai)
+{
+ rsock_syserr_fail_raddrinfo(errno, mesg, rai);
+}
+
+void
+rsock_syserr_fail_raddrinfo(int err, const char *mesg, VALUE rai)
+{
+ VALUE str, message;
+
+ str = rsock_addrinfo_inspect_sockaddr(rai);
+ message = rb_sprintf("%s for %"PRIsVALUE"", mesg, str);
+
+ rb_syserr_fail_str(err, message);
+}
+
+void
+rsock_sys_fail_raddrinfo_or_sockaddr(const char *mesg, VALUE addr, VALUE rai)
+{
+ rsock_syserr_fail_raddrinfo_or_sockaddr(errno, mesg, addr, rai);
+}
+
+void
+rsock_syserr_fail_raddrinfo_or_sockaddr(int err, const char *mesg, VALUE addr, VALUE rai)
+{
+ if (NIL_P(rai)) {
+ StringValue(addr);
+
+ rsock_syserr_fail_sockaddr(err, mesg,
+ (struct sockaddr *)RSTRING_PTR(addr),
+ (socklen_t)RSTRING_LEN(addr)); /* overflow should be checked already */
+ }
+ else
+ rsock_syserr_fail_raddrinfo(err, mesg, rai);
+}
+
static void
setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv)
{
@@ -46,7 +140,6 @@ sock_initialize(int argc, VALUE *argv, VALUE sock)
if (NIL_P(protocol))
protocol = INT2FIX(0);
- rb_secure(3);
setup_domain_and_type(domain, &d, type, &t);
fd = rsock_socket(d, t, NUM2INT(protocol));
if (fd < 0) rb_sys_fail("socket(2)");
@@ -58,7 +151,7 @@ sock_initialize(int argc, VALUE *argv, VALUE sock)
static VALUE
io_call_close(VALUE io)
{
- return rb_funcall(io, rb_intern("close"), 0, 0);
+ return rb_funcallv(io, rb_intern("close"), 0, 0);
}
static VALUE
@@ -75,57 +168,47 @@ pair_yield(VALUE pair)
#endif
#if defined HAVE_SOCKETPAIR
-
static int
-rsock_socketpair0(int domain, int type, int protocol, int sv[2])
+rsock_socketpair0(int domain, int type, int protocol, int descriptors[2])
{
- int ret;
-
#ifdef SOCK_CLOEXEC
- static int try_sock_cloexec = 1;
- if (try_sock_cloexec) {
- ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
- if (ret == -1 && errno == EINVAL) {
- /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
- ret = socketpair(domain, type, protocol, sv);
- if (ret != -1) {
- /* The reason of EINVAL may be other than SOCK_CLOEXEC.
- * So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
- * Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
- */
- try_sock_cloexec = 0;
- }
- }
- }
- else {
- ret = socketpair(domain, type, protocol, sv);
- }
-#else
- ret = socketpair(domain, type, protocol, sv);
+ type |= SOCK_CLOEXEC;
#endif
- if (ret == -1) {
+#ifdef SOCK_NONBLOCK
+ type |= SOCK_NONBLOCK;
+#endif
+
+ int result = socketpair(domain, type, protocol, descriptors);
+
+ if (result == -1)
return -1;
- }
- rb_fd_fix_cloexec(sv[0]);
- rb_fd_fix_cloexec(sv[1]);
+#ifndef SOCK_CLOEXEC
+ rb_fd_fix_cloexec(descriptors[0]);
+ rb_fd_fix_cloexec(descriptors[1]);
+#endif
- return ret;
+#ifndef SOCK_NONBLOCK
+ rsock_make_fd_nonblock(descriptors[0]);
+ rsock_make_fd_nonblock(descriptors[1]);
+#endif
+
+ return result;
}
static int
-rsock_socketpair(int domain, int type, int protocol, int sv[2])
+rsock_socketpair(int domain, int type, int protocol, int descriptors[2])
{
- int ret;
+ int result;
+
+ result = rsock_socketpair0(domain, type, protocol, descriptors);
- ret = rsock_socketpair0(domain, type, protocol, sv);
- if (ret < 0 && (errno == EMFILE || errno == ENFILE)) {
- rb_gc();
- ret = rsock_socketpair0(domain, type, protocol, sv);
+ if (result < 0 && rb_gc_for_fd(errno)) {
+ result = rsock_socketpair0(domain, type, protocol, descriptors);
}
- return ret;
+ return result;
}
/*
@@ -142,6 +225,14 @@ rsock_socketpair(int domain, int type, int protocol, int sv[2])
* _protocol_ should be a protocol defined in the domain,
* defaults to 0 for the domain.
*
+ * s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
+ * s1.send "a", 0
+ * s1.send "b", 0
+ * s1.close
+ * p s2.recv(10) #=> "ab"
+ * p s2.recv(10) #=> ""
+ * p s2.recv(10) #=> ""
+ *
* s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
* s1.send "a", 0
* s1.send "b", 0
@@ -167,8 +258,6 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
if (ret < 0) {
rb_sys_fail("socketpair(2)");
}
- rb_fd_fix_cloexec(sp[0]);
- rb_fd_fix_cloexec(sp[1]);
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
@@ -184,7 +273,7 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * socket.connect(remote_sockaddr) => 0
+ * socket.connect(remote_sockaddr) => 0
*
* Requests a connection to be made on the given +remote_sockaddr+. Returns 0 if
* successful, otherwise an exception is raised.
@@ -193,14 +282,14 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
* * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
*
* === Example:
- * # Pull down Google's web page
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
- * socket.connect( sockaddr )
- * socket.write( "GET / HTTP/1.0\r\n\r\n" )
- * results = socket.read
+ * # Pull down Google's web page
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
+ * socket.connect( sockaddr )
+ * socket.write( "GET / HTTP/1.0\r\n\r\n" )
+ * results = socket.read
*
* === Unix-based Exceptions
* On unix-based systems the following system exceptions may be raised if
@@ -241,7 +330,7 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
* * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected
* * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket
* bound to the specified peer address
- * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
+ * * Errno::ETIMEDOUT - the attempt to connect timed out before a connection
* was made.
*
* On unix-based systems if the address family of the calling +socket+ is
@@ -282,7 +371,7 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
* * Errno::EHOSTUNREACH - no route to the network is present
* * Errno::ENOBUFS - no buffer space is available
* * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
- * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
+ * * Errno::ETIMEDOUT - the attempt to connect timed out before a connection
* was made.
* * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the
* connection cannot be completed immediately
@@ -296,78 +385,49 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
static VALUE
sock_connect(VALUE sock, VALUE addr)
{
+ VALUE rai;
rb_io_t *fptr;
int fd, n;
- SockAddrStringValue(addr);
+ SockAddrStringValueWithAddrinfo(addr, rai);
addr = rb_str_new4(addr);
GetOpenFile(sock, fptr);
fd = fptr->fd;
- n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr), 0);
+ n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0, NULL);
if (n < 0) {
- rb_sys_fail("connect(2)");
+ rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
}
return INT2FIX(n);
}
-/*
- * call-seq:
- * socket.connect_nonblock(remote_sockaddr) => 0
- *
- * Requests a connection to be made on the given +remote_sockaddr+ after
- * O_NONBLOCK is set for the underlying file descriptor.
- * Returns 0 if successful, otherwise an exception is raised.
- *
- * === Parameter
- * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
- *
- * === Example:
- * # Pull down Google's web page
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(80, 'www.google.com')
- * begin # emulate blocking connect
- * socket.connect_nonblock(sockaddr)
- * rescue IO::WaitWritable
- * IO.select(nil, [socket]) # wait 3-way handshake completion
- * begin
- * socket.connect_nonblock(sockaddr) # check connection failure
- * rescue Errno::EISCONN
- * end
- * end
- * socket.write("GET / HTTP/1.0\r\n\r\n")
- * results = socket.read
- *
- * Refer to Socket#connect for the exceptions that may be thrown if the call
- * to _connect_nonblock_ fails.
- *
- * Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
- * including Errno::EINPROGRESS.
- *
- * If the exception is Errno::EINPROGRESS,
- * it is extended by IO::WaitWritable.
- * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock.
- *
- * === See
- * * Socket#connect
- */
+/* :nodoc: */
static VALUE
-sock_connect_nonblock(VALUE sock, VALUE addr)
+sock_connect_nonblock(VALUE sock, VALUE addr, VALUE ex)
{
+ VALUE rai;
rb_io_t *fptr;
int n;
- SockAddrStringValue(addr);
+ SockAddrStringValueWithAddrinfo(addr, rai);
addr = rb_str_new4(addr);
GetOpenFile(sock, fptr);
rb_io_set_nonblock(fptr);
- n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr));
+ n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr));
if (n < 0) {
- if (errno == EINPROGRESS)
- rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block");
- rb_sys_fail("connect(2)");
+ int e = errno;
+ if (e == EINPROGRESS) {
+ if (ex == Qfalse) {
+ return sym_wait_writable;
+ }
+ rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "connect(2) would block");
+ }
+ if (e == EISCONN) {
+ if (ex == Qfalse) {
+ return INT2FIX(0);
+ }
+ }
+ rsock_syserr_fail_raddrinfo_or_sockaddr(e, "connect(2)", addr, rai);
}
return INT2FIX(n);
@@ -375,7 +435,7 @@ sock_connect_nonblock(VALUE sock, VALUE addr)
/*
* call-seq:
- * socket.bind(local_sockaddr) => 0
+ * socket.bind(local_sockaddr) => 0
*
* Binds to the given local address.
*
@@ -383,18 +443,18 @@ sock_connect_nonblock(VALUE sock, VALUE addr)
* * +local_sockaddr+ - the +struct+ sockaddr contained in a string or an Addrinfo object
*
* === Example
- * require 'socket'
+ * require 'socket'
*
- * # use Addrinfo
- * socket = Socket.new(:INET, :STREAM, 0)
- * socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
- * p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>
+ * # use Addrinfo
+ * socket = Socket.new(:INET, :STREAM, 0)
+ * socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
+ * p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>
*
- * # use struct sockaddr
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.bind( sockaddr )
+ * # use struct sockaddr
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.bind( sockaddr )
*
* === Unix-based Exceptions
* On unix-based based systems the following system exceptions may be raised if
@@ -462,19 +522,20 @@ sock_connect_nonblock(VALUE sock, VALUE addr)
static VALUE
sock_bind(VALUE sock, VALUE addr)
{
+ VALUE rai;
rb_io_t *fptr;
- SockAddrStringValue(addr);
+ SockAddrStringValueWithAddrinfo(addr, rai);
GetOpenFile(sock, fptr);
- if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0)
- rb_sys_fail("bind(2)");
+ if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)) < 0)
+ rsock_sys_fail_raddrinfo_or_sockaddr("bind(2)", addr, rai);
return INT2FIX(0);
}
/*
* call-seq:
- * socket.listen( int ) => 0
+ * socket.listen( int ) => 0
*
* Listens for connections, using the specified +int+ as the backlog. A call
* to _listen_ only applies if the +socket+ is of type SOCK_STREAM or
@@ -484,18 +545,18 @@ sock_bind(VALUE sock, VALUE addr)
* * +backlog+ - the maximum length of the queue for pending connections.
*
* === Example 1
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.bind( sockaddr )
- * socket.listen( 5 )
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.bind( sockaddr )
+ * socket.listen( 5 )
*
* === Example 2 (listening on an arbitrary port, unix-based systems only):
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * socket.listen( 1 )
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * socket.listen( 1 )
*
* === Unix-based Exceptions
* On unix based systems the above will work because a new +sockaddr+ struct
@@ -548,7 +609,6 @@ rsock_sock_listen(VALUE sock, VALUE log)
rb_io_t *fptr;
int backlog;
- rb_secure(4);
backlog = NUM2INT(log);
GetOpenFile(sock, fptr);
if (listen(fptr->fd, backlog) < 0)
@@ -559,8 +619,8 @@ rsock_sock_listen(VALUE sock, VALUE log)
/*
* call-seq:
- * socket.recvfrom(maxlen) => [mesg, sender_addrinfo]
- * socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo]
+ * socket.recvfrom(maxlen) => [mesg, sender_addrinfo]
+ * socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo]
*
* Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more
* of the +MSG_+ options. The first element of the results, _mesg_, is the data
@@ -572,27 +632,27 @@ rsock_sock_listen(VALUE sock, VALUE log)
* * +flags+ - zero or more of the +MSG_+ options
*
* === Example
- * # In one file, start this first
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.bind( sockaddr )
- * socket.listen( 5 )
- * client, client_addrinfo = socket.accept
- * data = client.recvfrom( 20 )[0].chomp
- * puts "I only received 20 bytes '#{data}'"
- * sleep 1
- * socket.close
- *
- * # In another file, start this second
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.connect( sockaddr )
- * socket.puts "Watch this get cut short!"
- * socket.close
+ * # In one file, start this first
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.bind( sockaddr )
+ * socket.listen( 5 )
+ * client, client_addrinfo = socket.accept
+ * data = client.recvfrom( 20 )[0].chomp
+ * puts "I only received 20 bytes '#{data}'"
+ * sleep 1
+ * socket.close
+ *
+ * # In another file, start this second
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.connect( sockaddr )
+ * socket.puts "Watch this get cut short!"
+ * socket.close
*
* === Unix-based Exceptions
* On unix-based based systems the following system exceptions may be raised if the
@@ -668,72 +728,11 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock)
return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
}
-/*
- * call-seq:
- * socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
- * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_addrinfo_, contains protocol-specific address
- * information of the sender.
- *
- * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the maximum number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- * # In one file, start this first
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.bind(sockaddr)
- * socket.listen(5)
- * client, client_addrinfo = socket.accept
- * begin # emulate blocking recvfrom
- * pair = client.recvfrom_nonblock(20)
- * rescue IO::WaitReadable
- * IO.select([client])
- * retry
- * end
- * data = pair[0].chomp
- * puts "I only received 20 bytes '#{data}'"
- * sleep 1
- * socket.close
- *
- * # In another file, start this second
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.connect(sockaddr)
- * socket.puts "Watch this get cut short!"
- * socket.close
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
static VALUE
-sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+sock_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_SOCKET);
}
/*
@@ -751,114 +750,65 @@ sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
*
*/
static VALUE
-sock_accept(VALUE sock)
+sock_accept(VALUE server)
{
- rb_io_t *fptr;
- VALUE sock2;
- struct sockaddr_storage buf;
- socklen_t len = (socklen_t)sizeof buf;
+ union_sockaddr buffer;
+ socklen_t length = (socklen_t)sizeof(buffer);
- GetOpenFile(sock, fptr);
- sock2 = rsock_s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)&buf,&len);
+ VALUE peer = rsock_s_accept(rb_cSocket, server, &buffer.addr, &length);
- return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
+ return rb_assoc_new(peer, rsock_io_socket_addrinfo(peer, &buffer.addr, length));
}
-/*
- * call-seq:
- * socket.accept_nonblock => [client_socket, client_addrinfo]
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an array containing the accepted socket
- * for the incoming connection, _client_socket_,
- * and an Addrinfo, _client_addrinfo_.
- *
- * === Example
- * # In one script, start this first
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.bind(sockaddr)
- * socket.listen(5)
- * begin # emulate blocking accept
- * client_socket, client_addrinfo = socket.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([socket])
- * retry
- * end
- * puts "The client said, '#{client_socket.readline.chomp}'"
- * client_socket.puts "Hello from script one!"
- * socket.close
- *
- * # In another script, start this second
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- * sockaddr = Socket.sockaddr_in(2200, 'localhost')
- * socket.connect(sockaddr)
- * socket.puts "Hello from script 2."
- * puts "The server said, '#{socket.readline.chomp}'"
- * socket.close
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to _accept_nonblock_ fails.
- *
- * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * === See
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-sock_accept_nonblock(VALUE sock)
+sock_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
VALUE sock2;
- struct sockaddr_storage buf;
+ union_sockaddr buf;
+ struct sockaddr *addr = &buf.addr;
socklen_t len = (socklen_t)sizeof buf;
GetOpenFile(sock, fptr);
- sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len);
- return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
+ sock2 = rsock_s_accept_nonblock(rb_cSocket, ex, fptr, addr, &len);
+
+ if (SYMBOL_P(sock2)) /* :wait_readable */
+ return sock2;
+ return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}
/*
* call-seq:
- * socket.sysaccept => [client_socket_fd, client_addrinfo]
+ * socket.sysaccept => [client_socket_fd, client_addrinfo]
*
* Accepts an incoming connection returning an array containing the (integer)
* file descriptor for the incoming connection, _client_socket_fd_,
* and an Addrinfo, _client_addrinfo_.
*
* === Example
- * # In one script, start this first
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.bind( sockaddr )
- * socket.listen( 5 )
- * client_fd, client_addrinfo = socket.sysaccept
- * client_socket = Socket.for_fd( client_fd )
- * puts "The client said, '#{client_socket.readline.chomp}'"
- * client_socket.puts "Hello from script one!"
- * socket.close
- *
- * # In another script, start this second
- * require 'socket'
- * include Socket::Constants
- * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
- * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
- * socket.connect( sockaddr )
- * socket.puts "Hello from script 2."
- * puts "The server said, '#{socket.readline.chomp}'"
- * socket.close
+ * # In one script, start this first
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.bind( sockaddr )
+ * socket.listen( 5 )
+ * client_fd, client_addrinfo = socket.sysaccept
+ * client_socket = Socket.for_fd( client_fd )
+ * puts "The client said, '#{client_socket.readline.chomp}'"
+ * client_socket.puts "Hello from script one!"
+ * socket.close
+ *
+ * # In another script, start this second
+ * require 'socket'
+ * include Socket::Constants
+ * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
+ * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
+ * socket.connect( sockaddr )
+ * socket.puts "Hello from script 2."
+ * puts "The server said, '#{socket.readline.chomp}'"
+ * socket.close
*
* Refer to Socket#accept for the exceptions that may be thrown if the call
* to _sysaccept_ fails.
@@ -867,17 +817,14 @@ sock_accept_nonblock(VALUE sock)
* * Socket#accept
*/
static VALUE
-sock_sysaccept(VALUE sock)
+sock_sysaccept(VALUE server)
{
- rb_io_t *fptr;
- VALUE sock2;
- struct sockaddr_storage buf;
- socklen_t len = (socklen_t)sizeof buf;
+ union_sockaddr buffer;
+ socklen_t length = (socklen_t)sizeof(buffer);
- GetOpenFile(sock, fptr);
- sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len);
+ VALUE peer = rsock_s_accept(0, server, &buffer.addr, &length);
- return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
+ return rb_assoc_new(peer, rsock_io_socket_addrinfo(peer, &buffer.addr, length));
}
#ifdef HAVE_GETHOSTNAME
@@ -895,17 +842,35 @@ sock_sysaccept(VALUE sock)
static VALUE
sock_gethostname(VALUE obj)
{
-#ifndef HOST_NAME_MAX
-# define HOST_NAME_MAX 1024
+#if defined(NI_MAXHOST)
+# define RUBY_MAX_HOST_NAME_LEN NI_MAXHOST
+#elif defined(HOST_NAME_MAX)
+# define RUBY_MAX_HOST_NAME_LEN HOST_NAME_MAX
+#else
+# define RUBY_MAX_HOST_NAME_LEN 1024
#endif
- char buf[HOST_NAME_MAX+1];
- rb_secure(3);
- if (gethostname(buf, (int)sizeof buf - 1) < 0)
- rb_sys_fail("gethostname");
-
- buf[sizeof buf - 1] = '\0';
- return rb_str_new2(buf);
+ long len = RUBY_MAX_HOST_NAME_LEN;
+ VALUE name;
+
+ name = rb_str_new(0, len);
+ while (gethostname(RSTRING_PTR(name), len) < 0) {
+ int e = errno;
+ switch (e) {
+ case ENAMETOOLONG:
+#ifdef __linux__
+ case EINVAL:
+ /* glibc before version 2.1 uses EINVAL instead of ENAMETOOLONG */
+#endif
+ break;
+ default:
+ rb_syserr_fail(e, "gethostname(3)");
+ }
+ rb_str_modify_expand(name, len);
+ len += len;
+ }
+ rb_str_resize(name, strlen(RSTRING_PTR(name)));
+ return name;
}
#else
#ifdef HAVE_UNAME
@@ -917,7 +882,6 @@ sock_gethostname(VALUE obj)
{
struct utsname un;
- rb_secure(3);
uname(&un);
return rb_str_new2(un.nodename);
}
@@ -927,7 +891,7 @@ sock_gethostname(VALUE obj)
#endif
static VALUE
-make_addrinfo(struct addrinfo *res0, int norevlookup)
+make_addrinfo(struct rb_addrinfo *res0, int norevlookup)
{
VALUE base, ary;
struct addrinfo *res;
@@ -936,10 +900,10 @@ make_addrinfo(struct addrinfo *res0, int norevlookup)
rb_raise(rb_eSocket, "host not found");
}
base = rb_ary_new();
- for (res = res0; res; res = res->ai_next) {
- ary = rsock_ipaddr(res->ai_addr, norevlookup);
+ for (res = res0->ai; res; res = res->ai_next) {
+ ary = rsock_ipaddr(res->ai_addr, res->ai_addrlen, norevlookup);
if (res->ai_canonname) {
- RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
+ RARRAY_ASET(ary, 2, rb_str_new2(res->ai_canonname));
}
rb_ary_push(ary, INT2FIX(res->ai_family));
rb_ary_push(ary, INT2FIX(res->ai_socktype));
@@ -950,19 +914,19 @@ make_addrinfo(struct addrinfo *res0, int norevlookup)
}
static VALUE
-sock_sockaddr(struct sockaddr *addr, size_t len)
+sock_sockaddr(struct sockaddr *addr, socklen_t len)
{
char *ptr;
switch (addr->sa_family) {
case AF_INET:
ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
- len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
+ len = (socklen_t)sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
break;
#ifdef AF_INET6
case AF_INET6:
ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
- len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
+ len = (socklen_t)sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
break;
#endif
default:
@@ -976,7 +940,18 @@ sock_sockaddr(struct sockaddr *addr, size_t len)
* call-seq:
* Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
*
- * Obtains the host information for _hostname_.
+ * Use Addrinfo.getaddrinfo instead.
+ * This method is deprecated for the following reasons:
+ *
+ * - The 3rd element of the result is the address family of the first address.
+ * The address families of the rest of the addresses are not returned.
+ * - Uncommon address representation:
+ * 4/16-bytes binary string to represent IPv4/IPv6 address.
+ * - gethostbyname() may take a long time and it may block other threads.
+ * (GVL cannot be released since gethostbyname() is not thread safe.)
+ * - This method uses gethostbyname() function already removed from POSIX.
+ *
+ * This method obtains the host information for _hostname_.
*
* p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
*
@@ -984,21 +959,39 @@ sock_sockaddr(struct sockaddr *addr, size_t len)
static VALUE
sock_s_gethostbyname(VALUE obj, VALUE host)
{
- rb_secure(3);
- return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
+ rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
+ struct rb_addrinfo *res =
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ return rsock_make_hostent(host, res, sock_sockaddr);
}
/*
* call-seq:
* Socket.gethostbyaddr(address_string [, address_family]) => hostent
*
- * Obtains the host information for _address_.
+ * Use Addrinfo#getnameinfo instead.
+ * This method is deprecated for the following reasons:
+ *
+ * - Uncommon address representation:
+ * 4/16-bytes binary string to represent IPv4/IPv6 address.
+ * - gethostbyaddr() may take a long time and it may block other threads.
+ * (GVL cannot be released since gethostbyname() is not thread safe.)
+ * - This method uses gethostbyname() function already removed from POSIX.
+ *
+ * This method obtains the host information for _address_.
*
* p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
* #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
+ *
+ * p Socket.gethostbyaddr([127,0,0,1].pack("CCCC"))
+ * ["localhost", [], 2, "\x7F\x00\x00\x01"]
+ * p Socket.gethostbyaddr(([0]*15+[1]).pack("C"*16))
+ * #=> ["localhost", ["ip6-localhost", "ip6-loopback"], 10,
+ * "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"]
+ *
*/
static VALUE
-sock_s_gethostbyaddr(int argc, VALUE *argv)
+sock_s_gethostbyaddr(int argc, VALUE *argv, VALUE _)
{
VALUE addr, family;
struct hostent *h;
@@ -1006,6 +999,8 @@ sock_s_gethostbyaddr(int argc, VALUE *argv)
VALUE ary, names;
int t = AF_INET;
+ rb_warn("Socket.gethostbyaddr is deprecated; use Addrinfo#getnameinfo instead.");
+
rb_scan_args(argc, argv, "11", &addr, &family);
StringValue(addr);
if (!NIL_P(family)) {
@@ -1016,7 +1011,7 @@ sock_s_gethostbyaddr(int argc, VALUE *argv)
t = AF_INET6;
}
#endif
- h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LENINT(addr), t);
+ h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), t);
if (h == NULL) {
#ifdef HAVE_HSTRERROR
extern int h_errno;
@@ -1060,7 +1055,7 @@ sock_s_gethostbyaddr(int argc, VALUE *argv)
* Socket.getservbyname("syslog", "udp") #=> 514
*/
static VALUE
-sock_s_getservbyname(int argc, VALUE *argv)
+sock_s_getservbyname(int argc, VALUE *argv, VALUE _)
{
VALUE service, proto;
struct servent *sp;
@@ -1101,7 +1096,7 @@ sock_s_getservbyname(int argc, VALUE *argv)
*
*/
static VALUE
-sock_s_getservbyport(int argc, VALUE *argv)
+sock_s_getservbyport(int argc, VALUE *argv, VALUE _)
{
VALUE port, proto;
struct servent *sp;
@@ -1120,7 +1115,7 @@ sock_s_getservbyport(int argc, VALUE *argv)
if (!sp) {
rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
}
- return rb_tainted_str_new2(sp->s_name);
+ return rb_str_new2(sp->s_name);
}
/*
@@ -1129,7 +1124,10 @@ sock_s_getservbyport(int argc, VALUE *argv)
*
* Obtains address information for _nodename_:_servname_.
*
- * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc.
+ * Note that Addrinfo.getaddrinfo provides the same functionality in
+ * an object oriented style.
+ *
+ * _family_ should be an address family such as: :INET, :INET6, etc.
*
* _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
*
@@ -1150,16 +1148,17 @@ sock_s_getservbyport(int argc, VALUE *argv)
* be one of below. If _reverse_lookup_ is omitted, the default value is +nil+.
*
* +true+, +:hostname+: hostname is obtained from numeric address using reverse lookup, which may take a time.
- * +false+, +:numeric+: hostname is same as numeric address.
+ * +false+, +:numeric+: hostname is the same as numeric address.
* +nil+: obey to the current +do_not_reverse_lookup+ flag.
*
* If Addrinfo object is preferred, use Addrinfo.getaddrinfo.
*/
static VALUE
-sock_s_getaddrinfo(int argc, VALUE *argv)
+sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
{
VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
- struct addrinfo hints, *res;
+ struct addrinfo hints;
+ struct rb_addrinfo *res;
int norevlookup;
rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);
@@ -1179,10 +1178,11 @@ sock_s_getaddrinfo(int argc, VALUE *argv)
if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
norevlookup = rsock_do_not_reverse_lookup;
}
+
res = rsock_getaddrinfo(host, port, &hints, 0);
ret = make_addrinfo(res, norevlookup);
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
return ret;
}
@@ -1209,16 +1209,17 @@ sock_s_getaddrinfo(int argc, VALUE *argv)
* If Addrinfo object is preferred, use Addrinfo#getnameinfo.
*/
static VALUE
-sock_s_getnameinfo(int argc, VALUE *argv)
+sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
{
VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
- char *hptr, *pptr;
char hbuf[1024], pbuf[1024];
int fl;
- struct addrinfo hints, *res = NULL, *r;
- int error;
- struct sockaddr_storage ss;
+ struct rb_addrinfo *res = NULL;
+ struct addrinfo hints, *r;
+ int error, saved_errno;
+ union_sockaddr ss;
struct sockaddr *sap;
+ socklen_t salen;
sa = flags = Qnil;
rb_scan_args(argc, argv, "11", &sa, &flags);
@@ -1234,10 +1235,11 @@ sock_s_getnameinfo(int argc, VALUE *argv)
rb_raise(rb_eTypeError, "sockaddr length too big");
}
memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
- if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) {
+ if (!VALIDATE_SOCKLEN(&ss.addr, RSTRING_LEN(sa))) {
rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
}
- sap = (struct sockaddr*)&ss;
+ sap = &ss.addr;
+ salen = RSTRING_SOCKLEN(sa);
goto call_nameinfo;
}
tmp = rb_check_array_type(sa);
@@ -1245,16 +1247,16 @@ sock_s_getnameinfo(int argc, VALUE *argv)
sa = tmp;
MEMZERO(&hints, struct addrinfo, 1);
if (RARRAY_LEN(sa) == 3) {
- af = RARRAY_PTR(sa)[0];
- port = RARRAY_PTR(sa)[1];
- host = RARRAY_PTR(sa)[2];
+ af = RARRAY_AREF(sa, 0);
+ port = RARRAY_AREF(sa, 1);
+ host = RARRAY_AREF(sa, 2);
}
else if (RARRAY_LEN(sa) >= 4) {
- af = RARRAY_PTR(sa)[0];
- port = RARRAY_PTR(sa)[1];
- host = RARRAY_PTR(sa)[3];
+ af = RARRAY_AREF(sa, 0);
+ port = RARRAY_AREF(sa, 1);
+ host = RARRAY_AREF(sa, 3);
if (NIL_P(host)) {
- host = RARRAY_PTR(sa)[2];
+ host = RARRAY_AREF(sa, 2);
}
else {
/*
@@ -1270,70 +1272,46 @@ sock_s_getnameinfo(int argc, VALUE *argv)
rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
RARRAY_LEN(sa));
}
- /* host */
- if (NIL_P(host)) {
- hptr = NULL;
- }
- else {
- strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
- hbuf[sizeof(hbuf) - 1] = '\0';
- hptr = hbuf;
- }
- /* port */
- if (NIL_P(port)) {
- strcpy(pbuf, "0");
- pptr = NULL;
- }
- else if (FIXNUM_P(port)) {
- snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
- pptr = pbuf;
- }
- else {
- strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
- pbuf[sizeof(pbuf) - 1] = '\0';
- pptr = pbuf;
- }
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
/* af */
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
- error = rb_getaddrinfo(hptr, pptr, &hints, &res);
- if (error) goto error_exit_addr;
- sap = res->ai_addr;
+ res = rsock_getaddrinfo(host, port, &hints, 0);
+ sap = res->ai->ai_addr;
+ salen = res->ai->ai_addrlen;
}
else {
rb_raise(rb_eTypeError, "expecting String or Array");
}
call_nameinfo:
- error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
+ error = rb_getnameinfo(sap, salen, hbuf, sizeof(hbuf),
pbuf, sizeof(pbuf), fl);
if (error) goto error_exit_name;
if (res) {
- for (r = res->ai_next; r; r = r->ai_next) {
+ for (r = res->ai->ai_next; r; r = r->ai_next) {
char hbuf2[1024], pbuf2[1024];
sap = r->ai_addr;
- error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2),
+ salen = r->ai_addrlen;
+ error = rb_getnameinfo(sap, salen, hbuf2, sizeof(hbuf2),
pbuf2, sizeof(pbuf2), fl);
if (error) goto error_exit_name;
if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
}
}
- freeaddrinfo(res);
+ rb_freeaddrinfo(res);
}
return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
- error_exit_addr:
- if (res) freeaddrinfo(res);
- rsock_raise_socket_error("getaddrinfo", error);
-
error_exit_name:
- if (res) freeaddrinfo(res);
+ saved_errno = errno;
+ if (res) rb_freeaddrinfo(res);
+ errno = saved_errno;
rsock_raise_socket_error("getnameinfo", error);
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
}
/*
@@ -1353,12 +1331,10 @@ sock_s_getnameinfo(int argc, VALUE *argv)
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
- struct addrinfo *res = rsock_addrinfo(host, port, 0, 0);
- VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
+ struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
+ VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
- freeaddrinfo(res);
- OBJ_INFECT(addr, port);
- OBJ_INFECT(addr, host);
+ rb_freeaddrinfo(res);
return addr;
}
@@ -1399,8 +1375,7 @@ sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
rb_raise(rb_eArgError, "not an AF_INET sockaddr");
#endif
}
- host = rsock_make_ipaddr((struct sockaddr*)sockaddr);
- OBJ_INFECT(host, addr);
+ host = rsock_make_ipaddr((struct sockaddr*)sockaddr, RSTRING_SOCKLEN(addr));
return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
}
@@ -1423,15 +1398,13 @@ sock_s_pack_sockaddr_un(VALUE self, VALUE path)
VALUE addr;
StringValue(path);
- MEMZERO(&sockaddr, struct sockaddr_un, 1);
- sockaddr.sun_family = AF_UNIX;
+ INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
}
memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
- addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr));
- OBJ_INFECT(addr, path);
+ addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));
return addr;
}
@@ -1467,17 +1440,57 @@ sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
}
- path = rsock_unixpath_str(sockaddr, RSTRING_LENINT(addr));
- OBJ_INFECT(path, addr);
+ path = rsock_unixpath_str(sockaddr, RSTRING_SOCKLEN(addr));
return path;
}
#endif
#if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32)
+
+static socklen_t
+sockaddr_len(struct sockaddr *addr)
+{
+ if (addr == NULL)
+ return 0;
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ if (addr->sa_len != 0)
+ return addr->sa_len;
+#endif
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ return (socklen_t)sizeof(struct sockaddr_in);
+
+#ifdef AF_INET6
+ case AF_INET6:
+ return (socklen_t)sizeof(struct sockaddr_in6);
+#endif
+
+#ifdef HAVE_SYS_UN_H
+ case AF_UNIX:
+ return (socklen_t)sizeof(struct sockaddr_un);
+#endif
+
+#ifdef AF_PACKET
+ case AF_PACKET:
+ return (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + ((struct sockaddr_ll *)addr)->sll_halen);
+#endif
+
+ default:
+ return (socklen_t)(offsetof(struct sockaddr, sa_family) + sizeof(addr->sa_family));
+ }
+}
+
+socklen_t
+rsock_sockaddr_len(struct sockaddr *addr)
+{
+ return sockaddr_len(addr);
+}
+
static VALUE
-sockaddr_obj(struct sockaddr *addr)
+sockaddr_obj(struct sockaddr *addr, socklen_t len)
{
- socklen_t len;
#if defined(AF_INET6) && defined(__KAME__)
struct sockaddr_in6 addr6;
#endif
@@ -1485,18 +1498,14 @@ sockaddr_obj(struct sockaddr *addr)
if (addr == NULL)
return Qnil;
- switch (addr->sa_family) {
- case AF_INET:
- len = (socklen_t)sizeof(struct sockaddr_in);
- break;
+ len = sockaddr_len(addr);
-#ifdef AF_INET6
- case AF_INET6:
- len = (socklen_t)sizeof(struct sockaddr_in6);
-# ifdef __KAME__
+#if defined(__KAME__) && defined(AF_INET6)
+ if (addr->sa_family == AF_INET6) {
/* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */
/* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */
/* convert fe80:1::1 to fe80::1%1 */
+ len = (socklen_t)sizeof(struct sockaddr_in6);
memcpy(&addr6, addr, len);
addr = (struct sockaddr *)&addr6;
if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
@@ -1506,27 +1515,18 @@ sockaddr_obj(struct sockaddr *addr)
addr6.sin6_addr.s6_addr[2] = 0;
addr6.sin6_addr.s6_addr[3] = 0;
}
-# endif
- break;
-#endif
-
-#ifdef HAVE_SYS_UN_H
- case AF_UNIX:
- len = (socklen_t)sizeof(struct sockaddr_un);
- break;
-#endif
-
- default:
- len = (socklen_t)sizeof(struct sockaddr_in);
- break;
}
-#ifdef SA_LEN
- if (len < (socklen_t)SA_LEN(addr))
- len = (socklen_t)SA_LEN(addr);
#endif
return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
}
+
+VALUE
+rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len)
+{
+ return sockaddr_obj(addr, len);
+}
+
#endif
#if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32)
@@ -1562,7 +1562,28 @@ socket_s_ip_address_list(VALUE self)
list = rb_ary_new();
for (p = ifp; p; p = p->ifa_next) {
if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
- rb_ary_push(list, sockaddr_obj(p->ifa_addr));
+ struct sockaddr *addr = p->ifa_addr;
+#if defined(AF_INET6) && defined(__sun)
+ /*
+ * OpenIndiana SunOS 5.11 getifaddrs() returns IPv6 link local
+ * address with sin6_scope_id == 0.
+ * So fill it from the interface name (ifa_name).
+ */
+ struct sockaddr_in6 addr6;
+ if (addr->sa_family == AF_INET6) {
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_in6);
+ memcpy(&addr6, addr, len);
+ addr = (struct sockaddr *)&addr6;
+ if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
+ addr6.sin6_scope_id == 0) {
+ unsigned int ifindex = if_nametoindex(p->ifa_name);
+ if (ifindex != 0) {
+ addr6.sin6_scope_id = ifindex;
+ }
+ }
+ }
+#endif
+ rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
}
}
@@ -1576,7 +1597,7 @@ socket_s_ip_address_list(VALUE self)
int ret;
struct lifnum ln;
struct lifconf lc;
- char *reason = NULL;
+ const char *reason = NULL;
int save_errno;
int i;
VALUE list = Qnil;
@@ -1585,7 +1606,7 @@ socket_s_ip_address_list(VALUE self)
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
- rb_sys_fail("socket");
+ rb_sys_fail("socket(2)");
memset(&ln, 0, sizeof(ln));
ln.lifn_family = AF_UNSPEC;
@@ -1624,7 +1645,7 @@ socket_s_ip_address_list(VALUE self)
}
((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index;
}
- rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr));
+ rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr, req->lifr_addrlen));
}
}
@@ -1637,13 +1658,13 @@ socket_s_ip_address_list(VALUE self)
errno = save_errno;
if (reason)
- rb_sys_fail(reason);
+ rb_syserr_fail(save_errno, reason);
return list;
#elif defined(SIOCGIFCONF)
int fd = -1;
int ret;
-#define EXTRA_SPACE (sizeof(struct ifconf) + sizeof(struct sockaddr_storage))
+#define EXTRA_SPACE ((int)(sizeof(struct ifconf) + sizeof(union_sockaddr)))
char initbuf[4096+EXTRA_SPACE];
char *buf = initbuf;
int bufsize;
@@ -1655,7 +1676,7 @@ socket_s_ip_address_list(VALUE self)
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
- rb_sys_fail("socket");
+ rb_sys_fail("socket(2)");
bufsize = sizeof(initbuf);
buf = initbuf;
@@ -1696,9 +1717,9 @@ socket_s_ip_address_list(VALUE self)
while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) {
struct sockaddr *addr = &req->ifr_addr;
if (IS_IP_FAMILY(addr->sa_family)) {
- rb_ary_push(list, sockaddr_obj(addr));
+ rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
}
-#ifdef HAVE_SA_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# ifndef _SIZEOF_ADDR_IFREQ
# define _SIZEOF_ADDR_IFREQ(r) \
(sizeof(struct ifreq) + \
@@ -1722,7 +1743,7 @@ socket_s_ip_address_list(VALUE self)
errno = save_errno;
if (reason)
- rb_sys_fail(reason);
+ rb_syserr_fail(save_errno, reason);
return list;
#undef EXTRA_SPACE
@@ -1813,7 +1834,7 @@ socket_s_ip_address_list(VALUE self)
#else
if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family))
#endif
- rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr));
+ rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr, uni->Address.iSockaddrLength));
}
for (any = adapters->FirstAnycastAddress; any; any = any->Next) {
#ifndef INET6
@@ -1821,7 +1842,7 @@ socket_s_ip_address_list(VALUE self)
#else
if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family))
#endif
- rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr));
+ rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr, any->Address.iSockaddrLength));
}
}
@@ -1834,8 +1855,10 @@ socket_s_ip_address_list(VALUE self)
#endif
void
-Init_socket()
+Init_socket(void)
{
+ rb_ext_ractor_safe(true);
+
rsock_init_basicsocket();
/*
@@ -1852,7 +1875,7 @@ Init_socket()
*
* === What's a socket?
*
- * Sockets are endpoints of a bidirectionnal communication channel.
+ * Sockets are endpoints of a bidirectional communication channel.
* Sockets can communicate within a process, between processes on the same
* machine or between different machines. There are many types of socket:
* TCPSocket, UDPSocket or UNIXSocket for example.
@@ -1877,7 +1900,7 @@ Init_socket()
*
* *hostname:*
* The identifier of a network interface:
- * * a string (hostname, IPv4 or IPv6 adress or +broadcast+
+ * * a string (hostname, IPv4 or IPv6 address or +broadcast+
* which specifies a broadcast address)
* * a zero-length string which specifies INADDR_ANY
* * an integer (interpreted as binary address in host byte order).
@@ -1889,6 +1912,8 @@ Init_socket()
*
* Let's create an internet socket using the IPv4 protocol in a C-like manner:
*
+ * require 'socket'
+ *
* s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
* s.connect Socket.pack_sockaddr_in(80, 'example.com')
*
@@ -1959,15 +1984,26 @@ Init_socket()
rb_define_method(rb_cSocket, "initialize", sock_initialize, -1);
rb_define_method(rb_cSocket, "connect", sock_connect, 1);
- rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cSocket,
+ "__connect_nonblock", sock_connect_nonblock, 2);
+
rb_define_method(rb_cSocket, "bind", sock_bind, 1);
rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1);
rb_define_method(rb_cSocket, "accept", sock_accept, 0);
- rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cSocket,
+ "__accept_nonblock", sock_accept_nonblock, 1);
+
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
- rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
+
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cSocket,
+ "__recvfrom_nonblock", sock_recvfrom_nonblock, 4);
rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
@@ -1988,4 +2024,7 @@ Init_socket()
#endif
rb_define_singleton_method(rb_cSocket, "ip_address_list", socket_s_ip_address_list, 0);
+
+#undef rb_intern
+ sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
}
diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h
index 5f2fd24530..2b58958ae7 100644
--- a/ext/socket/sockport.h
+++ b/ext/socket/sockport.h
@@ -10,42 +10,74 @@
#ifndef SOCKPORT_H
#define SOCKPORT_H
-#ifdef SA_LEN
-# define SS_LEN(ss) (ss)->ss_len
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+# define VALIDATE_SOCKLEN(addr, len) ((addr)->sa_len == (len))
#else
-# ifdef HAVE_SA_LEN
-# define SA_LEN(sa) (sa)->sa_len
-# define SS_LEN(ss) (ss)->ss_len
-# else
-# ifdef AF_INET6
-# define SA_LEN(sa) \
- (((sa)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) \
- : sizeof(struct sockaddr))
-# define SS_LEN(ss) \
- (((ss)->ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) \
- : sizeof(struct sockaddr))
-# else
- /* by tradition, sizeof(struct sockaddr) covers most of the sockaddrs */
-# define SA_LEN(sa) (sizeof(struct sockaddr))
-# define SS_LEN(ss) (sizeof(struct sockaddr))
-# endif
-# endif
+# define VALIDATE_SOCKLEN(addr, len) ((void)(addr), (void)(len), 1)
#endif
-#ifdef HAVE_SA_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# define SET_SA_LEN(sa, len) (void)((sa)->sa_len = (len))
-# define SET_SS_LEN(ss, len) (void)((ss)->ss_len = (len))
#else
# define SET_SA_LEN(sa, len) (void)(len)
-# define SET_SS_LEN(ss, len) (void)(len)
#endif
-#ifdef HAVE_SIN_LEN
-# define SIN_LEN(si) (si)->sin_len
-# define SET_SIN_LEN(si,len) (si)->sin_len = (len)
+/* for strict-aliasing rule */
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+# define SET_SIN_LEN(sa, len) (void)((sa)->sin_len = (len))
+#else
+# define SET_SIN_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len))
+#endif
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+# define SET_SIN6_LEN(sa, len) (void)((sa)->sin6_len = (len))
#else
-# define SIN_LEN(si) sizeof(struct sockaddr_in)
-# define SET_SIN_LEN(si,len)
+# define SET_SIN6_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len))
+#endif
+
+#define INIT_SOCKADDR(addr, family, len) \
+ do { \
+ struct sockaddr *init_sockaddr_ptr = (addr); \
+ socklen_t init_sockaddr_len = (len); \
+ memset(init_sockaddr_ptr, 0, init_sockaddr_len); \
+ init_sockaddr_ptr->sa_family = (family); \
+ SET_SA_LEN(init_sockaddr_ptr, init_sockaddr_len); \
+ } while (0)
+
+#define INIT_SOCKADDR_IN(addr, len) \
+ do { \
+ struct sockaddr_in *init_sockaddr_ptr = (addr); \
+ socklen_t init_sockaddr_len = (len); \
+ memset(init_sockaddr_ptr, 0, init_sockaddr_len); \
+ init_sockaddr_ptr->sin_family = AF_INET; \
+ SET_SIN_LEN(init_sockaddr_ptr, init_sockaddr_len); \
+ } while (0)
+
+#define INIT_SOCKADDR_IN6(addr, len) \
+ do { \
+ struct sockaddr_in6 *init_sockaddr_ptr = (addr); \
+ socklen_t init_sockaddr_len = (len); \
+ memset(init_sockaddr_ptr, 0, init_sockaddr_len); \
+ init_sockaddr_ptr->sin6_family = AF_INET6; \
+ SET_SIN6_LEN(init_sockaddr_ptr, init_sockaddr_len); \
+ } while (0)
+
+
+/* for strict-aliasing rule */
+#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
+# ifdef HAVE_STRUCT_SOCKADDR_IN_SUN_LEN
+# define SET_SUN_LEN(sa, len) (void)((sa)->sun_len = (len))
+# else
+# define SET_SUN_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len))
+# endif
+# define INIT_SOCKADDR_UN(addr, len) \
+ do { \
+ struct sockaddr_un *init_sockaddr_ptr = (addr); \
+ socklen_t init_sockaddr_len = (len); \
+ memset(init_sockaddr_ptr, 0, init_sockaddr_len); \
+ init_sockaddr_ptr->sun_family = AF_UNIX; \
+ SET_SUN_LEN(init_sockaddr_ptr, init_sockaddr_len); \
+ } while (0)
#endif
#ifndef IN_MULTICAST
diff --git a/ext/socket/sockssocket.c b/ext/socket/sockssocket.c
index 48be4fcf99..b8b7e12998 100644
--- a/ext/socket/sockssocket.c
+++ b/ext/socket/sockssocket.c
@@ -13,13 +13,19 @@
#ifdef SOCKS
/*
* call-seq:
- * SOCKSSocket.new(host, serv) => socket
+ * SOCKSSocket.new(host, port) => socket
*
- * Opens a SOCKS connection to +host+ via the SOCKS server +serv+.
+ * Opens a SOCKS connection to +host+ via the SOCKS server.
+ *
+ * The SOCKS server configuration varies by implementation
+ *
+ * When using the Dante libsocks/libsocksd implementation it is configured as SOCKS_SERVER env var.
+ *
+ * See: https://manpages.debian.org/testing/dante-client/socksify.1.en.html for full env variable support.
*
*/
static VALUE
-socks_init(VALUE sock, VALUE host, VALUE serv)
+socks_init(VALUE sock, VALUE host, VALUE port)
{
static int init = 0;
@@ -28,7 +34,7 @@ socks_init(VALUE sock, VALUE host, VALUE serv)
init = 1;
}
- return rsock_init_inetsock(sock, host, serv, Qnil, Qnil, INET_SOCKS);
+ return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil);
}
#ifdef SOCKS5
@@ -41,9 +47,6 @@ socks_s_close(VALUE sock)
{
rb_io_t *fptr;
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
- rb_raise(rb_eSecurityError, "Insecure: can't close socket");
- }
GetOpenFile(sock, fptr);
shutdown(fptr->fd, 2);
return rb_io_close(sock);
diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c
index 6596733239..675733c6f9 100644
--- a/ext/socket/tcpserver.c
+++ b/ext/socket/tcpserver.c
@@ -12,7 +12,7 @@
/*
* call-seq:
- * TCPServer.new([hostname,] port) => tcpserver
+ * TCPServer.new([hostname,] port) => tcpserver
*
* Creates a new server socket bound to _port_.
*
@@ -22,6 +22,13 @@
* s = serv.accept
* s.puts Time.now
* s.close
+ *
+ * Internally, TCPServer.new calls getaddrinfo() function to
+ * obtain addresses.
+ * If getaddrinfo() returns multiple addresses,
+ * TCPServer.new tries to create a server socket for each address
+ * and returns first one that is successful.
+ *
*/
static VALUE
tcp_svr_init(int argc, VALUE *argv, VALUE sock)
@@ -29,13 +36,15 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
VALUE hostname, port;
rb_scan_args(argc, argv, "011", &hostname, &port);
- return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER);
+ return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil);
}
/*
* call-seq:
* tcpserver.accept => tcpsocket
*
+ * Accepts an incoming connection. It returns a new TCPSocket object.
+ *
* TCPServer.open("127.0.0.1", 14641) {|serv|
* s = serv.accept
* s.puts Time.now
@@ -44,62 +53,24 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
*
*/
static VALUE
-tcp_accept(VALUE sock)
+tcp_accept(VALUE server)
{
- rb_io_t *fptr;
- struct sockaddr_storage from;
- socklen_t fromlen;
+ union_sockaddr buffer;
+ socklen_t length = sizeof(buffer);
- GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept(rb_cTCPSocket, fptr->fd,
- (struct sockaddr*)&from, &fromlen);
+ return rsock_s_accept(rb_cTCPSocket, server, &buffer.addr, &length);
}
-/*
- * call-seq:
- * tcpserver.accept_nonblock => tcpsocket
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an accepted TCPSocket for the incoming connection.
- *
- * === Example
- * require 'socket'
- * serv = TCPServer.new(2202)
- * begin # emulate blocking accept
- * sock = serv.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([serv])
- * retry
- * end
- * # sock is an accepted socket.
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to TCPServer#accept_nonblock fails.
- *
- * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED, Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * === See
- * * TCPServer#accept
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-tcp_accept_nonblock(VALUE sock)
+tcp_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
- struct sockaddr_storage from;
- socklen_t fromlen;
+ union_sockaddr from;
+ socklen_t len = (socklen_t)sizeof(from);
GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept_nonblock(rb_cTCPSocket, fptr,
- (struct sockaddr *)&from, &fromlen);
+ return rsock_s_accept_nonblock(rb_cTCPSocket, ex, fptr, &from.addr, &len);
}
/*
@@ -117,15 +88,12 @@ tcp_accept_nonblock(VALUE sock)
*
*/
static VALUE
-tcp_sysaccept(VALUE sock)
+tcp_sysaccept(VALUE server)
{
- rb_io_t *fptr;
- struct sockaddr_storage from;
- socklen_t fromlen;
+ union_sockaddr buffer;
+ socklen_t length = sizeof(buffer);
- GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
+ return rsock_s_accept(0, server, &buffer.addr, &length);
}
void
@@ -164,7 +132,8 @@ rsock_init_tcpserver(void)
*/
rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
- rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0);
+ rb_define_private_method(rb_cTCPServer,
+ "__accept_nonblock", tcp_accept_nonblock, 1);
rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c
index 7eb6fc7aa2..51e77a0de9 100644
--- a/ext/socket/tcpsocket.c
+++ b/ext/socket/tcpsocket.c
@@ -12,36 +12,64 @@
/*
* call-seq:
- * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil)
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, connect_timeout: nil)
*
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
* and +local_port+ are specified, then those parameters are used on the local
* end to establish the connection.
+ *
+ * [:connect_timeout] specify the timeout in seconds.
*/
static VALUE
tcp_init(int argc, VALUE *argv, VALUE sock)
{
VALUE remote_host, remote_serv;
VALUE local_host, local_serv;
+ VALUE opt;
+ static ID keyword_ids[2];
+ VALUE kwargs[2];
+ VALUE resolv_timeout = Qnil;
+ VALUE connect_timeout = Qnil;
+
+ if (!keyword_ids[0]) {
+ CONST_ID(keyword_ids[0], "resolv_timeout");
+ CONST_ID(keyword_ids[1], "connect_timeout");
+ }
+
+ rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
+ &local_host, &local_serv, &opt);
- rb_scan_args(argc, argv, "22", &remote_host, &remote_serv,
- &local_host, &local_serv);
+ if (!NIL_P(opt)) {
+ rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
+ if (kwargs[0] != Qundef) { resolv_timeout = kwargs[0]; }
+ if (kwargs[1] != Qundef) { connect_timeout = kwargs[1]; }
+ }
return rsock_init_inetsock(sock, remote_host, remote_serv,
- local_host, local_serv, INET_CLIENT);
+ local_host, local_serv, INET_CLIENT,
+ resolv_timeout, connect_timeout);
}
static VALUE
-tcp_sockaddr(struct sockaddr *addr, size_t len)
+tcp_sockaddr(struct sockaddr *addr, socklen_t len)
{
- return rsock_make_ipaddr(addr);
+ return rsock_make_ipaddr(addr, len);
}
/*
* call-seq:
* TCPSocket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
*
- * Lookups host information by _hostname_.
+ * Use Addrinfo.getaddrinfo instead.
+ * This method is deprecated for the following reasons:
+ *
+ * - The 3rd element of the result is the address family of the first address.
+ * The address families of the rest of the addresses are not returned.
+ * - gethostbyname() may take a long time and it may block other threads.
+ * (GVL cannot be released since gethostbyname() is not thread safe.)
+ * - This method uses gethostbyname() function already removed from POSIX.
+ *
+ * This method lookups host information by _hostname_.
*
* TCPSocket.gethostbyname("localhost")
* #=> ["localhost", ["hal"], 2, "127.0.0.1"]
@@ -50,9 +78,10 @@ tcp_sockaddr(struct sockaddr *addr, size_t len)
static VALUE
tcp_s_gethostbyname(VALUE obj, VALUE host)
{
- rb_secure(3);
- return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME),
- tcp_sockaddr);
+ rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
+ struct rb_addrinfo *res =
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ return rsock_make_hostent(host, res, tcp_sockaddr);
}
void
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index 0ba4371f1a..2bfd7c8560 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -19,6 +19,8 @@
* _address_family_ should be an integer, a string or a symbol:
* Socket::AF_INET, "AF_INET", :INET, etc.
*
+ * require 'socket'
+ *
* UDPSocket.new #=> #<UDPSocket:fd 3>
* UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4>
*
@@ -30,7 +32,6 @@ udp_init(int argc, VALUE *argv, VALUE sock)
int family = AF_INET;
int fd;
- rb_secure(3);
if (rb_scan_args(argc, argv, "01", &arg) == 1) {
family = rsock_family_arg(arg);
}
@@ -44,26 +45,28 @@ udp_init(int argc, VALUE *argv, VALUE sock)
struct udp_arg
{
- struct addrinfo *res;
- int fd;
+ struct rb_addrinfo *res;
+ rb_io_t *fptr;
};
static VALUE
-udp_connect_internal(struct udp_arg *arg)
+udp_connect_internal(VALUE v)
{
- int fd = arg->fd;
+ struct udp_arg *arg = (void *)v;
+ rb_io_t *fptr;
+ int fd;
struct addrinfo *res;
- for (res = arg->res; res; res = res->ai_next) {
- if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
+ rb_io_check_closed(fptr = arg->fptr);
+ fd = fptr->fd;
+ for (res = arg->res->ai; res; res = res->ai_next) {
+ if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0, NULL) >= 0) {
return Qtrue;
}
}
return Qfalse;
}
-VALUE rsock_freeaddrinfo(struct addrinfo *addr);
-
/*
* call-seq:
* udpsocket.connect(host, port) => 0
@@ -83,20 +86,36 @@ VALUE rsock_freeaddrinfo(struct addrinfo *addr);
static VALUE
udp_connect(VALUE sock, VALUE host, VALUE port)
{
- rb_io_t *fptr;
struct udp_arg arg;
VALUE ret;
- rb_secure(3);
- arg.res = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
- GetOpenFile(sock, fptr);
- arg.fd = fptr->fd;
+ GetOpenFile(sock, arg.fptr);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
- if (!ret) rb_sys_fail("connect(2)");
+ if (!ret) rsock_sys_fail_host_port("connect(2)", host, port);
return INT2FIX(0);
}
+static VALUE
+udp_bind_internal(VALUE v)
+{
+ struct udp_arg *arg = (void *)v;
+ rb_io_t *fptr;
+ int fd;
+ struct addrinfo *res;
+
+ rb_io_check_closed(fptr = arg->fptr);
+ fd = fptr->fd;
+ for (res = arg->res->ai; res; res = res->ai_next) {
+ if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
+ continue;
+ }
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
/*
* call-seq:
* udpsocket.bind(host, port) #=> 0
@@ -112,22 +131,50 @@ udp_connect(VALUE sock, VALUE host, VALUE port)
static VALUE
udp_bind(VALUE sock, VALUE host, VALUE port)
{
+ struct udp_arg arg;
+ VALUE ret;
+
+ GetOpenFile(sock, arg.fptr);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+ ret = rb_ensure(udp_bind_internal, (VALUE)&arg,
+ rsock_freeaddrinfo, (VALUE)arg.res);
+ if (!ret) rsock_sys_fail_host_port("bind(2)", host, port);
+ return INT2FIX(0);
+}
+
+struct udp_send_arg {
+ struct rb_addrinfo *res;
rb_io_t *fptr;
- struct addrinfo *res0, *res;
+ struct rsock_send_arg sarg;
+};
- rb_secure(3);
- res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
- GetOpenFile(sock, fptr);
- for (res = res0; res; res = res->ai_next) {
- if (bind(fptr->fd, res->ai_addr, res->ai_addrlen) < 0) {
- continue;
- }
- freeaddrinfo(res0);
- return INT2FIX(0);
+static VALUE
+udp_send_internal(VALUE v)
+{
+ struct udp_send_arg *arg = (void *)v;
+ rb_io_t *fptr;
+ struct addrinfo *res;
+
+ rb_io_check_closed(fptr = arg->fptr);
+ for (res = arg->res->ai; res; res = res->ai_next) {
+ retry:
+ arg->sarg.fd = fptr->fd;
+ arg->sarg.to = res->ai_addr;
+ arg->sarg.tolen = res->ai_addrlen;
+
+#ifdef RSOCK_WAIT_BEFORE_BLOCKING
+ rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil);
+#endif
+
+ ssize_t n = (ssize_t)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg->sarg);
+
+ if (n >= 0) return RB_SSIZE2NUM(n);
+
+ if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
+ goto retry;
+ }
}
- freeaddrinfo(res0);
- rb_sys_fail("bind(2)");
- return INT2FIX(0);
+ return Qfalse;
}
/*
@@ -156,94 +203,30 @@ static VALUE
udp_send(int argc, VALUE *argv, VALUE sock)
{
VALUE flags, host, port;
- rb_io_t *fptr;
- int n;
- struct addrinfo *res0, *res;
- struct rsock_send_arg arg;
+ struct udp_send_arg arg;
+ VALUE ret;
if (argc == 2 || argc == 3) {
return rsock_bsock_send(argc, argv, sock);
}
- rb_secure(4);
- rb_scan_args(argc, argv, "4", &arg.mesg, &flags, &host, &port);
-
- StringValue(arg.mesg);
- res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
- GetOpenFile(sock, fptr);
- arg.fd = fptr->fd;
- arg.flags = NUM2INT(flags);
- for (res = res0; res; res = res->ai_next) {
- retry:
- arg.to = res->ai_addr;
- arg.tolen = res->ai_addrlen;
- rb_thread_fd_writable(arg.fd);
- n = (int)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg);
- if (n >= 0) {
- freeaddrinfo(res0);
- return INT2FIX(n);
- }
- if (rb_io_wait_writable(fptr->fd)) {
- goto retry;
- }
- }
- freeaddrinfo(res0);
- rb_sys_fail("sendto(2)");
- return INT2FIX(n);
+ rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);
+
+ StringValue(arg.sarg.mesg);
+ GetOpenFile(sock, arg.fptr);
+ arg.sarg.fd = arg.fptr->fd;
+ arg.sarg.flags = NUM2INT(flags);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+ ret = rb_ensure(udp_send_internal, (VALUE)&arg,
+ rsock_freeaddrinfo, (VALUE)arg.res);
+ if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
+ return ret;
}
-/*
- * call-seq:
- * udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr]
- * udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr]
- *
- * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * If _maxlen_ is omitted, its default value is 65536.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_inet_addr_, is an array to represent the sender address.
- *
- * When recvfrom(2) returns 0,
- * Socket#recvfrom_nonblock returns an empty string as data.
- * It means an empty packet.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- * require 'socket'
- * s1 = UDPSocket.new
- * s1.bind("127.0.0.1", 0)
- * s2 = UDPSocket.new
- * s2.bind("127.0.0.1", 0)
- * s2.connect(*s1.addr.values_at(3,1))
- * s1.connect(*s2.addr.values_at(3,1))
- * s1.send "aaa", 0
- * begin # emulate blocking recvfrom
- * p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
- * rescue IO::WaitReadable
- * IO.select([s2])
- * retry
- * end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
static VALUE
-udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
{
- return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
+ return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
}
void
@@ -260,6 +243,8 @@ rsock_init_udpsocket(void)
rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
- rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
-}
+ /* for ext/socket/lib/socket.rb use only: */
+ rb_define_private_method(rb_cUDPSocket,
+ "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
+}
diff --git a/ext/socket/unixserver.c b/ext/socket/unixserver.c
index 9bd959d439..890f9d3fae 100644
--- a/ext/socket/unixserver.c
+++ b/ext/socket/unixserver.c
@@ -17,6 +17,8 @@
*
* Creates a new UNIX server socket bound to _path_.
*
+ * require 'socket'
+ *
* serv = UNIXServer.new("/tmp/sock")
* s = serv.accept
* p s.read
@@ -31,8 +33,8 @@ unix_svr_init(VALUE sock, VALUE path)
* call-seq:
* unixserver.accept => unixsocket
*
- * Accepts a new connection.
- * It returns new UNIXSocket object.
+ * Accepts an incoming connection.
+ * It returns a new UNIXSocket object.
*
* UNIXServer.open("/tmp/sock") {|serv|
* UNIXSocket.open("/tmp/sock") {|c|
@@ -45,53 +47,17 @@ unix_svr_init(VALUE sock, VALUE path)
*
*/
static VALUE
-unix_accept(VALUE sock)
+unix_accept(VALUE server)
{
- rb_io_t *fptr;
- struct sockaddr_un from;
- socklen_t fromlen;
+ struct sockaddr_un buffer;
+ socklen_t length = sizeof(buffer);
- GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(struct sockaddr_un);
- return rsock_s_accept(rb_cUNIXSocket, fptr->fd,
- (struct sockaddr*)&from, &fromlen);
+ return rsock_s_accept(rb_cUNIXSocket, server, (struct sockaddr*)&buffer, &length);
}
-/*
- * call-seq:
- * unixserver.accept_nonblock => unixsocket
- *
- * Accepts an incoming connection using accept(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * It returns an accepted UNIXSocket for the incoming connection.
- *
- * === Example
- * require 'socket'
- * serv = UNIXServer.new("/tmp/sock")
- * begin # emulate blocking accept
- * sock = serv.accept_nonblock
- * rescue IO::WaitReadable, Errno::EINTR
- * IO.select([serv])
- * retry
- * end
- * # sock is an accepted socket.
- *
- * Refer to Socket#accept for the exceptions that may be thrown if the call
- * to UNIXServer#accept_nonblock fails.
- *
- * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
- *
- * === See
- * * UNIXServer#accept
- * * Socket#accept
- */
+/* :nodoc: */
static VALUE
-unix_accept_nonblock(VALUE sock)
+unix_accept_nonblock(VALUE sock, VALUE ex)
{
rb_io_t *fptr;
struct sockaddr_un from;
@@ -99,7 +65,7 @@ unix_accept_nonblock(VALUE sock)
GetOpenFile(sock, fptr);
fromlen = (socklen_t)sizeof(from);
- return rsock_s_accept_nonblock(rb_cUNIXSocket, fptr,
+ return rsock_s_accept_nonblock(rb_cUNIXSocket, ex, fptr,
(struct sockaddr *)&from, &fromlen);
}
@@ -122,15 +88,12 @@ unix_accept_nonblock(VALUE sock)
*
*/
static VALUE
-unix_sysaccept(VALUE sock)
+unix_sysaccept(VALUE server)
{
- rb_io_t *fptr;
- struct sockaddr_un from;
- socklen_t fromlen;
+ struct sockaddr_un buffer;
+ socklen_t length = sizeof(buffer);
- GetOpenFile(sock, fptr);
- fromlen = (socklen_t)sizeof(struct sockaddr_un);
- return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
+ return rsock_s_accept(0, server, (struct sockaddr*)&buffer, &length);
}
#endif
@@ -148,7 +111,10 @@ rsock_init_unixserver(void)
rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1);
rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
- rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, 0);
+
+ rb_define_private_method(rb_cUNIXServer,
+ "__accept_nonblock", unix_accept_nonblock, 1);
+
rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
rb_define_method(rb_cUNIXServer, "listen", rsock_sock_listen, 1); /* in socket.c */
#endif
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 596fb5cdcd..857cfa6002 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -13,6 +13,7 @@
#ifdef HAVE_SYS_UN_H
struct unixsock_arg {
struct sockaddr_un *sockaddr;
+ socklen_t sockaddrlen;
int fd;
};
@@ -21,37 +22,61 @@ unixsock_connect_internal(VALUE a)
{
struct unixsock_arg *arg = (struct unixsock_arg *)a;
return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
- (socklen_t)sizeof(*arg->sockaddr), 0);
+ arg->sockaddrlen, 0, NULL);
+}
+
+static VALUE
+unixsock_path_value(VALUE path)
+{
+#ifdef __linux__
+#define TO_STR_FOR_LINUX_ABSTRACT_NAMESPACE 0
+
+ VALUE name = path;
+#if TO_STR_FOR_LINUX_ABSTRACT_NAMESPACE
+ const int isstr = !NIL_P(name = rb_check_string_type(name));
+#else
+ const int isstr = RB_TYPE_P(name, T_STRING);
+#endif
+ if (isstr) {
+ if (RSTRING_LEN(name) == 0 || RSTRING_PTR(name)[0] == '\0') {
+ return name; /* ignore encoding */
+ }
+ }
+#endif
+ return rb_get_path(path);
}
VALUE
rsock_init_unixsock(VALUE sock, VALUE path, int server)
{
struct sockaddr_un sockaddr;
+ socklen_t sockaddrlen;
int fd, status;
rb_io_t *fptr;
- SafeStringValue(path);
- fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- rb_sys_fail("socket(2)");
- }
+ path = unixsock_path_value(path);
- MEMZERO(&sockaddr, struct sockaddr_un, 1);
- sockaddr.sun_family = AF_UNIX;
+ INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)",
RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path));
}
memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
+ sockaddrlen = rsock_unix_sockaddr_len(path);
+
+ fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ rsock_sys_fail_path("socket(2)", path);
+ }
if (server) {
- status = bind(fd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr));
+ status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen);
}
else {
int prot;
struct unixsock_arg arg;
arg.sockaddr = &sockaddr;
+ arg.sockaddrlen = sockaddrlen;
arg.fd = fd;
status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot);
if (prot) {
@@ -61,14 +86,16 @@ rsock_init_unixsock(VALUE sock, VALUE path, int server)
}
if (status < 0) {
+ int e = errno;
close(fd);
- rb_sys_fail_str(path);
+ rsock_syserr_fail_path(e, "connect(2)", path);
}
if (server) {
if (listen(fd, SOMAXCONN) < 0) {
+ int e = errno;
close(fd);
- rb_sys_fail("listen(2)");
+ rsock_syserr_fail_path(e, "listen(2)", path);
}
}
@@ -87,6 +114,8 @@ rsock_init_unixsock(VALUE sock, VALUE path, int server)
*
* Creates a new UNIX client socket connected to _path_.
*
+ * require 'socket'
+ *
* s = UNIXSocket.new("/tmp/sock")
* s.send "hello", 0
*
@@ -116,8 +145,10 @@ unix_path(VALUE sock)
if (NIL_P(fptr->pathv)) {
struct sockaddr_un addr;
socklen_t len = (socklen_t)sizeof(addr);
+ socklen_t len0 = len;
if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
- rb_sys_fail(0);
+ rsock_sys_fail_path("getsockname(2)", fptr->pathv);
+ if (len0 < len) len = len0;
fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len));
}
return rb_str_dup(fptr->pathv);
@@ -125,7 +156,7 @@ unix_path(VALUE sock)
/*
* call-seq:
- * unixsocket.recvfrom(maxlen [, flags]) => [mesg, unixaddress]
+ * unixsocket.recvfrom(maxlen [, flags[, outbuf]]) => [mesg, unixaddress]
*
* Receives a message via _unixsocket_.
*
@@ -133,6 +164,9 @@ unix_path(VALUE sock)
*
* _flags_ should be a bitwise OR of Socket::MSG_* constants.
*
+ * _outbuf_ will contain only the received data after the method call
+ * even if it is not empty at the beginning.
+ *
* s1 = Socket.new(:UNIX, :DGRAM, 0)
* s1_ai = Addrinfo.unix("/tmp/sock1")
* s1.bind(s1_ai)
@@ -152,13 +186,13 @@ unix_recvfrom(int argc, VALUE *argv, VALUE sock)
return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX);
}
-#if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(SCM_RIGHTS)
#define FD_PASSING_BY_MSG_CONTROL 1
#else
#define FD_PASSING_BY_MSG_CONTROL 0
#endif
-#if defined(HAVE_ST_MSG_ACCRIGHTS)
+#if defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
#define FD_PASSING_BY_MSG_ACCRIGHTS 1
#else
#define FD_PASSING_BY_MSG_ACCRIGHTS 0
@@ -192,6 +226,8 @@ sendmsg_blocking(void *data)
* p stdout.fileno #=> 6
*
* stdout.puts "hello" # outputs "hello\n" to standard output.
+ *
+ * _io_ may be any kind of IO object or integer file descriptor.
*/
static VALUE
unix_send_io(VALUE sock, VALUE val)
@@ -203,9 +239,9 @@ unix_send_io(VALUE sock, VALUE val)
char buf[1];
#if FD_PASSING_BY_MSG_CONTROL
- struct {
+ union {
struct cmsghdr hdr;
- char pad[8+sizeof(int)+8];
+ char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
} cmsg;
#endif
@@ -250,7 +286,7 @@ unix_send_io(VALUE sock, VALUE val)
arg.fd = fptr->fd;
while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) {
if (!rb_io_wait_writable(arg.fd))
- rb_sys_fail("sendmsg(2)");
+ rsock_sys_fail_path("sendmsg(2)", fptr->pathv);
}
return Qnil;
@@ -272,6 +308,8 @@ recvmsg_blocking(void *data)
* call-seq:
* unixsocket.recv_io([klass [, mode]]) => io
*
+ * Example
+ *
* UNIXServer.open("/tmp/sock") {|serv|
* UNIXSocket.open("/tmp/sock") {|c|
* s = serv.accept
@@ -286,6 +324,11 @@ recvmsg_blocking(void *data)
* }
* }
*
+ * _klass_ will determine the class of _io_ returned (using the
+ * IO.for_fd singleton method or similar).
+ * If _klass_ is +nil+, an integer file descriptor is returned.
+ *
+ * _mode_ is the same as the argument passed to IO.for_fd
*/
static VALUE
unix_recv_io(int argc, VALUE *argv, VALUE sock)
@@ -295,12 +338,18 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
struct iomsg_arg arg;
struct iovec vec[2];
char buf[1];
+ unsigned int gc_reason = 0;
+ enum {
+ GC_REASON_EMSGSIZE = 0x1,
+ GC_REASON_TRUNCATE = 0x2,
+ GC_REASON_ENOMEM = 0x4
+ };
int fd;
#if FD_PASSING_BY_MSG_CONTROL
- struct {
+ union {
struct cmsghdr hdr;
- char pad[8+sizeof(int)+8];
+ char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
} cmsg;
#endif
@@ -310,6 +359,7 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
if (argc <= 1)
mode = Qnil;
+retry:
GetOpenFile(sock, fptr);
arg.msg.msg_name = NULL;
@@ -337,12 +387,31 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
arg.fd = fptr->fd;
while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) {
+ int e = errno;
+ if (e == EMSGSIZE && !(gc_reason & GC_REASON_EMSGSIZE)) {
+ /* FreeBSD gets here when we're out of FDs */
+ gc_reason |= GC_REASON_EMSGSIZE;
+ rb_gc_for_fd(EMFILE);
+ goto retry;
+ }
+ else if (e == ENOMEM && !(gc_reason & GC_REASON_ENOMEM)) {
+ /* ENOMEM is documented in recvmsg manpages */
+ gc_reason |= GC_REASON_ENOMEM;
+ rb_gc_for_fd(e);
+ goto retry;
+ }
if (!rb_io_wait_readable(arg.fd))
- rb_sys_fail("recvmsg(2)");
+ rsock_syserr_fail_path(e, "recvmsg(2)", fptr->pathv);
}
#if FD_PASSING_BY_MSG_CONTROL
if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) {
+ /* FreeBSD and Linux both get here when we're out of FDs */
+ if (!(gc_reason & GC_REASON_TRUNCATE)) {
+ gc_reason |= GC_REASON_TRUNCATE;
+ rb_gc_for_fd(EMFILE);
+ goto retry;
+ }
rb_raise(rb_eSocket,
"file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)",
(int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr));
@@ -376,7 +445,7 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
#else
if (arg.msg.msg_accrightslen != sizeof(fd)) {
rb_raise(rb_eSocket,
- "file descriptor was not passed (accrightslen) : %d != %d",
+ "file descriptor was not passed (accrightslen=%d, %d expected)",
arg.msg.msg_accrightslen, (int)sizeof(fd));
}
#endif
@@ -384,7 +453,9 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
#if FD_PASSING_BY_MSG_CONTROL
memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
#endif
- rb_fd_fix_cloexec(fd);
+
+ rb_update_max_fd(fd);
+ rb_maygvl_fd_fix_cloexec(fd);
if (klass == Qnil)
return INT2FIX(fd);
@@ -396,7 +467,7 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
ff_argc = mode == Qnil ? 1 : 2;
ff_argv[0] = INT2FIX(fd);
ff_argv[1] = mode;
- return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
+ return rb_funcallv(klass, for_fd, ff_argc, ff_argv);
}
}
#else
@@ -420,11 +491,13 @@ unix_addr(VALUE sock)
rb_io_t *fptr;
struct sockaddr_un addr;
socklen_t len = (socklen_t)sizeof addr;
+ socklen_t len0 = len;
GetOpenFile(sock, fptr);
if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
- rb_sys_fail("getsockname(2)");
+ rsock_sys_fail_path("getsockname(2)", fptr->pathv);
+ if (len0 < len) len = len0;
return rsock_unixaddr(&addr, len);
}
@@ -446,11 +519,13 @@ unix_peeraddr(VALUE sock)
rb_io_t *fptr;
struct sockaddr_un addr;
socklen_t len = (socklen_t)sizeof addr;
+ socklen_t len0 = len;
GetOpenFile(sock, fptr);
if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
- rb_sys_fail("getpeername(2)");
+ rsock_sys_fail_path("getpeername(2)", fptr->pathv);
+ if (len0 < len) len = len0;
return rsock_unixaddr(&addr, len);
}
@@ -459,7 +534,7 @@ unix_peeraddr(VALUE sock)
* UNIXSocket.pair([type [, protocol]]) => [unixsocket1, unixsocket2]
* UNIXSocket.socketpair([type [, protocol]]) => [unixsocket1, unixsocket2]
*
- * Creates a pair of sockets connected each other.
+ * Creates a pair of sockets connected to each other.
*
* _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
*