diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1999-08-13 05:37:52 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1999-08-13 05:37:52 +0000 |
commit | 0a64817fb80016030c03518fb9459f63c11605ea (patch) | |
tree | 3ea2e607f9ea08c56830ef7b803cd259e3d67c7f /ext/socket | |
parent | 210367ec889f5910e270d6ea2c7ddb8a8d939e61 (diff) |
remove marshal/gtk/kconv
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/socket')
-rw-r--r-- | ext/socket/MANIFEST | 4 | ||||
-rw-r--r-- | ext/socket/addrinfo.h | 172 | ||||
-rw-r--r-- | ext/socket/depend | 4 | ||||
-rw-r--r-- | ext/socket/extconf.rb | 257 | ||||
-rw-r--r-- | ext/socket/getaddrinfo.c | 676 | ||||
-rw-r--r-- | ext/socket/getnameinfo.c | 250 | ||||
-rw-r--r-- | ext/socket/socket.c | 1289 | ||||
-rw-r--r-- | ext/socket/sockport.h | 43 |
8 files changed, 2261 insertions, 434 deletions
diff --git a/ext/socket/MANIFEST b/ext/socket/MANIFEST index d41d9e0b69..616d459d92 100644 --- a/ext/socket/MANIFEST +++ b/ext/socket/MANIFEST @@ -1,4 +1,8 @@ MANIFEST +addrinfo.h depend extconf.rb +getaddrinfo.c +getnameinfo.c +sockport.h socket.c diff --git a/ext/socket/addrinfo.h b/ext/socket/addrinfo.h new file mode 100644 index 0000000000..74fae207b9 --- /dev/null +++ b/ext/socket/addrinfo.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADDR_INFO_H +#define ADDR_INFO_H +#ifndef HAVE_GETADDRINFO + +/* special compatibility hack */ +#undef EAI_ADDRFAMILY +#undef EAI_AGAIN +#undef EAI_BADFLAGS +#undef EAI_FAIL +#undef EAI_FAMILY +#undef EAI_MEMORY +#undef EAI_NODATA +#undef EAI_NONAME +#undef EAI_SERVICE +#undef EAI_SOCKTYPE +#undef EAI_SYSTEM +#undef EAI_BADHINTS +#undef EAI_PROTOCOL +#undef EAI_MAX + +#undef AI_PASSIVE +#undef AI_CANONNAME +#undef AI_NUMERICHOST +#undef AI_ALL +#undef AI_ADDRCONFIG +#undef AI_V4MAPPED +#undef AI_DEFAULT + +#undef NI_NOFQDN +#undef NI_NUMERICHOST +#undef NI_NAMEREQD +#undef NI_NUMERICSERV +#undef NI_DGRAM + +#define addrinfo addrinfo__compat +#define getaddrinfo getaddrinfo__compat +#define getnameinfo getnameinfo__compat +#define freehostent freehostent__compat +#define freeaddrinfo freeaddrinfo__compat + +#ifndef __P +# ifdef HAVE_PROTOTYPES +# define __P(args) args +# else +# define __P(args) () +# endif +#endif + +/* special compatibility hack -- end*/ + + +/* + * Error return codes from getaddrinfo() + */ +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_MAX 14 + +/* + * Flag values for getaddrinfo() + */ +#define AI_PASSIVE 0x00000001 /* get address to use bind() */ +#define AI_CANONNAME 0x00000002 /* fill ai_canonname */ +#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ +/* valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) + +#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ +#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ +#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ +#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ +/* special recommended flags for getipnodebyname */ +#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) + +/* + * Constants for getnameinfo() + */ +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +/* + * Flag values for getnameinfo() + */ +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 + +#ifdef NT +#define IN_EXPERIMENTAL(x) 0 +#define IN_LOOPBACKNET 0 +#endif + +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; + +extern int getaddrinfo __P(( + const char *hostname, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res)); + +extern int getnameinfo __P(( + const struct sockaddr *sa, + size_t salen, + char *host, + size_t hostlen, + char *serv, + size_t servlen, + int flags)); + +extern void freehostent __P((struct hostent *)); +extern void freeaddrent __P((struct addrinfo *)); +extern char *gai_strerror __P((int)); + +/* In case there is no definition of offsetof() provided - though any proper +Standard C system should have one. */ + +#ifndef offsetof +#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) +#endif + +#endif +#endif diff --git a/ext/socket/depend b/ext/socket/depend index 6e8c3b7d97..cca6d4e62a 100644 --- a/ext/socket/depend +++ b/ext/socket/depend @@ -1 +1,3 @@ -socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h +socket.o : socket.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h sockport.h +getnameinfo.o: getnameinfo.c $(topdir)/config.h addrinfo.h sockport.h +getaddrinfo.o: getaddrinfo.c $(topdir)/config.h addrinfo.h sockport.h diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb index 449d5a2785..da1a2a6b05 100644 --- a/ext/socket/extconf.rb +++ b/ext/socket/extconf.rb @@ -1,27 +1,276 @@ require 'mkmf' -$LDFLAGS = "-L/usr/local/lib" if File.directory?("/usr/local/lib") +$LDFLAGS += " -L/usr/local/lib" if File.directory?("/usr/local/lib") +$CFLAGS += " -Dss_family=__ss_family -Dss_len=__ss_len" + case PLATFORM when /mswin32/ test_func = "WSACleanup" have_library("wsock32", "WSACleanup") -when /cygwin32/ +when /cygwin/ + $LDFLAGS << " -L/usr/lib" if File.directory?("/usr/lib") + $CFLAGS << " -I/usr/include" test_func = "socket" + have_library("bind", "gethostbyaddr") when /beos/ test_func = "socket" have_library("net", "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 + +$ipv6 = false +if enable_config("ipv6", false) + if try_link(<<EOF) +#include <sys/types.h> +#include <sys/socket.h> +main() +{ + socket(AF_INET6, SOCK_STREAM, 0); +} +EOF + $CFLAGS+=" -DENABLE_IPV6" + $ipv6 = true + end +end + +$ipv6type = nil +$ipv6lib = nil +$ipv6libdir = nil +if $ipv6 + if egrep_cpp("yes", <<EOF) +#include <netinet/in.h> +#ifdef IPV6_INRIA_VERSION +yes +#endif +EOF + $ipv6type = "inria" + $CFLAGS="-DINET6 "+$CFLAGS + elsif egrep_cpp("yes", <<EOF) +#include <netinet/in.h> +#ifdef __KAME__ +yes +#endif +EOF + $ipv6type = "kame" + $ipv6lib="inet6" + $ipv6libdir="/usr/local/v6/lib" + $CFLAGS="-DINET6 "+$CFLAGS + elsif File.directory? "/usr/inet6" + $ipv6type = "linux" + $ipv6lib="inet6" + $ipv6libdir="/usr/inet6/lib" + $CFLAGS="-DINET6 -I/usr/inet6/include "+$CFLAGS + elsif egrep_cpp("yes", <<EOF) +#include <sys/param.h> +#ifdef _TOSHIBA_INET6 +yes +#endif +EOF + $ipv6type = "toshiba" + $ipv6lib="inet6" + $ipv6libdir="/usr/local/v6/lib" + $CFLAGS="-DINET6 "+$CFLAGS + elsif egrep_cpp("yes", <<EOF) +#include </usr/local/v6/include/sys/v6config.h> +#ifdef __V6D__ +yes +#endif +EOF + $ipv6type = "v6d" + $ipv6lib="v6" + $ipv6libdir="/usr/local/v6/lib" + $CFLAGS="-DINET6 -I/usr/local/v6/include "+$CFLAGS + elsif egrep_cpp("yes", <<EOF) +#include <sys/param.h> +#ifdef _ZETA_MINAMI_INET6 +yes +#endif +EOF + $ipv6type = "zeta" + $ipv6lib="inet6" + $ipv6libdir="/usr/local/v6/lib" + $CFLAGS="-DINET6 "+$CFLAGS + end + + if $ipv6lib + if File.directory? $ipv6libdir and File.exist? "#{$ipv6libdir}/lib#{$ipv6lib}.a" + $LOCAL_LIBS = " -L#$ipv6libdir -l#$ipv6lib" + else + print <<EOS + +Fatal: no #$ipv6lib library found. cannot continue. +You need to fetch lib#{$ipv6lib}.a from appropriate +ipv6 kit and compile beforehand. +EOS + exit + end + end +end + + if try_link(<<EOF) +#include <sys/types.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +int +main() +{ + struct sockaddr_in sin; + + sin.sin_len; + return 0; +} +EOF + $CFLAGS="-DHAVE_SIN_LEN "+$CFLAGS +end + + if try_link(<<EOF) +#include <sys/types.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +int +main() +{ + struct sockaddr sa; + + sa.sa_len; + return 0; +} +EOF + $CFLAGS="-DHAVE_SA_LEN "+$CFLAGS +end + +have_header("sys/sysctl.h") + +$getaddr_info_ok = false +if try_run(<<EOF) +#include <sys/types.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> + +main() +{ + int passive, gaierr, inet4 = 0, inet6 = 0; + struct addrinfo hints, *ai, *aitop; + char straddr[INET6_ADDRSTRLEN], strport[16]; + + for (passive = 0; passive <= 1; passive++) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + 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_addr == NULL || + 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 (inet6 != 2 || inet4 != 2) + goto bad; + + if (aitop) + freeaddrinfo(aitop); + exit(0); + + bad: + if (aitop) + freeaddrinfo(aitop); + exit(1); +} +EOF + $getaddr_info_ok = true +end +if $ipv6 and not $getaddr_info_ok + print <<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. +EOS + exit +end + + +$objs = ["socket.#{$OBJEXT}"] + +if $getaddr_info_ok and have_func("getaddrinfo") and have_func("getnameinfo") + have_getaddrinfo = true +end + +if have_getaddrinfo + $CFLAGS="-DHAVE_GETADDRINFO "+$CFLAGS +else + $CFLAGS="-I. "+$CFLAGS + $objs += ["getaddrinfo.#{$OBJEXT}"] + $objs += ["getnameinfo.#{$OBJEXT}"] + have_func("inet_ntop") or have_func("inet_ntoa") + have_func("inet_pton") or have_func("inet_aton") + have_header("arpa/nameser.h") + have_header("resolv.h") +end + have_header("sys/un.h") + if have_func(test_func) - have_func("inet_aton") have_func("hsterror") unless have_func("gethostname") have_func("uname") end - if ENV["SOCKS_SERVER"] # test if SOCKSsocket needed + if ENV["SOCKS_SERVER"] or enable_config("socks", false) if have_library("socks", "Rconnect") $CFLAGS="-DSOCKS" end diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c new file mode 100644 index 0000000000..c71a56ca80 --- /dev/null +++ b/ext/socket/getaddrinfo.c @@ -0,0 +1,676 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. + * + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2133 is silent about which error + * code must be returned for which situation. + * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. + */ + +#include <sys/types.h> +#ifndef NT +#include <sys/param.h> +#endif +#ifdef HAVE_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifndef NT +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#if defined(HAVE_ARPA_NAMESER_H) +#include <arpa/nameser.h> +#endif +#include <netdb.h> +#if defined(HAVE_RESOLV_H) +#include <resolv.h> +#endif +#include <unistd.h> +#else +#include <winsock2.h> +#include <io.h> +#endif +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <ctype.h> + +#include "config.h" +#include "addrinfo.h" +#include "sockport.h" + +#if defined(__KAME__) && defined(INET6) +# define FAITH +#endif + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +#ifdef FAITH +static int translate = NO; +static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; +#endif + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +static struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; +} afdl [] = { +#ifdef INET6 +#define N_INET6 0 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback}, +#define N_INET 1 +#else +#define N_INET 0 +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback}, + {0, 0, 0, 0, NULL, NULL}, +}; + +#ifdef INET6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + + +static int get_name __P((const char *, struct afd *, + struct addrinfo **, char *, struct addrinfo *, + int)); +static int get_addr __P((const char *, int, struct addrinfo **, + struct addrinfo *, int)); +static int str_isnumber __P((const char *)); + +static char *ai_errlist[] = { + "success.", + "address family for hostname not supported.", /* EAI_ADDRFAMILY */ + "temporary failure in name resolution.", /* EAI_AGAIN */ + "invalid value for ai_flags.", /* EAI_BADFLAGS */ + "non-recoverable failure in name resolution.", /* EAI_FAIL */ + "ai_family not supported.", /* EAI_FAMILY */ + "memory allocation failure.", /* EAI_MEMORY */ + "no address associated with hostname.", /* EAI_NODATA */ + "hostname nor servname provided, or not known.",/* EAI_NONAME */ + "servname not supported for ai_socktype.", /* EAI_SERVICE */ + "ai_socktype not supported.", /* EAI_SOCKTYPE */ + "system error returned in errno.", /* EAI_SYSTEM */ + "invalid value for hints.", /* EAI_BADHINTS */ + "resolved protocol is unknown.", /* EAI_PROTOCOL */ + "unknown error.", /* EAI_MAX */ +}; + +#define GET_CANONNAME(ai, str) \ +if (pai->ai_flags & AI_CANONNAME) {\ + if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ + strcpy((ai)->ai_canonname, (str));\ + } else {\ + error = EAI_MEMORY;\ + goto free;\ + }\ +} + +#define GET_AI(ai, afd, addr, port) {\ + char *p;\ + if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ + ((afd)->a_socklen)))\ + == NULL) {\ + error = EAI_MEMORY;\ + goto free;\ + }\ + 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;\ + ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ + p = (char *)((ai)->ai_addr);\ + memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\ +} + +#define ERR(err) { error = (err); goto bad; } + +char * +gai_strerror(ecode) + int ecode; +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} + +void +freeaddrinfo(ai) + struct addrinfo *ai; +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + } while ((ai = next) != NULL); +} + +static int +str_isnumber(p) + const char *p; +{ + char *q = (char *)p; + while (*q) { + if (! isdigit(*q)) + return NO; + q++; + } + return YES; +} + +#ifndef HAVE_INET_PTON + +static int +inet_pton(af, hostname, pton) + int af; + const char *hostname; + void *pton; +{ + struct in_addr in; + +#ifdef HAVE_INET_ATON + if (!inet_aton(hostname, &in)) + return 0; +#else + int d1, d2, d3, d4; + char ch; + + if (sscanf(hostname, "%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) { + in.s_addr = htonl( + ((long) d1 << 24) | ((long) d2 << 16) | + ((long) d3 << 8) | ((long) d4 << 0)); + } + else { + return 0; + } +#endif + memcpy(pton, &in, sizeof(in)); + return 1; +} +#endif + +int +getaddrinfo(hostname, servname, hints, res) + const char *hostname, *servname; + const struct addrinfo *hints; + struct addrinfo **res; +{ + struct addrinfo sentinel; + struct addrinfo *top = NULL; + struct addrinfo *cur; + int i, error = 0; + char pton[PTON_MAX]; + struct addrinfo ai; + struct addrinfo *pai; + u_short port; + +#ifdef FAITH + static int firsttime = 1; + + if (firsttime) { + /* translator hack */ + { + char *q = getenv("GAI"); + if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) + translate = YES; + } + firsttime = 0; + } +#endif + + /* initialize file static vars */ + sentinel.ai_next = NULL; + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + port = ANY; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef INET6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + switch (pai->ai_socktype) { + case ANY: + switch (pai->ai_protocol) { + case ANY: + break; + case IPPROTO_UDP: + pai->ai_socktype = SOCK_DGRAM; + break; + case IPPROTO_TCP: + pai->ai_socktype = SOCK_STREAM; + break; + default: + pai->ai_socktype = SOCK_RAW; + break; + } + break; + case SOCK_RAW: + break; + case SOCK_DGRAM: + if (pai->ai_protocol != IPPROTO_UDP && + pai->ai_protocol != ANY) + ERR(EAI_BADHINTS); /*xxx*/ + pai->ai_protocol = IPPROTO_UDP; + break; + case SOCK_STREAM: + if (pai->ai_protocol != IPPROTO_TCP && + pai->ai_protocol != ANY) + ERR(EAI_BADHINTS); /*xxx*/ + pai->ai_protocol = IPPROTO_TCP; + break; + default: + ERR(EAI_SOCKTYPE); + break; + } + } + + /* + * service port + */ + if (servname) { + if (str_isnumber(servname)) { + if (pai->ai_socktype == ANY) { + /* caller accept *ANY* socktype */ + pai->ai_socktype = SOCK_DGRAM; + pai->ai_protocol = IPPROTO_UDP; + } + port = htons((unsigned short)atoi(servname)); + } else { + struct servent *sp; + char *proto; + + proto = NULL; + switch (pai->ai_socktype) { + case ANY: + proto = NULL; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + fprintf(stderr, "panic!\n"); + break; + } + if ((sp = getservbyname(servname, proto)) == NULL) + ERR(EAI_SERVICE); + port = sp->s_port; + if (pai->ai_socktype == ANY) + if (strcmp(sp->s_proto, "udp") == 0) { + pai->ai_socktype = SOCK_DGRAM; + pai->ai_protocol = IPPROTO_UDP; + } else if (strcmp(sp->s_proto, "tcp") == 0) { + pai->ai_socktype = SOCK_STREAM; + pai->ai_protocol = IPPROTO_TCP; + } else + ERR(EAI_PROTOCOL); /*xxx*/ + } + } + + /* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ + if (hostname == NULL) { + struct afd *afd; + int s; + + for (afd = &afdl[0]; afd->a_af; afd++) { + if (!(pai->ai_family == PF_UNSPEC + || pai->ai_family == afd->a_af)) { + continue; + } + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(afd->a_af, SOCK_DGRAM, 0); + if (s < 0) + continue; + close(s); + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany, port); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback, + port); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + } + cur = cur->ai_next; + } + top = sentinel.ai_next; + if (top) + goto good; + else + ERR(EAI_FAMILY); + } + + /* hostname as numeric name */ + for (i = 0; afdl[i].a_af; i++) { + if (inet_pton(afdl[i].a_af, hostname, pton)) { + u_long v4a; +#ifdef INET6 + u_char pfx; +#endif + + switch (afdl[i].a_af) { + case AF_INET: + v4a = ((struct in_addr *)pton)->s_addr; + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + pai->ai_flags &= ~AI_CANONNAME; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + pai->ai_flags &= ~AI_CANONNAME; + break; +#ifdef INET6 + case AF_INET6: + pfx = ((struct in6_addr *)pton)->s6_addr8[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + pai->ai_flags &= ~AI_CANONNAME; + break; +#endif + } + + if (pai->ai_family == afdl[i].a_af || + pai->ai_family == PF_UNSPEC) { + if (! (pai->ai_flags & AI_CANONNAME)) { + GET_AI(top, &afdl[i], pton, port); + goto good; + } + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks strange + * that we do addr->name translation here. + */ + get_name(pton, &afdl[i], &top, pton, pai, port); + goto good; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + } + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + + /* hostname as alphabetical name */ + error = get_addr(hostname, pai->ai_family, &top, pai, port); + if (error == 0) { + if (top) { + good: + *res = top; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + if (top) + freeaddrinfo(top); + bad: + *res = NULL; + return error; +} + +static int +get_name(addr, afd, res, numaddr, pai, port0) + const char *addr; + struct afd *afd; + struct addrinfo **res; + char *numaddr; + struct addrinfo *pai; + int port0; +{ + u_short port = port0 & 0xffff; + struct hostent *hp; + struct addrinfo *cur; + int error = 0; +#ifdef INET6 + int h_error; +#endif + +#ifdef INET6 + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, afd->a_addrlen, AF_INET); +#endif + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { + GET_AI(cur, afd, hp->h_addr_list[0], port); + GET_CANONNAME(cur, hp->h_name); + } else + GET_AI(cur, afd, numaddr, port); + +#ifdef INET6 + if (hp) + freehostent(hp); +#endif + *res = cur; + return SUCCESS; + free: + if (cur) + freeaddrinfo(cur); +#ifdef INET6 + if (hp) + freehostent(hp); +#endif + /* bad: */ + *res = NULL; + return error; +} + +static int +get_addr(hostname, af, res, pai, port0) + const char *hostname; + int af; + struct addrinfo **res; + struct addrinfo *pai; + int port0; +{ + u_short port = port0 & 0xffff; + struct addrinfo sentinel; + struct hostent *hp; + struct addrinfo *top, *cur; + struct afd *afd; + int i, error = 0, h_error; + char *ap; +#ifndef INET6 +#ifndef NT + extern int h_errno; +#endif +#endif + + top = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; +#ifdef INET6 + if (af == AF_UNSPEC) { + hp = getipnodebyname(hostname, AF_INET6, + AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); + } else + hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); +#else + hp = gethostbyname(hostname); + h_error = h_errno; +#endif + if (hp == NULL) { + switch (h_error) { + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NODATA; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + default: + error = EAI_FAIL; + break; + } + goto bad; + } + + if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || + (hp->h_addr_list[0] == NULL)) + ERR(EAI_FAIL); + + for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { + switch (af) { +#ifdef INET6 + case AF_INET6: + afd = &afdl[N_INET6]; + break; +#endif +#ifndef INET6 + default: /* AF_UNSPEC */ +#endif + case AF_INET: + afd = &afdl[N_INET]; + break; +#ifdef INET6 + default: /* AF_UNSPEC */ + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { + ap += sizeof(struct in6_addr) - + sizeof(struct in_addr); + afd = &afdl[N_INET]; + } else + afd = &afdl[N_INET6]; + break; +#endif + } +#ifdef FAITH + if (translate && afd->a_af == AF_INET) { + struct in6_addr *in6; + + GET_AI(cur->ai_next, &afdl[N_INET6], ap, port); + in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; + memcpy(&in6->s6_addr32[0], &faith_prefix, + sizeof(struct in6_addr) - sizeof(struct in_addr)); + memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); + } else +#endif /* FAITH */ + GET_AI(cur->ai_next, afd, ap, port); + if (cur == &sentinel) { + top = cur->ai_next; + GET_CANONNAME(top, hp->h_name); + } + cur = cur->ai_next; + } +#ifdef INET6 + freehostent(hp); +#endif + *res = top; + return SUCCESS; + free: + if (top) + freeaddrinfo(top); +#ifdef INET6 + if (hp) + freehostent(hp); +#endif + bad: + *res = NULL; + return error; +} diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c new file mode 100644 index 0000000000..abadd8f442 --- /dev/null +++ b/ext/socket/getnameinfo.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - Return values. There seems to be no standard for return value (RFC2133) + * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). + */ + +#include <sys/types.h> +#ifndef NT +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#if defined(HAVE_ARPA_NAMESER_H) +#include <arpa/nameser.h> +#endif +#include <netdb.h> +#if defined(HAVE_RESOLV_H) +#include <resolv.h> +#endif +#endif +#ifdef NT +#include <winsock2.h> +#include <stdio.h> +#define snprintf _snprintf +#endif + +#include <string.h> +#include <stddef.h> + +#include "config.h" +#include "addrinfo.h" +#include "sockport.h" + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +static struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; +} afdl [] = { +#ifdef INET6 +#define N_INET6 0 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#define N_INET 1 +#else +#define N_INET 0 +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0, 0}, +}; + +#define ENI_NOSOCKET 0 +#define ENI_NOSERVNAME 1 +#define ENI_NOHOSTNAME 2 +#define ENI_MEMORY 3 +#define ENI_SYSTEM 4 +#define ENI_FAMILY 5 +#define ENI_SALEN 6 + +#ifndef HAVE_INET_NTOP +static const char * +inet_ntop(af, addr, numaddr, numaddr_len) + 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(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + size_t salen; + char *host; + size_t hostlen; + char *serv; + size_t servlen; + int flags; +{ + struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, len, i; + char *addr, *p; + u_long v4a; +#ifdef INET6 + u_char pfx; +#endif + int h_error; + char numserv[512]; + char numaddr[512]; +#ifndef NT + extern int h_errno; +#endif + + if (sa == NULL) + return ENI_NOSOCKET; + + len = SA_LEN(sa); + if (len != salen) return ENI_SALEN; + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return ENI_FAMILY; + + found: + if (len != afd->a_socklen) return ENI_SALEN; + + port = ((struct sockinet *)sa)->si_port; /* network byte order */ + addr = (char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* what we should do? */ + } else if (flags & NI_NUMERICSERV) { + snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return ENI_MEMORY; + strcpy(serv, numserv); + } else { + sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); + if (sp) { + if (strlen(sp->s_name) > servlen) + return ENI_MEMORY; + strcpy(serv, sp->s_name); + } else + return ENI_NOSERVNAME; + } + + switch (sa->sa_family) { + case AF_INET: + v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; +#ifdef INET6 + case AF_INET6: + pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + flags |= NI_NUMERICHOST; + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* what should we do? */ + } else if (flags & NI_NUMERICHOST) { + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } else { +#ifdef INET6 + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); + h_error = h_errno; +#endif + + if (hp) { + if (flags & NI_NOFQDN) { + p = strchr(hp->h_name, '.'); + if (p) *p = '\0'; + } + if (strlen(hp->h_name) > hostlen) { +#ifdef INET6 + freehostent(hp); +#endif + return ENI_MEMORY; + } + strcpy(host, hp->h_name); +#ifdef INET6 + freehostent(hp); +#endif + } else { + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_NOHOSTNAME; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } + } + return SUCCESS; +} diff --git a/ext/socket/socket.c b/ext/socket/socket.c index e9bdbc9e8c..93a8aacce3 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 } diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h new file mode 100644 index 0000000000..99bec91a1a --- /dev/null +++ b/ext/socket/sockport.h @@ -0,0 +1,43 @@ +/************************************************ + + sockport.h - + + $Author$ + $Date$ + created at: Fri Apr 30 23:19:34 JST 1999 + +************************************************/ + +#ifndef SOCKPORT_H +#define SOCKPORT_H + +#ifndef SA_LEN +# ifdef HAVE_SA_LEN +# define SA_LEN(sa) (sa)->sa_len +# else +# ifdef INET6 +# define SA_LEN(sa) \ + (((sa)->sa_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)) +# endif +# endif +#endif + +#ifdef HAVE_SA_LEN +# define SET_SA_LEN(sa, len) (sa)->sa_len = (len) +#else +# define SET_SA_LEN(sa, len) (len) +#endif + +#ifdef HAVE_SIN_LEN +# define SIN_LEN(si) (si)->sin_len +# define SET_SIN_LEN(si,len) (si)->sin_len = (len) +#else +# define SIN_LEN(si) sizeof(struct sockaddr_in) +# define SET_SIN_LEN(si,len) (len) +#endif + +#endif |