summaryrefslogtreecommitdiff
path: root/ext/socket/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/socket/socket.c')
-rw-r--r--ext/socket/socket.c1289
1 files changed, 860 insertions, 429 deletions
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index e9bdbc9e8ce..93a8aacce30 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -30,7 +30,7 @@ extern int rb_thread_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); /*
# include <GUSI.h>
#endif
-#if defined(USE_THREAD) && defined(HAVE_FCNTL)
+#if defined(HAVE_FCNTL)
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -41,44 +41,58 @@ extern int rb_thread_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); /*
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
+#ifndef HAVE_GETADDRINFO
+# include "addrinfo.h"
+#endif
+#include "sockport.h"
+
+static int do_not_reverse_lookup = 0;
VALUE rb_cBasicSocket;
-VALUE rb_cIPsocket;
-VALUE rb_cTCPsocket;
-VALUE rb_cTCPserver;
-VALUE rb_cUDPsocket;
+VALUE rb_cIPSocket;
+VALUE rb_cTCPSocket;
+VALUE rb_cTCPServer;
+VALUE rb_cUDPSocket;
#ifdef AF_UNIX
-VALUE rb_cUNIXsocket;
-VALUE rb_cUNIXserver;
+VALUE rb_cUNIXSocket;
+VALUE rb_cUNIXServer;
#endif
VALUE rb_cSocket;
static VALUE rb_eSocket;
#ifdef SOCKS
-VALUE rb_cSOCKSsocket;
+VALUE rb_cSOCKSSocket;
void SOCKSinit();
int Rconnect();
#endif
-char *strdup();
-
#define INET_CLIENT 0
#define INET_SERVER 1
#define INET_SOCKS 2
+#ifndef INET6
+# undef ss_family
+# define sockaddr_storage sockaddr
+# define ss_family sa_family
+#endif
+
#ifdef NT
static void
sock_finalize(fptr)
OpenFile *fptr;
{
SOCKET s;
+ extern int errno;
if (!fptr->f) return;
- s = fileno(fptr->f);
- free(fptr->f);
- if (fptr->f2) free(fptr->f2);
+
+ myfdclose(fptr->f);
+ if(fptr->f2) myfdclose(fptr->f);
+/*
+ s = get_osfhandle(fileno(fptr->f));
closesocket(s);
+*/
}
#endif
@@ -96,11 +110,12 @@ sock_new(class, fd)
fp->f = rb_fdopen(fd, "r");
#ifdef NT
fp->finalize = sock_finalize;
+#else
+ fd = dup(fd);
#endif
fp->f2 = rb_fdopen(fd, "w");
fp->mode = FMODE_READWRITE;
rb_io_unbuffered(fp);
- rb_obj_call_init((VALUE)sock);
return (VALUE)sock;
}
@@ -140,11 +155,11 @@ bsock_close_read(sock)
rb_secure(4);
GetOpenFile(sock, fptr);
+ shutdown(fileno(fptr->f), 0);
if (fptr->f2 == 0) {
return rb_io_close(sock);
}
- if (shutdown(fileno(fptr->f), 0) == -1)
- rb_sys_fail(0);
+ rb_thread_fd_close(fileno(fptr->f));
fptr->mode &= ~FMODE_READABLE;
#ifdef NT
free(fptr->f);
@@ -168,8 +183,7 @@ bsock_close_write(sock)
if (fptr->f2 == 0) {
return rb_io_close(sock);
}
- if (shutdown(fileno(fptr->f), 1) == -1)
- rb_sys_fail(0);
+ shutdown(fileno(fptr->f2), 1);
fptr->mode &= ~FMODE_WRITABLE;
#ifdef NT
free(fptr->f2);
@@ -290,9 +304,7 @@ bsock_send(argc, argv, sock)
f = GetWriteFile(fptr);
fd = fileno(f);
retry:
-#ifdef USE_THREAD
rb_thread_fd_writable(fd);
-#endif
m = rb_str2cstr(msg, &mlen);
if (RTEST(to)) {
t = rb_str2cstr(to, &tlen);
@@ -305,13 +317,13 @@ bsock_send(argc, argv, sock)
if (n < 0) {
switch (errno) {
case EINTR:
+ rb_thread_schedule();
+ goto retry;
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
+ rb_thread_fd_writable(fd);
goto retry;
}
rb_sys_fail("send(2)");
@@ -319,16 +331,16 @@ bsock_send(argc, argv, sock)
return INT2FIX(n);
}
-static VALUE ipaddr _((struct sockaddr_in*));
+static VALUE ipaddr _((struct sockaddr *));
#ifdef HAVE_SYS_UN_H
-static VALUE unixaddr _((struct sockaddr_un*));
+static VALUE unixaddr _((struct sockaddr_un *));
#endif
enum sock_recv_type {
RECV_RECV, /* BasicSocket#recv(no from) */
- RECV_TCP, /* TCPsocket#recvfrom */
- RECV_UDP, /* UDPsocket#recvfrom */
- RECV_UNIX, /* UNIXsocket#recvfrom */
+ RECV_TCP, /* TCPSocket#recvfrom */
+ RECV_UDP, /* UDPSocket#recvfrom */
+ RECV_UNIX, /* UNIXSocket#recvfrom */
RECV_SOCKET, /* Socket#recvfrom */
};
@@ -355,9 +367,7 @@ s_recv(sock, argc, argv, from)
GetOpenFile(sock, fptr);
fd = fileno(fptr->f);
-#ifdef USE_THREAD
rb_thread_wait_fd(fd);
-#endif
TRAP_BEG;
retry:
RSTRING(str)->len = recvfrom(fd, RSTRING(str)->ptr, RSTRING(str)->len, flags,
@@ -367,13 +377,14 @@ s_recv(sock, argc, argv, from)
if (RSTRING(str)->len < 0) {
switch (errno) {
case EINTR:
+ rb_thread_schedule();
+ goto retry;
+
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
+ rb_thread_wait_fd(fd);
goto retry;
}
rb_sys_fail("recvfrom(2)");
@@ -383,17 +394,13 @@ s_recv(sock, argc, argv, from)
case RECV_RECV:
return (VALUE)str;
case RECV_TCP:
+ case RECV_UDP:
+#if 0
if (alen != sizeof(struct sockaddr_in)) {
rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
}
- return rb_assoc_new(str, ipaddr((struct sockaddr_in *)buf));
- case RECV_UDP:
- {
- VALUE addr = ipaddr((struct sockaddr_in *)buf);
-
- return rb_assoc_new(str, rb_assoc_new(RARRAY(addr)->ptr[2],
- RARRAY(addr)->ptr[1]));
- }
+#endif
+ return rb_assoc_new(str, ipaddr((struct sockaddr *)buf));
#ifdef HAVE_SYS_UN_H
case RECV_UNIX:
return rb_assoc_new(str, unixaddr((struct sockaddr_un *)buf));
@@ -413,106 +420,206 @@ bsock_recv(argc, argv, sock)
}
static VALUE
-mkipaddr(x)
- unsigned long x;
+bsock_do_not_rev_lookup()
{
- char buf[16];
-
- x = ntohl(x);
- sprintf(buf, "%d.%d.%d.%d",
- (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
- (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
- return rb_str_new2(buf);
+ return do_not_reverse_lookup?Qtrue:Qfalse;
}
static VALUE
-ipaddr(sockaddr)
- struct sockaddr_in *sockaddr;
+bsock_do_not_rev_lookup_set(self, val)
{
- VALUE family, port, addr1, addr2;
- VALUE ary;
- struct hostent *hostent;
+ do_not_reverse_lookup = RTEST(val);
+ return val;
+}
- family = rb_str_new2("AF_INET");
- hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr,
- sizeof(sockaddr->sin_addr),
- AF_INET);
- addr1 = 0;
- if (hostent) {
- addr1 = rb_str_new2(hostent->h_name);
+static void
+mkipaddr0(addr, buf, len)
+ struct sockaddr *addr;
+ char *buf;
+ size_t len;
+{
+ int error;
+
+ error = getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0,
+ NI_NUMERICHOST);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
}
- addr2 = mkipaddr(sockaddr->sin_addr.s_addr);
- if (!addr1) addr1 = addr2;
+}
- port = INT2FIX(ntohs(sockaddr->sin_port));
- ary = rb_ary_new3(4, family, port, addr1, addr2);
+static VALUE
+mkipaddr(addr)
+ struct sockaddr *addr;
+{
+ char buf[1024];
- return ary;
+ mkipaddr0(addr, buf, sizeof(buf));
+ return rb_str_new2(buf);
}
-#ifndef HAVE_INET_ATON
-static unsigned long
-inet_aton(host, inp)
- char *host;
- struct in_addr *inp;
+static void
+mkinetaddr(host, buf, len)
+ long host;
+ char *buf;
+ size_t len;
{
- int d1, d2, d3, d4;
- char ch;
+ struct sockaddr_in sin;
+
+ MEMZERO(&sin, struct sockaddr_in, 1);
+ sin.sin_family = AF_INET;
+ SET_SIN_LEN(&sin, sizeof(sin));
+ sin.sin_addr.s_addr = host;
+ mkipaddr0((struct sockaddr *)&sin, buf, len);
+}
+
+static struct addrinfo*
+ip_addrsetup(host, port)
+ VALUE host, port;
+{
+ struct addrinfo hints, *res;
+ char *hostp, *portp;
+ int error;
+ char hbuf[1024], pbuf[16];
+
+ if (NIL_P(host)) {
+ hostp = NULL;
+ }
+ else if (rb_obj_is_kind_of(host, rb_cInteger)) {
+ long i = NUM2LONG(host);
- if (sscanf(host, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
- 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
- 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
- inp->s_addr = htonl(
- ((long) d1 << 24) | ((long) d2 << 16) |
- ((long) d3 << 8) | ((long) d4 << 0));
- return 1;
+ mkinetaddr(htonl(i), hbuf, sizeof(hbuf));
}
- return 0;
+ else {
+ char *name = STR2CSTR(host);
+
+ if (*name == 0) {
+ mkinetaddr(INADDR_ANY, hbuf, sizeof(hbuf));
+ }
+ else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
+ mkinetaddr(INADDR_BROADCAST, hbuf, sizeof(hbuf));
+ }
+ else {
+ strcpy(hbuf, name);
+ }
+ }
+ hostp = hbuf;
+ if (NIL_P(port)) {
+ portp = 0;
+ }
+ else if (FIXNUM_P(port)) {
+ snprintf(pbuf, sizeof(pbuf), "%d", FIX2INT(port));
+ portp = pbuf;
+ }
+ else {
+ portp = STR2CSTR(port);
+ }
+
+ MEMZERO(&hints, struct addrinfo, 1);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(hostp, portp, &hints, &res);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+
+ return res;
}
-#endif
static void
setipaddr(name, addr)
- char *name;
- struct sockaddr_in *addr;
+ VALUE name;
+ struct sockaddr *addr;
{
- struct hostent *hp;
+ struct addrinfo *res = ip_addrsetup(name, Qnil);
- if (name[0] == 0) {
- addr->sin_addr.s_addr = INADDR_ANY;
+ /* just take the first one */
+ memcpy(addr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+}
+
+static VALUE
+ipaddr(sockaddr)
+ struct sockaddr *sockaddr;
+{
+ VALUE family, port, addr1, addr2;
+ VALUE ary;
+ int error;
+ char hbuf[1024], pbuf[1024];
+
+ switch (sockaddr->sa_family) {
+ case AF_INET:
+ family = rb_str_new2("AF_INET");
+ break;
+#ifdef INET6
+ case AF_INET6:
+ family = rb_str_new2("AF_INET6");
+ break;
+#endif
+ default:
+ family = 0;
+ break;
}
- else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
- addr->sin_addr.s_addr = INADDR_BROADCAST;
+ if (!do_not_reverse_lookup) {
+ error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
+ NULL, 0, 0);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+ addr1 = rb_str_new2(hbuf);
}
- else if (inet_aton(name, &addr->sin_addr) != 0) {
- /* ok to set addr->sin_addr */
+ error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
+ pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
}
- else {
- hp = gethostbyname(name);
- if (!hp) {
-#ifdef HAVE_HSTRERROR
- extern int h_errno;
- rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
-#else
- rb_raise(rb_eSocket, "host not found");
-#endif
+ addr2 = rb_str_new2(hbuf);
+ if (do_not_reverse_lookup) {
+ addr1 = addr2;
+ }
+ port = INT2FIX(atoi(pbuf));
+ ary = rb_ary_new3(4, family, port, addr1, addr2);
+
+ return ary;
+}
+
+static void
+thread_write_select(fd)
+ int fd;
+{
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ rb_thread_select(fd+1, 0, &fds, 0, 0);
+}
+
+static int
+ruby_socket(domain, type, proto)
+ int domain, type, proto;
+{
+ int fd;
+
+ fd = socket(domain, type, proto);
+ if (fd < 0) {
+ if (errno == EMFILE || errno == ENFILE) {
+ rb_gc();
+ fd = socket(domain, type, proto);
}
- memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
}
+ return fd;
}
-#if defined(USE_THREAD) && defined(HAVE_FCNTL)
static int
-thread_connect(fd, sockaddr, len, type)
+ruby_connect(fd, sockaddr, len, socks)
int fd;
struct sockaddr *sockaddr;
int len;
- int type;
+ int socks;
{
int status;
int mode;
- fd_set fds;
+#if defined(HAVE_FCNTL)
mode = fcntl(fd, F_GETFL, 0);
#ifdef O_NDELAY
@@ -525,9 +632,11 @@ thread_connect(fd, sockaddr, len, type)
#endif
#endif
fcntl(fd, F_SETFL, mode|NONBLOCKING);
+#endif /* HAVE_FCNTL */
+
for (;;) {
#ifdef SOCKS
- if (type == INET_SOCKS) {
+ if (socks) {
status = Rconnect(fd, sockaddr, len);
}
else
@@ -537,151 +646,107 @@ thread_connect(fd, sockaddr, len, type)
}
if (status < 0) {
switch (errno) {
+ case EAGAIN:
#ifdef EINPROGRESS
case EINPROGRESS:
-#ifdef EAGAIN
- case EAGAIN:
#endif
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- rb_thread_select(fd+1, 0, &fds, 0, 0);
+ thread_write_select(fd);
continue;
-#endif
#ifdef EISCONN
case EISCONN:
-#endif
-#ifdef EALREADY
- case EALREADY:
-#endif
-#if defined(EISCONN) || defined(EALREADY)
status = 0;
errno = 0;
break;
#endif
}
}
+#ifdef HAVE_FCNTL
mode &= ~NONBLOCKING;
fcntl(fd, F_SETFL, mode);
+#endif
return status;
}
}
-#endif
static VALUE
open_inet(class, h, serv, type)
VALUE class, h, serv;
int type;
{
- char *host;
- struct hostent *hostent, _hostent;
- struct servent *servent, _servent;
- struct protoent *protoent;
- struct sockaddr_in sockaddr;
+ struct addrinfo hints, *res, *res0;
int fd, status;
- int hostaddr, hostaddrPtr[2];
- int servport;
char *syscall;
+ char pbuf[1024], *portp;
+ char *host;
+ int error;
if (h) {
Check_SafeStr(h);
host = RSTRING(h)->ptr;
- hostent = gethostbyname(host);
- if (hostent == NULL) {
- if (!inet_aton(host, &sockaddr.sin_addr)) {
- if (type == INET_SERVER && !strlen(host))
- hostaddr = INADDR_ANY;
- else {
-#ifdef HAVE_HSTRERROR
- extern int h_errno;
- rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
-#else
- rb_raise(rb_eSocket, "host not found");
-#endif
- }
- }
- hostaddr = sockaddr.sin_addr.s_addr;
- _hostent.h_addr_list = (char **)hostaddrPtr;
- _hostent.h_addr_list[0] = (char *)&hostaddr;
- _hostent.h_addr_list[1] = NULL;
- _hostent.h_length = sizeof(hostaddr);
- _hostent.h_addrtype = AF_INET;
- hostent = &_hostent;
- }
- }
- servent = NULL;
- if (FIXNUM_P(serv)) {
- servport = FIX2UINT(serv);
- goto setup_servent;
- }
- servent = getservbyname(STR2CSTR(serv), "tcp");
- if (servent == NULL) {
- char *s = STR2CSTR(serv);
- char *end;
-
- servport = strtoul(s, &end, 0);
- if (*end != '\0') {
- rb_raise(rb_eSocket, "no such servce %s", s);
- }
- setup_servent:
- _servent.s_port = htons(servport);
- _servent.s_proto = "tcp";
- servent = &_servent;
}
-#ifdef __BEOS__
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-#else
- protoent = getprotobyname(servent->s_proto);
- if (protoent == NULL) {
- rb_raise(rb_eSocket, "no such proto %s", servent->s_proto);
+ else {
+ host = NULL;
}
-
- fd = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
-#endif
-
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sin_family = AF_INET;
- if (h) {
- memcpy((char *)&(sockaddr.sin_addr.s_addr),
- (char *) hostent->h_addr_list[0],
- (size_t) hostent->h_length);
+ if (FIXNUM_P(serv)) {
+ snprintf(pbuf, sizeof(pbuf), "%d", FIX2UINT(serv));
+ portp = pbuf;
}
else {
- sockaddr.sin_addr.s_addr = INADDR_ANY;
+ strcpy(pbuf, STR2CSTR(serv));
+ portp = pbuf;
}
- sockaddr.sin_port = servent->s_port;
-
+ MEMZERO(&hints, struct addrinfo, 1);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
if (type == INET_SERVER) {
- status = 1;
- setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&status,sizeof(status));
- status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
- syscall = "bind(2)";
+ hints.ai_flags = AI_PASSIVE;
}
- else {
-#if defined(USE_THREAD) && defined(HAVE_FCNTL)
- status = thread_connect(fd, (struct sockaddr*)&sockaddr,
- sizeof(sockaddr), type);
-#else
-#ifdef SOCKS
- if (type == INET_SOCKS) {
- status = Rconnect(fd, &sockaddr, sizeof(sockaddr));
+ error = getaddrinfo(host, portp, &hints, &res0);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+
+ fd = -1;
+ for (res = res0; res; res = res->ai_next) {
+ status = ruby_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
+ syscall = "socket(2)";
+ fd = status;
+ if (fd < 0) {
+ continue;
}
- else
-#endif
- {
- status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ if (type == INET_SERVER) {
+ status = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char*)&status, sizeof(status));
+ status = bind(fd, res->ai_addr, res->ai_addrlen);
+ syscall = "bind(2)";
+ }
+ else {
+ status = ruby_connect(fd, res->ai_addr, res->ai_addrlen,
+ (type == INET_SOCKS));
+ syscall = "connect(2)";
}
-#endif
- syscall = "connect(2)";
- }
+ if (status < 0) {
+ close(fd);
+ fd = -1;
+ continue;
+ } else
+ break;
+ }
if (status < 0) {
- close(fd);
+ if (fd >= 0)
+ close(fd);
+ freeaddrinfo(res0);
rb_sys_fail(syscall);
}
- if (type == INET_SERVER) listen(fd, 5);
+
+ if (type == INET_SERVER)
+ listen(fd, 5);
/* create new instance */
+ freeaddrinfo(res0);
return sock_new(class, fd);
}
@@ -710,24 +775,60 @@ socks_s_open(class, host, serv)
}
#endif
+/*
+ * NOTE: using gethostbyname() against AF_INET6 is a bad idea, as it
+ * does not initialize sin_flowinfo nor sin_scope_id properly.
+ */
static VALUE
tcp_s_gethostbyname(obj, host)
VALUE obj, host;
{
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
struct hostent *h;
char **pch;
VALUE ary, names;
- setipaddr(STR2CSTR(host), &addr);
- h = gethostbyaddr((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET);
+ if (rb_obj_is_kind_of(host, rb_cInteger)) {
+ long i = NUM2LONG(host);
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)&addr;
+ MEMZERO(sin, struct sockaddr_in, 1);
+ sin->sin_family = AF_INET;
+ SET_SIN_LEN(sin, sizeof(*sin));
+ sin->sin_addr.s_addr = htonl(i);
+ }
+ else {
+ setipaddr(host, &addr);
+ }
+ switch (addr.ss_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)&addr;
+ h = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof(sin->sin_addr),
+ sin->sin_family);
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+ sin6 = (struct sockaddr_in6 *)&addr;
+ h = gethostbyaddr((char *)&sin6->sin6_addr,
+ sizeof(sin6->sin6_addr),
+ sin6->sin6_family);
+ break;
+ }
+#endif
+ default:
+ h = NULL;
+ }
if (h == NULL) {
-#ifdef HAVE_HSTRERROR
+#ifdef HAVE_HSTERROR
extern int h_errno;
- rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
+ rb_raise(rb_eSocket, "%s", (char *)hsterror(h_errno));
#else
rb_raise(rb_eSocket, "host not found");
#endif
@@ -739,15 +840,45 @@ tcp_s_gethostbyname(obj, host)
for (pch = h->h_aliases; *pch; pch++) {
rb_ary_push(names, rb_str_new2(*pch));
}
- rb_ary_push(ary, NUM2INT(h->h_addrtype));
+ rb_ary_push(ary, INT2NUM(h->h_addrtype));
#ifdef h_addr
for (pch = h->h_addr_list; *pch; pch++) {
- memcpy((char *) &addr.sin_addr, *pch, h->h_length);
- rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr));
+ switch (addr.ss_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in sin;
+ MEMZERO(&sin, struct sockaddr_in, 1);
+ sin.sin_family = AF_INET;
+ SET_SIN_LEN(&sin, sizeof(sin));
+ memcpy((char *) &sin.sin_addr, *pch, h->h_length);
+ h = gethostbyaddr((char *)&sin.sin_addr,
+ sizeof(sin.sin_addr),
+ sin.sin_family);
+ rb_ary_push(ary, mkipaddr((struct sockaddr *)&sin));
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6;
+ MEMZERO(&sin6, struct sockaddr_in6, 1);
+ sin6.sin6_family = AF_INET;
+ sin6.sin6_len = sizeof(sin6);
+ memcpy((char *) &sin6.sin6_addr, *pch, h->h_length);
+ h = gethostbyaddr((char *)&sin6.sin6_addr,
+ sizeof(sin6.sin6_addr),
+ sin6.sin6_family);
+ rb_ary_push(ary, mkipaddr((struct sockaddr *)&sin6));
+ break;
+ }
+#endif
+ default:
+ h = NULL;
+ }
}
#else
memcpy((char *)&addr.sin_addr, h->h_addr, h->h_length);
- rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr));
+ rb_ary_push(ary, mkipaddr((struct sockaddr *)&addr));
#endif
return ary;
@@ -777,22 +908,21 @@ s_accept(class, fd, sockaddr, len)
int fd2;
retry:
-#ifdef USE_THREAD
rb_thread_wait_fd(fd);
-#endif
TRAP_BEG;
fd2 = accept(fd, sockaddr, len);
TRAP_END;
if (fd2 < 0) {
switch (errno) {
case EINTR:
+ rb_thread_schedule();
+ goto retry;
+
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
+ rb_thread_wait_fd(fd);
goto retry;
}
rb_sys_fail(0);
@@ -805,12 +935,12 @@ tcp_accept(sock)
VALUE sock;
{
OpenFile *fptr;
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int fromlen;
GetOpenFile(sock, fptr);
- fromlen = sizeof(struct sockaddr_in);
- return s_accept(rb_cTCPsocket, fileno(fptr->f),
+ fromlen = sizeof(from);
+ return s_accept(rb_cTCPSocket, fileno(fptr->f),
(struct sockaddr*)&from, &fromlen);
}
@@ -836,10 +966,12 @@ open_unix(class, path, server)
OpenFile *fptr;
Check_SafeStr(path);
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) rb_sys_fail("socket(2)");
+ fd = ruby_socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ rb_sys_fail("socket(2)");
+ }
- memset(&sockaddr, 0, sizeof(sockaddr));
+ MEMZERO(&sockaddr, struct sockaddr_un, 1);
sockaddr.sun_family = AF_UNIX;
strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1);
sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0';
@@ -848,7 +980,7 @@ open_unix(class, path, server)
status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
}
else {
- status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ status = ruby_connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr), 0);
}
if (status < 0) {
@@ -871,14 +1003,14 @@ ip_addr(sock)
VALUE sock;
{
OpenFile *fptr;
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
int len = sizeof addr;
GetOpenFile(sock, fptr);
if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0)
rb_sys_fail("getsockname(2)");
- return ipaddr(&addr);
+ return ipaddr((struct sockaddr *)&addr);
}
static VALUE
@@ -886,106 +1018,67 @@ ip_peeraddr(sock)
VALUE sock;
{
OpenFile *fptr;
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
int len = sizeof addr;
GetOpenFile(sock, fptr);
if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0)
rb_sys_fail("getpeername(2)");
- return ipaddr(&addr);
+ return ipaddr((struct sockaddr *)&addr);
}
static VALUE
ip_s_getaddress(obj, host)
VALUE obj, host;
{
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
- if (rb_obj_is_kind_of(host, rb_cInteger)) {
- int i = NUM2INT(host);
- addr.sin_addr.s_addr = htonl(i);
- }
- else {
- setipaddr(STR2CSTR(host), &addr);
- }
-
- return mkipaddr(addr.sin_addr.s_addr);
+ setipaddr(host, &addr);
+ return mkipaddr((struct sockaddr *)&addr);
}
static VALUE
-udp_s_open(class)
+udp_s_open(argc, argv, class)
+ int argc;
+ VALUE *argv;
VALUE class;
{
- return sock_new(class, socket(AF_INET, SOCK_DGRAM, 0));
-}
+ VALUE arg;
+ int socktype = AF_INET;
+ int fd;
-static void
-udp_addrsetup(host, port, addr)
- VALUE host, port;
- struct sockaddr_in *addr;
-{
- memset(addr, 0, sizeof(struct sockaddr_in));
- addr->sin_family = AF_INET;
- if (NIL_P(host)) {
- addr->sin_addr.s_addr = INADDR_ANY;
- }
- else if (rb_obj_is_kind_of(host, rb_cInteger)) {
- int i = NUM2INT(host);
- addr->sin_addr.s_addr = htonl(i);
- }
- else {
- setipaddr(STR2CSTR(host), addr);
+ if (rb_scan_args(argc, argv, "01", &arg) == 1) {
+ socktype = NUM2INT(arg);
}
- if (FIXNUM_P(port)) {
- addr->sin_port = htons(FIX2INT(port));
+ fd = ruby_socket(socktype, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ rb_sys_fail("socket(2) - udp");
}
- else {
- struct servent *servent;
- servent = getservbyname(STR2CSTR(port), "udp");
- if (servent) {
- addr->sin_port = servent->s_port;
- }
- else {
- char *s = STR2CSTR(port);
- char *end;
- int portno;
-
- portno = strtoul(s, &end, 0);
- if (*end != '\0') {
- rb_raise(rb_eSocket, "no such servce %s", s);
- }
- addr->sin_port = htons(port);
- }
- }
+ return sock_new(class, fd);
}
static VALUE
udp_connect(sock, host, port)
VALUE sock, host, port;
{
- struct sockaddr_in addr;
OpenFile *fptr;
+ int fd;
+ struct addrinfo *res0, *res;
- udp_addrsetup(host, port, &addr);
GetOpenFile(sock, fptr);
- retry:
- if (connect(fileno(fptr->f), (struct sockaddr*)&addr, sizeof(addr))<0) {
- switch (errno) {
- case EINTR:
- case EWOULDBLOCK:
-#if EAGAIN != EWOULDBLOCK
- case EAGAIN:
-#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
- goto retry;
+ fd = fileno(fptr->f);
+ res0 = ip_addrsetup(host, port);
+ for (res = res0; res; res = res->ai_next) {
+ if (ruby_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
+ freeaddrinfo(res0);
+ return INT2FIX(0);
}
- rb_sys_fail("connect(2)");
}
+ freeaddrinfo(res0);
+ rb_sys_fail("connect(2)");
return INT2FIX(0);
}
@@ -993,14 +1086,20 @@ static VALUE
udp_bind(sock, host, port)
VALUE sock, host, port;
{
- struct sockaddr_in addr;
OpenFile *fptr;
+ struct addrinfo *res0, *res;
- udp_addrsetup(host, port, &addr);
GetOpenFile(sock, fptr);
- if (bind(fileno(fptr->f), (struct sockaddr*)&addr, sizeof(addr))<0) {
- rb_sys_fail("bind(2)");
+ res0 = ip_addrsetup(host, port);
+ for (res = res0; res; res = res->ai_next) {
+ if (bind(fileno(fptr->f), res->ai_addr, res->ai_addrlen) < 0) {
+ continue;
+ }
+ freeaddrinfo(res0);
+ return INT2FIX(0);
}
+ freeaddrinfo(res0);
+ rb_sys_fail("bind(2)");
return INT2FIX(0);
}
@@ -1011,39 +1110,45 @@ udp_send(argc, argv, sock)
VALUE sock;
{
VALUE mesg, flags, host, port;
- struct sockaddr_in addr;
OpenFile *fptr;
FILE *f;
int n;
char *m;
int mlen;
+ struct addrinfo *res0, *res;
if (argc == 2) {
return bsock_send(argc, argv, sock);
}
rb_scan_args(argc, argv, "4", &mesg, &flags, &host, &port);
- udp_addrsetup(host, port, &addr);
GetOpenFile(sock, fptr);
+ res0 = ip_addrsetup(host, port);
f = GetWriteFile(fptr);
m = rb_str2cstr(mesg, &mlen);
+ for (res = res0; res; res = res->ai_next) {
retry:
- n = sendto(fileno(f), m, mlen, NUM2INT(flags),
- (struct sockaddr*)&addr, sizeof(addr));
- if (n < 0) {
+ n = sendto(fileno(f), m, mlen, NUM2INT(flags), res->ai_addr,
+ res->ai_addrlen);
+ if (n >= 0) {
+ freeaddrinfo(res0);
+ return INT2FIX(n);
+ }
switch (errno) {
case EINTR:
+ rb_thread_schedule();
+ goto retry;
+
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
+ thread_write_select(fileno(f));
goto retry;
}
- rb_sys_fail("sendto(2)");
}
+ freeaddrinfo(res0);
+ rb_sys_fail("sendto(2)");
return INT2FIX(n);
}
@@ -1107,7 +1212,7 @@ unix_accept(sock)
GetOpenFile(sock, fptr);
fromlen = sizeof(struct sockaddr_un);
- return s_accept(rb_cUNIXsocket, fileno(fptr->f),
+ return s_accept(rb_cUNIXSocket, fileno(fptr->f),
(struct sockaddr*)&from, &fromlen);
}
@@ -1242,7 +1347,7 @@ sock_s_open(class, domain, type, protocol)
int d, t;
setup_domain_and_type(domain, &d, type, &t);
- fd = socket(d, t, NUM2INT(protocol));
+ fd = ruby_socket(d, t, NUM2INT(protocol));
if (fd < 0) rb_sys_fail("socket(2)");
return sock_new(class, fd);
@@ -1259,12 +1364,18 @@ static VALUE
sock_s_socketpair(class, domain, type, protocol)
VALUE class, domain, type, protocol;
{
-#if !defined(NT) && !defined(__BEOS__)
+#if !defined(NT) && !defined(__BEOS__) && !defined(__EMX__)
int d, t, sp[2];
setup_domain_and_type(domain, &d, type, &t);
- if (socketpair(d, t, NUM2INT(protocol), sp) < 0)
+ again:
+ if (socketpair(d, t, NUM2INT(protocol), sp) < 0) {
+ if (errno == EMFILE || errno == ENFILE) {
+ rb_gc();
+ goto again;
+ }
rb_sys_fail("socketpair(2)");
+ }
return rb_assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1]));
#else
@@ -1277,24 +1388,14 @@ sock_connect(sock, addr)
VALUE sock, addr;
{
OpenFile *fptr;
+ int fd;
Check_Type(addr, T_STRING);
rb_str_modify(addr);
GetOpenFile(sock, fptr);
- retry:
- if (connect(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0) {
- switch (errno) {
- case EINTR:
- case EWOULDBLOCK:
-#if EAGAIN != EWOULDBLOCK
- case EAGAIN:
-#endif
-#ifdef USE_THREAD
- rb_thread_schedule();
-#endif
- goto retry;
- }
+ fd = fileno(fptr->f);
+ if (ruby_connect(fd, (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len, 0) < 0) {
rb_sys_fail("connect(2)");
}
@@ -1344,7 +1445,7 @@ sock_accept(sock)
VALUE sock;
{
OpenFile *fptr;
- VALUE addr, sock2;
+ VALUE sock2;
char buf[1024];
int len = sizeof buf;
@@ -1401,7 +1502,7 @@ mkhostent(h)
if (h == NULL) {
#ifdef HAVE_HSTRERROR
extern int h_errno;
- rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
+ rb_raise(rb_eSocket, "%s", (char *)hstrerror(h_errno));
#else
rb_raise(rb_eSocket, "host not found");
#endif
@@ -1413,7 +1514,7 @@ mkhostent(h)
for (pch = h->h_aliases; *pch; pch++) {
rb_ary_push(names, rb_str_new2(*pch));
}
- rb_ary_push(ary, NUM2INT(h->h_addrtype));
+ rb_ary_push(ary, INT2NUM(h->h_addrtype));
#ifdef h_addr
for (pch = h->h_addr_list; *pch; pch++) {
rb_ary_push(ary, rb_str_new(*pch, h->h_length));
@@ -1426,22 +1527,73 @@ mkhostent(h)
}
static VALUE
+mkaddrinfo(res0)
+ struct addrinfo *res0;
+{
+ VALUE base, ary;
+ struct addrinfo *res;
+
+ if (res0 == NULL) {
+ rb_raise(rb_eSocket, "host not found");
+ }
+ base = rb_ary_new();
+ for (res = res0; res; res = res->ai_next) {
+ ary = ipaddr(res->ai_addr);
+ rb_ary_push(ary, INT2FIX(res->ai_family));
+ rb_ary_push(ary, INT2FIX(res->ai_socktype));
+ rb_ary_push(ary, INT2FIX(res->ai_protocol));
+ rb_ary_push(base, ary);
+ }
+ return base;
+}
+
+/*
+ * NOTE: using gethostbyname() against AF_INET6 is a bad idea, as it
+ * does not initialize sin_flowinfo nor sin_scope_id properly.
+ */
+static VALUE
sock_s_gethostbyname(obj, host)
VALUE obj, host;
{
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
struct hostent *h;
if (rb_obj_is_kind_of(host, rb_cInteger)) {
- int i = NUM2INT(host);
- addr.sin_addr.s_addr = htonl(i);
+ long i = NUM2LONG(host);
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)&addr;
+ MEMZERO(sin, struct sockaddr_in, 1);
+ sin->sin_family = AF_INET;
+ SET_SIN_LEN(sin, sizeof(*sin));
+ sin->sin_addr.s_addr = htonl(i);
}
else {
- setipaddr(STR2CSTR(host), &addr);
+ setipaddr(host, (struct sockaddr *)&addr);
+ }
+ switch (addr.ss_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)&addr;
+ h = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof(sin->sin_addr),
+ sin->sin_family);
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+ sin6 = (struct sockaddr_in6 *)&addr;
+ h = gethostbyaddr((char *)&sin6->sin6_addr,
+ sizeof(sin6->sin6_addr),
+ sin6->sin6_family);
+ break;
+ }
+#endif
+ default:
+ h = NULL;
}
- h = gethostbyaddr((char *)&addr.sin_addr,
- sizeof(addr.sin_addr),
- AF_INET);
return mkhostent(h);
}
@@ -1502,10 +1654,172 @@ sock_s_getservbyaname(argc, argv)
return INT2FIX(port);
}
+static VALUE
+sock_s_getaddrinfo(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE host, port, family, socktype, protocol, flags, ret;
+ char hbuf[1024], pbuf[1024];
+ char *hptr, *pptr;
+ struct addrinfo hints, *res;
+ int error;
+
+ host = port = family = socktype = protocol = flags = Qnil;
+ rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol,
+ &flags);
+ if (NIL_P(host)) {
+ hptr = NULL;
+ }
+ else {
+ strncpy(hbuf, STR2CSTR(host), sizeof(hbuf));
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ hptr = hbuf;
+ }
+ if (NIL_P(port)) {
+ pptr = NULL;
+ }
+ else if (FIXNUM_P(port)) {
+ snprintf(pbuf, sizeof(pbuf), "%d", FIX2INT(port));
+ pptr = pbuf;
+ }
+ else {
+ strncpy(pbuf, STR2CSTR(port), sizeof(pbuf));
+ pbuf[sizeof(pbuf) - 1] = '\0';
+ pptr = pbuf;
+ }
+
+ MEMZERO(&hints, struct addrinfo, 1);
+ if (!NIL_P(family)) {
+ hints.ai_family = NUM2INT(family);
+ }
+ else {
+ hints.ai_family = PF_UNSPEC;
+ }
+ if (!NIL_P(socktype)) {
+ hints.ai_socktype = NUM2INT(socktype);
+ }
+ if (!NIL_P(protocol)) {
+ hints.ai_protocol = NUM2INT(protocol);
+ }
+ if (!NIL_P(flags)) {
+ hints.ai_flags = NUM2INT(flags);
+ }
+ error = getaddrinfo(hptr, pptr, &hints, &res);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+
+ ret = mkaddrinfo(res);
+ freeaddrinfo(res);
+ return ret;
+}
+
+static VALUE
+sock_s_getnameinfo(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE sa, af, host, port, flags;
+ static char hbuf[1024], pbuf[1024];
+ char *hptr, *pptr;
+ int fl;
+ struct addrinfo hints, *res = NULL;
+ int error;
+ struct sockaddr_storage ss;
+ struct sockaddr *sap;
+
+ sa = flags = Qnil;
+ rb_scan_args(argc, argv, "11", &sa, &flags);
+
+ if (TYPE(sa) == T_STRING) {
+ if (sizeof(ss) < RSTRING(sa)->len) {
+ rb_raise(rb_eTypeError, "sockaddr length too big");
+ }
+ memcpy(&ss, RSTRING(sa)->ptr, RSTRING(sa)->len);
+ if (RSTRING(sa)->len != SA_LEN((struct sockaddr *)&ss)) {
+ rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
+ }
+ sap = (struct sockaddr *)&ss;
+ }
+ else if (TYPE(sa) == T_ARRAY) {
+ if (RARRAY(sa)->len == 3) {
+ af = RARRAY(sa)->ptr[0];
+ port = RARRAY(sa)->ptr[1];
+ host = RARRAY(sa)->ptr[2];
+ }
+ else if (RARRAY(sa)->len >= 4) {
+ af = RARRAY(sa)->ptr[0];
+ port = RARRAY(sa)->ptr[1];
+ host = RARRAY(sa)->ptr[3];
+ if (NIL_P(host)) {
+ host = RARRAY(sa)->ptr[2];
+ }
+ }
+ if (NIL_P(host)) {
+ hptr = NULL;
+ }
+ else {
+ strncpy(hbuf, STR2CSTR(host), sizeof(hbuf));
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ hptr = hbuf;
+ }
+ if (NIL_P(port)) {
+ strcpy(pbuf, "0");
+ pptr = NULL;
+ }
+ else if (!NIL_P(port)) {
+ snprintf(pbuf, sizeof(pbuf), "%d", NUM2INT(port));
+ pptr = pbuf;
+ }
+ else {
+ strncpy(pbuf, STR2CSTR(port), sizeof(pbuf));
+ pbuf[sizeof(pbuf) - 1] = '\0';
+ pptr = pbuf;
+ }
+ MEMZERO(&hints, struct addrinfo, 1);
+ if (strcmp(STR2CSTR(af), "AF_INET") == 0) {
+ hints.ai_family = PF_INET;
+ }
+#ifdef INET6
+ else if (strcmp(STR2CSTR(af), "AF_INET6") == 0) {
+ hints.ai_family = PF_INET6;
+ }
+#endif
+ else {
+ hints.ai_family = PF_UNSPEC;
+ }
+ error = getaddrinfo(hptr, pptr, &hints, &res);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+ sap = res->ai_addr;
+ }
+ else {
+ rb_raise(rb_eTypeError, "expecting String or Array");
+ }
+
+ fl = 0;
+ if (!NIL_P(flags)) {
+ fl = NUM2INT(flags);
+ }
+
+ gotsap:
+ error = getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
+ pbuf, sizeof(pbuf), fl);
+ if (error) {
+ rb_raise(rb_eSocket, "%s", gai_strerror(error));
+ }
+ if (res)
+ freeaddrinfo(res);
+
+ return rb_ary_new3(2, rb_str_new2(hbuf), rb_str_new2(pbuf));
+}
+
static VALUE mConst;
static void
-sock_rb_define_const(name, value)
+sock_define_const(name, value)
char *name;
int value;
{
@@ -1513,6 +1827,7 @@ sock_rb_define_const(name, value)
rb_define_const(mConst, name, INT2FIX(value));
}
+void
Init_socket()
{
rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
@@ -1520,6 +1835,12 @@ Init_socket()
rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO);
rb_undef_method(CLASS_OF(rb_cBasicSocket), "new");
rb_undef_method(CLASS_OF(rb_cBasicSocket), "open");
+
+ rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup",
+ bsock_do_not_rev_lookup, 0);
+ rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=",
+ bsock_do_not_rev_lookup_set, 1);
+
rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0);
rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0);
rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1);
@@ -1530,49 +1851,56 @@ Init_socket()
rb_define_method(rb_cBasicSocket, "send", bsock_send, -1);
rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
- rb_cIPsocket = rb_define_class("IPsocket", rb_cBasicSocket);
- rb_define_method(rb_cIPsocket, "addr", ip_addr, 0);
- rb_define_method(rb_cIPsocket, "peeraddr", ip_peeraddr, 0);
- rb_define_singleton_method(rb_cIPsocket, "getaddress", ip_s_getaddress, 1);
+ rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
+ rb_define_global_const("IPsocket", rb_cIPSocket);
+ rb_define_method(rb_cIPSocket, "addr", ip_addr, 0);
+ rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, 0);
+ rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1);
- rb_cTCPsocket = rb_define_class("TCPsocket", rb_cIPsocket);
- rb_define_singleton_method(rb_cTCPsocket, "open", tcp_s_open, 2);
- rb_define_singleton_method(rb_cTCPsocket, "new", tcp_s_open, 2);
- rb_define_singleton_method(rb_cTCPsocket, "gethostbyname", tcp_s_gethostbyname, 1);
- rb_define_method(rb_cTCPsocket, "recvfrom", tcp_recvfrom, -1);
+ rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket);
+ rb_define_global_const("TCPsocket", rb_cTCPSocket);
+ rb_define_singleton_method(rb_cTCPSocket, "open", tcp_s_open, 2);
+ rb_define_singleton_method(rb_cTCPSocket, "new", tcp_s_open, 2);
+ rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1);
+ rb_define_method(rb_cTCPSocket, "recvfrom", tcp_recvfrom, -1);
#ifdef SOCKS
- rb_cSOCKSsocket = rb_define_class("SOCKSsocket", rb_cTCPsocket);
- rb_define_singleton_method(rb_cSOCKSsocket, "open", socks_s_open, 2);
- rb_define_singleton_method(rb_cSOCKSsocket, "new", socks_s_open, 2);
-#endif
-
- rb_cTCPserver = rb_define_class("TCPserver", rb_cTCPsocket);
- rb_define_singleton_method(rb_cTCPserver, "open", tcp_svr_s_open, -1);
- rb_define_singleton_method(rb_cTCPserver, "new", tcp_svr_s_open, -1);
- rb_define_method(rb_cTCPserver, "accept", tcp_accept, 0);
-
- rb_cUDPsocket = rb_define_class("UDPsocket", rb_cIPsocket);
- rb_define_singleton_method(rb_cUDPsocket, "open", udp_s_open, 0);
- rb_define_singleton_method(rb_cUDPsocket, "new", udp_s_open, 0);
- 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", udp_recvfrom, -1);
+ rb_cSOCKSSocket = rb_define_class("SOCKSSocket", rb_cTCPSocket);
+ rb_define_global_const("SOCKSsocket", rb_cSOCKSSocket);
+ rb_define_singleton_method(rb_cSOCKSSocket, "open", socks_s_open, 2);
+ rb_define_singleton_method(rb_cSOCKSSocket, "new", socks_s_open, 2);
+#endif
+
+ rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
+ rb_define_global_const("TCPserver", rb_cTCPServer);
+ rb_define_singleton_method(rb_cTCPServer, "open", tcp_svr_s_open, -1);
+ rb_define_singleton_method(rb_cTCPServer, "new", tcp_svr_s_open, -1);
+ rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
+
+ rb_cUDPSocket = rb_define_class("UDPSocket", rb_cIPSocket);
+ rb_define_global_const("UDPsocket", rb_cUDPSocket);
+ rb_define_singleton_method(rb_cUDPSocket, "open", udp_s_open, -1);
+ rb_define_singleton_method(rb_cUDPSocket, "new", udp_s_open, -1);
+ 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", udp_recvfrom, -1);
#ifdef HAVE_SYS_UN_H
- rb_cUNIXsocket = rb_define_class("UNIXsocket", rb_cBasicSocket);
- rb_define_singleton_method(rb_cUNIXsocket, "open", unix_s_sock_open, 1);
- rb_define_singleton_method(rb_cUNIXsocket, "new", unix_s_sock_open, 1);
- rb_define_method(rb_cUNIXsocket, "path", unix_path, 0);
- rb_define_method(rb_cUNIXsocket, "addr", unix_addr, 0);
- rb_define_method(rb_cUNIXsocket, "peeraddr", unix_peeraddr, 0);
- rb_define_method(rb_cUNIXsocket, "recvfrom", unix_recvfrom, -1);
-
- rb_cUNIXserver = rb_define_class("UNIXserver", rb_cUNIXsocket);
- rb_define_singleton_method(rb_cUNIXserver, "open", unix_svr_s_open, 1);
- rb_define_singleton_method(rb_cUNIXserver, "new", unix_svr_s_open, 1);
- rb_define_method(rb_cUNIXserver, "accept", unix_accept, 0);
+ rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
+ rb_define_global_const("UNIXsocket", rb_cUNIXSocket);
+ rb_define_singleton_method(rb_cUNIXSocket, "open", unix_s_sock_open, 1);
+ rb_define_singleton_method(rb_cUNIXSocket, "new", unix_s_sock_open, 1);
+ rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
+ rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
+ rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
+ rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
+
+ rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
+ rb_define_global_const("UNIXserver", rb_cUNIXServer);
+ rb_define_singleton_method(rb_cUNIXServer, "open", unix_svr_s_open, 1);
+ rb_define_singleton_method(rb_cUNIXServer, "new", unix_svr_s_open, 1);
+ rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
#endif
rb_cSocket = rb_define_class("Socket", rb_cBasicSocket);
@@ -1593,152 +1921,255 @@ Init_socket()
rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1);
rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1);
rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyaname, -1);
+ rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1);
+ rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1);
/* constants */
mConst = rb_define_module_under(rb_cSocket, "Constants");
- sock_rb_define_const("SOCK_STREAM", SOCK_STREAM);
- sock_rb_define_const("SOCK_DGRAM", SOCK_DGRAM);
+ sock_define_const("SOCK_STREAM", SOCK_STREAM);
+ sock_define_const("SOCK_DGRAM", SOCK_DGRAM);
#ifdef SOCK_RAW
- sock_rb_define_const("SOCK_RAW", SOCK_RAW);
+ sock_define_const("SOCK_RAW", SOCK_RAW);
#endif
#ifdef SOCK_RDM
- sock_rb_define_const("SOCK_RDM", SOCK_RDM);
+ sock_define_const("SOCK_RDM", SOCK_RDM);
#endif
#ifdef SOCK_SEQPACKET
- sock_rb_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET);
+ sock_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET);
#endif
#ifdef SOCK_PACKET
- sock_rb_define_const("SOCK_PACKET", SOCK_PACKET);
+ sock_define_const("SOCK_PACKET", SOCK_PACKET);
#endif
- sock_rb_define_const("AF_INET", AF_INET);
+ sock_define_const("AF_INET", AF_INET);
#ifdef PF_INET
- sock_rb_define_const("PF_INET", PF_INET);
+ sock_define_const("PF_INET", PF_INET);
#endif
#ifdef AF_UNIX
- sock_rb_define_const("AF_UNIX", AF_UNIX);
- sock_rb_define_const("PF_UNIX", PF_UNIX);
+ sock_define_const("AF_UNIX", AF_UNIX);
+ sock_define_const("PF_UNIX", PF_UNIX);
#endif
#ifdef AF_AX25
- sock_rb_define_const("AF_AX25", AF_AX25);
- sock_rb_define_const("PF_AX25", PF_AX25);
+ sock_define_const("AF_AX25", AF_AX25);
+ sock_define_const("PF_AX25", PF_AX25);
#endif
#ifdef AF_IPX
- sock_rb_define_const("AF_IPX", AF_IPX);
- sock_rb_define_const("PF_IPX", PF_IPX);
+ sock_define_const("AF_IPX", AF_IPX);
+ sock_define_const("PF_IPX", PF_IPX);
#endif
#ifdef AF_APPLETALK
- sock_rb_define_const("AF_APPLETALK", AF_APPLETALK);
- sock_rb_define_const("PF_APPLETALK", PF_APPLETALK);
+ sock_define_const("AF_APPLETALK", AF_APPLETALK);
+ sock_define_const("PF_APPLETALK", PF_APPLETALK);
+#endif
+#ifdef AF_UNSPEC
+ sock_define_const("AF_UNSPEC", AF_UNSPEC);
+ sock_define_const("PF_UNSPEC", PF_UNSPEC);
+#endif
+#ifdef AF_INET6
+ sock_define_const("AF_INET6", AF_INET6);
+#endif
+#ifdef PF_INET6
+ sock_define_const("PF_INET6", PF_INET6);
#endif
- sock_rb_define_const("MSG_OOB", MSG_OOB);
+ sock_define_const("MSG_OOB", MSG_OOB);
#ifdef MSG_PEEK
- sock_rb_define_const("MSG_PEEK", MSG_PEEK);
+ sock_define_const("MSG_PEEK", MSG_PEEK);
#endif
#ifdef MSG_DONTROUTE
- sock_rb_define_const("MSG_DONTROUTE", MSG_DONTROUTE);
+ sock_define_const("MSG_DONTROUTE", MSG_DONTROUTE);
#endif
- sock_rb_define_const("SOL_SOCKET", SOL_SOCKET);
+ sock_define_const("SOL_SOCKET", SOL_SOCKET);
#ifdef SOL_IP
- sock_rb_define_const("SOL_IP", SOL_IP);
+ sock_define_const("SOL_IP", SOL_IP);
#endif
#ifdef SOL_IPX
- sock_rb_define_const("SOL_IPX", SOL_IPX);
+ sock_define_const("SOL_IPX", SOL_IPX);
#endif
#ifdef SOL_AX25
- sock_rb_define_const("SOL_AX25", SOL_AX25);
+ sock_define_const("SOL_AX25", SOL_AX25);
#endif
#ifdef SOL_ATALK
- sock_rb_define_const("SOL_ATALK", SOL_ATALK);
+ sock_define_const("SOL_ATALK", SOL_ATALK);
#endif
#ifdef SOL_TCP
- sock_rb_define_const("SOL_TCP", SOL_TCP);
+ sock_define_const("SOL_TCP", SOL_TCP);
#endif
#ifdef SOL_UDP
- sock_rb_define_const("SOL_UDP", SOL_UDP);
+ sock_define_const("SOL_UDP", SOL_UDP);
#endif
#ifdef SO_DEBUG
- sock_rb_define_const("SO_DEBUG", SO_DEBUG);
+ sock_define_const("SO_DEBUG", SO_DEBUG);
#endif
- sock_rb_define_const("SO_REUSEADDR", SO_REUSEADDR);
+ sock_define_const("SO_REUSEADDR", SO_REUSEADDR);
#ifdef SO_TYPE
- sock_rb_define_const("SO_TYPE", SO_TYPE);
+ sock_define_const("SO_TYPE", SO_TYPE);
#endif
#ifdef SO_ERROR
- sock_rb_define_const("SO_ERROR", SO_ERROR);
+ sock_define_const("SO_ERROR", SO_ERROR);
#endif
#ifdef SO_DONTROUTE
- sock_rb_define_const("SO_DONTROUTE", SO_DONTROUTE);
+ sock_define_const("SO_DONTROUTE", SO_DONTROUTE);
#endif
#ifdef SO_BROADCAST
- sock_rb_define_const("SO_BROADCAST", SO_BROADCAST);
+ sock_define_const("SO_BROADCAST", SO_BROADCAST);
#endif
#ifdef SO_SNDBUF
- sock_rb_define_const("SO_SNDBUF", SO_SNDBUF);
+ sock_define_const("SO_SNDBUF", SO_SNDBUF);
#endif
#ifdef SO_RCVBUF
- sock_rb_define_const("SO_RCVBUF", SO_RCVBUF);
+ sock_define_const("SO_RCVBUF", SO_RCVBUF);
#endif
#ifdef SO_KEEPALIVE
- sock_rb_define_const("SO_KEEPALIVE", SO_KEEPALIVE);
+ sock_define_const("SO_KEEPALIVE", SO_KEEPALIVE);
#endif
#ifdef SO_OOBINLINE
- sock_rb_define_const("SO_OOBINLINE", SO_OOBINLINE);
+ sock_define_const("SO_OOBINLINE", SO_OOBINLINE);
#endif
#ifdef SO_NO_CHECK
- sock_rb_define_const("SO_NO_CHECK", SO_NO_CHECK);
+ sock_define_const("SO_NO_CHECK", SO_NO_CHECK);
#endif
#ifdef SO_PRIORITY
- sock_rb_define_const("SO_PRIORITY", SO_PRIORITY);
+ sock_define_const("SO_PRIORITY", SO_PRIORITY);
#endif
#ifdef SO_LINGER
- sock_rb_define_const("SO_LINGER", SO_LINGER);
+ sock_define_const("SO_LINGER", SO_LINGER);
#endif
#ifdef SOPRI_INTERACTIVE
- sock_rb_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE);
+ sock_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE);
#endif
#ifdef SOPRI_NORMAL
- sock_rb_define_const("SOPRI_NORMAL", SOPRI_NORMAL);
+ sock_define_const("SOPRI_NORMAL", SOPRI_NORMAL);
#endif
#ifdef SOPRI_BACKGROUND
- sock_rb_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND);
+ sock_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND);
#endif
#ifdef IP_MULTICAST_IF
- sock_rb_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF);
+ sock_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF);
#endif
#ifdef IP_MULTICAST_TTL
- sock_rb_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL);
+ sock_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL);
#endif
#ifdef IP_MULTICAST_LOOP
- sock_rb_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP);
+ sock_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP);
#endif
#ifdef IP_ADD_MEMBERSHIP
- sock_rb_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP);
+ sock_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP);
#endif
#ifdef IP_DEFAULT_MULTICAST_TTL
- sock_rb_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL);
+ sock_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL);
#endif
#ifdef IP_DEFAULT_MULTICAST_LOOP
- sock_rb_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP);
+ sock_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP);
#endif
#ifdef IP_MAX_MEMBERSHIPS
- sock_rb_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS);
+ sock_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS);
#endif
#ifdef IPX_TYPE
- sock_rb_define_const("IPX_TYPE", IPX_TYPE);
+ sock_define_const("IPX_TYPE", IPX_TYPE);
#endif
#ifdef TCP_NODELAY
- sock_rb_define_const("TCP_NODELAY", TCP_NODELAY);
+ sock_define_const("TCP_NODELAY", TCP_NODELAY);
#endif
#ifdef TCP_MAXSEG
- sock_rb_define_const("TCP_MAXSEG", TCP_MAXSEG);
+ sock_define_const("TCP_MAXSEG", TCP_MAXSEG);
+#endif
+
+#ifdef EAI_ADDRFAMILY
+ sock_define_const("EAI_ADDRFAMILY", EAI_ADDRFAMILY);
+#endif
+#ifdef EAI_AGAIN
+ sock_define_const("EAI_AGAIN", EAI_AGAIN);
+#endif
+#ifdef EAI_BADFLAGS
+ sock_define_const("EAI_BADFLAGS", EAI_BADFLAGS);
+#endif
+#ifdef EAI_FAIL
+ sock_define_const("EAI_FAIL", EAI_FAIL);
+#endif
+#ifdef EAI_FAMILY
+ sock_define_const("EAI_FAMILY", EAI_FAMILY);
+#endif
+#ifdef EAI_MEMORY
+ sock_define_const("EAI_MEMORY", EAI_MEMORY);
+#endif
+#ifdef EAI_NODATA
+ sock_define_const("EAI_NODATA", EAI_NODATA);
+#endif
+#ifdef EAI_NONAME
+ sock_define_const("EAI_NONAME", EAI_NONAME);
+#endif
+#ifdef EAI_SERVICE
+ sock_define_const("EAI_SERVICE", EAI_SERVICE);
+#endif
+#ifdef EAI_SOCKTYPE
+ sock_define_const("EAI_SOCKTYPE", EAI_SOCKTYPE);
+#endif
+#ifdef EAI_SYSTEM
+ sock_define_const("EAI_SYSTEM", EAI_SYSTEM);
+#endif
+#ifdef EAI_BADHINTS
+ sock_define_const("EAI_BADHINTS", EAI_BADHINTS);
+#endif
+#ifdef EAI_PROTOCOL
+ sock_define_const("EAI_PROTOCOL", EAI_PROTOCOL);
+#endif
+#ifdef EAI_MAX
+ sock_define_const("EAI_MAX", EAI_MAX);
+#endif
+#ifdef AI_PASSIVE
+ sock_define_const("AI_PASSIVE", AI_PASSIVE);
+#endif
+#ifdef AI_CANONNAME
+ sock_define_const("AI_CANONNAME", AI_CANONNAME);
+#endif
+#ifdef AI_NUMERICHOST
+ sock_define_const("AI_NUMERICHOST", AI_NUMERICHOST);
+#endif
+#ifdef AI_MASK
+ sock_define_const("AI_MASK", AI_MASK);
+#endif
+#ifdef AI_ALL
+ sock_define_const("AI_ALL", AI_ALL);
+#endif
+#ifdef AI_V4MAPPED_CFG
+ sock_define_const("AI_V4MAPPED_CFG", AI_V4MAPPED_CFG);
+#endif
+#ifdef AI_ADDRCONFIG
+ sock_define_const("AI_ADDRCONFIG", AI_ADDRCONFIG);
+#endif
+#ifdef AI_V4MAPPED
+ sock_define_const("AI_V4MAPPED", AI_V4MAPPED);
+#endif
+#ifdef AI_DEFAULT
+ sock_define_const("AI_DEFAULT", AI_DEFAULT);
+#endif
+#ifdef NI_MAXHOST
+ sock_define_const("NI_MAXHOST", NI_MAXHOST);
+#endif
+#ifdef NI_MAXSERV
+ sock_define_const("NI_MAXSERV", NI_MAXSERV);
+#endif
+#ifdef NI_NOFQDN
+ sock_define_const("NI_NOFQDN", NI_NOFQDN);
+#endif
+#ifdef NI_NUMERICHOST
+ sock_define_const("NI_NUMERICHOST", NI_NUMERICHOST);
+#endif
+#ifdef NI_NAMEREQD
+ sock_define_const("NI_NAMEREQD", NI_NAMEREQD);
+#endif
+#ifdef NI_NUMERICSERV
+ sock_define_const("NI_NUMERICSERV", NI_NUMERICSERV);
+#endif
+#ifdef NI_DGRAM
+ sock_define_const("NI_DGRAM", NI_DGRAM);
#endif
}