mirror of
https://github.com/python/cpython
synced 2024-09-05 00:05:39 +00:00
Patch #401196: Configuration machinery for IPv6.
Contributed by Jun-ichiro "itojun" Hagino. get{addr,name}info emulation code taken from WIDE.
This commit is contained in:
parent
e7e03cd0cf
commit
01dfdb3d35
140
Modules/addrinfo.h
Normal file
140
Modules/addrinfo.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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 HAVE_GETADDRINFO
|
||||
|
||||
/*
|
||||
* Error return codes from getaddrinfo()
|
||||
*/
|
||||
#ifndef EAI_ADDRFAMILY
|
||||
#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
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flag values for getaddrinfo()
|
||||
*/
|
||||
#ifndef AI_PASSIVE
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Constants for getnameinfo()
|
||||
*/
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flag values for getnameinfo()
|
||||
*/
|
||||
#ifndef NI_NOFQDN
|
||||
#define NI_NOFQDN 0x00000001
|
||||
#define NI_NUMERICHOST 0x00000002
|
||||
#define NI_NAMEREQD 0x00000004
|
||||
#define NI_NUMERICSERV 0x00000008
|
||||
#define NI_DGRAM 0x00000010
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ADDRINFO
|
||||
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 */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKADDR_STORAGE
|
||||
/*
|
||||
* RFC 2553: protocol-independent placeholder for socket addresses
|
||||
*/
|
||||
#define _SS_MAXSIZE 128
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#define _SS_ALIGNSIZE (sizeof(long long))
|
||||
#else
|
||||
#define _SS_ALIGNSIZE (sizeof(double))
|
||||
#endif
|
||||
#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2)
|
||||
#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \
|
||||
_SS_PAD1SIZE - _SS_ALIGNSIZE)
|
||||
|
||||
struct sockaddr_storage {
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
unsigned char ss_len; /* address length */
|
||||
unsigned char ss_family; /* address family */
|
||||
#else
|
||||
unsigned short ss_family; /* address family */
|
||||
#endif
|
||||
char __ss_pad1[_SS_PAD1SIZE];
|
||||
#ifdef HAVE_LONG_LONG
|
||||
long long __ss_align; /* force desired structure storage alignment */
|
||||
#else
|
||||
double __ss_align; /* force desired structure storage alignment */
|
||||
#endif
|
||||
char __ss_pad2[_SS_PAD2SIZE];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void freehostent Py_PROTO((struct hostent *));
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
625
Modules/getaddrinfo.c
Normal file
625
Modules/getaddrinfo.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* 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
|
||||
* GAI_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 GAI_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 GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "addrinfo.h"
|
||||
#endif
|
||||
|
||||
#if defined(__KAME__) && defined(INET6)
|
||||
# define FAITH
|
||||
#endif
|
||||
|
||||
#define SUCCESS 0
|
||||
#define GAI_ANY 0
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
#ifdef FAITH
|
||||
static int translate = NO;
|
||||
static struct in6_addr faith_prefix = IN6ADDR_GAI_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 gai_afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
int a_socklen;
|
||||
int a_off;
|
||||
const char *a_addrany;
|
||||
const char *a_loopback;
|
||||
} gai_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 Py_PROTO((const char *, struct gai_afd *,
|
||||
struct addrinfo **, char *, struct addrinfo *,
|
||||
int));
|
||||
static int get_addr Py_PROTO((const char *, int, struct addrinfo **,
|
||||
struct addrinfo *, int));
|
||||
static int str_isnumber Py_PROTO((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;\
|
||||
}\
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
#define GET_AI(ai, gai_afd, addr, port) {\
|
||||
char *p;\
|
||||
if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
|
||||
((gai_afd)->a_socklen)))\
|
||||
== NULL) goto free;\
|
||||
memcpy(ai, pai, sizeof(struct addrinfo));\
|
||||
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
|
||||
memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
|
||||
(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
|
||||
(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
|
||||
((struct sockinet *)(ai)->ai_addr)->si_port = port;\
|
||||
p = (char *)((ai)->ai_addr);\
|
||||
memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
|
||||
}
|
||||
#else
|
||||
#define GET_AI(ai, gai_afd, addr, port) {\
|
||||
char *p;\
|
||||
if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
|
||||
((gai_afd)->a_socklen)))\
|
||||
== NULL) goto free;\
|
||||
memcpy(ai, pai, sizeof(struct addrinfo));\
|
||||
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
|
||||
memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
|
||||
(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
|
||||
((struct sockinet *)(ai)->ai_addr)->si_port = port;\
|
||||
p = (char *)((ai)->ai_addr);\
|
||||
memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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 = GAI_ANY;
|
||||
pai->ai_protocol = GAI_ANY;
|
||||
pai->ai_addrlen = 0;
|
||||
pai->ai_canonname = NULL;
|
||||
pai->ai_addr = NULL;
|
||||
pai->ai_next = NULL;
|
||||
port = GAI_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 GAI_ANY:
|
||||
switch (pai->ai_protocol) {
|
||||
case GAI_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 != GAI_ANY)
|
||||
ERR(EAI_BADHINTS); /*xxx*/
|
||||
pai->ai_protocol = IPPROTO_UDP;
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
if (pai->ai_protocol != IPPROTO_TCP &&
|
||||
pai->ai_protocol != GAI_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 == GAI_ANY) {
|
||||
/* caller accept *GAI_ANY* socktype */
|
||||
pai->ai_socktype = SOCK_DGRAM;
|
||||
pai->ai_protocol = IPPROTO_UDP;
|
||||
}
|
||||
port = htons(atoi(servname));
|
||||
} else {
|
||||
struct servent *sp;
|
||||
char *proto;
|
||||
|
||||
proto = NULL;
|
||||
switch (pai->ai_socktype) {
|
||||
case GAI_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 == GAI_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 gai_afd *gai_afd;
|
||||
|
||||
for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
|
||||
if (!(pai->ai_family == PF_UNSPEC
|
||||
|| pai->ai_family == gai_afd->a_af)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pai->ai_flags & AI_PASSIVE) {
|
||||
GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
|
||||
/* xxx meaningless?
|
||||
* GET_CANONNAME(cur->ai_next, "anyaddr");
|
||||
*/
|
||||
} else {
|
||||
GET_AI(cur->ai_next, gai_afd, gai_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; gai_afdl[i].a_af; i++) {
|
||||
if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
|
||||
u_long v4a;
|
||||
u_char pfx;
|
||||
|
||||
switch (gai_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 == gai_afdl[i].a_af ||
|
||||
pai->ai_family == PF_UNSPEC) {
|
||||
if (! (pai->ai_flags & AI_CANONNAME)) {
|
||||
GET_AI(top, &gai_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, &gai_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, gai_afd, res, numaddr, pai, port0)
|
||||
const char *addr;
|
||||
struct gai_afd *gai_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, h_error;
|
||||
|
||||
#ifdef INET6
|
||||
hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
|
||||
#endif
|
||||
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
|
||||
GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
|
||||
GET_CANONNAME(cur, hp->h_name);
|
||||
} else
|
||||
GET_AI(cur, gai_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 gai_afd *gai_afd;
|
||||
int i, error = 0, h_error;
|
||||
char *ap;
|
||||
#ifndef INET6
|
||||
extern int h_errno;
|
||||
#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:
|
||||
gai_afd = &gai_afdl[N_INET6];
|
||||
break;
|
||||
#endif
|
||||
#ifndef INET6
|
||||
default: /* AF_UNSPEC */
|
||||
#endif
|
||||
case AF_INET:
|
||||
gai_afd = &gai_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);
|
||||
gai_afd = &gai_afdl[N_INET];
|
||||
} else
|
||||
gai_afd = &gai_afdl[N_INET6];
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#ifdef FAITH
|
||||
if (translate && gai_afd->a_af == AF_INET) {
|
||||
struct in6_addr *in6;
|
||||
|
||||
GET_AI(cur->ai_next, &gai_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, gai_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;
|
||||
}
|
208
Modules/getnameinfo.c
Normal file
208
Modules/getnameinfo.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* 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().
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "addrinfo.h"
|
||||
#endif
|
||||
|
||||
#define SUCCESS 0
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
static struct gni_afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
int a_socklen;
|
||||
int a_off;
|
||||
} gni_afdl [] = {
|
||||
#ifdef INET6
|
||||
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
|
||||
offsetof(struct sockaddr_in6, sin6_addr)},
|
||||
#endif
|
||||
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
|
||||
offsetof(struct sockaddr_in, sin_addr)},
|
||||
{0, 0, 0},
|
||||
};
|
||||
|
||||
struct gni_sockinet {
|
||||
u_char si_len;
|
||||
u_char si_family;
|
||||
u_short si_port;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
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 gni_afd *gni_afd;
|
||||
struct servent *sp;
|
||||
struct hostent *hp;
|
||||
u_short port;
|
||||
int family, len, i;
|
||||
char *addr, *p;
|
||||
u_long v4a;
|
||||
u_char pfx;
|
||||
int h_error;
|
||||
char numserv[512];
|
||||
char numaddr[512];
|
||||
|
||||
if (sa == NULL)
|
||||
return ENI_NOSOCKET;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
len = sa->sa_len;
|
||||
if (len != salen) return ENI_SALEN;
|
||||
#else
|
||||
len = salen;
|
||||
#endif
|
||||
|
||||
family = sa->sa_family;
|
||||
for (i = 0; gni_afdl[i].a_af; i++)
|
||||
if (gni_afdl[i].a_af == family) {
|
||||
gni_afd = &gni_afdl[i];
|
||||
goto found;
|
||||
}
|
||||
return ENI_FAMILY;
|
||||
|
||||
found:
|
||||
if (len != gni_afd->a_socklen) return ENI_SALEN;
|
||||
|
||||
port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
|
||||
addr = (char *)sa + gni_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(gni_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, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
|
||||
#else
|
||||
hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_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(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
|
||||
== NULL)
|
||||
return ENI_NOHOSTNAME;
|
||||
if (strlen(numaddr) > hostlen)
|
||||
return ENI_MEMORY;
|
||||
strcpy(host, numaddr);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
|
@ -187,6 +187,8 @@ Socket methods:
|
|||
#include <GUSI.h>
|
||||
#endif
|
||||
|
||||
#include "addrinfo.h"
|
||||
|
||||
#ifdef USE_SSL
|
||||
#include "openssl/rsa.h"
|
||||
#include "openssl/crypto.h"
|
||||
|
@ -196,6 +198,14 @@ Socket methods:
|
|||
#include "openssl/err.h"
|
||||
#endif /* USE_SSL */
|
||||
|
||||
/* I know this is a bad practice, but it is the easiest... */
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#include "getaddrinfo.c"
|
||||
#endif
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
#include "getnameinfo.c"
|
||||
#endif
|
||||
|
||||
#if defined(MS_WINDOWS) || defined(__BEOS__)
|
||||
/* BeOS suffers from the same socket dichotomy as Win32... - [cjh] */
|
||||
/* seem to be a few differences in the API */
|
||||
|
|
12
acconfig.h
12
acconfig.h
|
@ -35,6 +35,18 @@
|
|||
/* Define this if your time.h defines altzone */
|
||||
#undef HAVE_ALTZONE
|
||||
|
||||
/* Define if --enable-ipv6 is specified */
|
||||
#undef ENABLE_IPV6
|
||||
|
||||
/* Define if sockaddr has sa_len member */
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
/* struct addrinfo (netdb.h) */
|
||||
#undef HAVE_ADDRINFO
|
||||
|
||||
/* struct sockaddr_storage (sys/socket.h) */
|
||||
#undef HAVE_SOCKADDR_STORAGE
|
||||
|
||||
/* Defined when any dynamic module loading is enabled */
|
||||
#undef HAVE_DYNAMIC_LOADING
|
||||
|
||||
|
|
18
config.h.in
18
config.h.in
|
@ -100,6 +100,18 @@
|
|||
/* Define this if your time.h defines altzone */
|
||||
#undef HAVE_ALTZONE
|
||||
|
||||
/* Define if --enable-ipv6 is specified */
|
||||
#undef ENABLE_IPV6
|
||||
|
||||
/* Define if sockaddr has sa_len member */
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
/* struct addrinfo (netdb.h) */
|
||||
#undef HAVE_ADDRINFO
|
||||
|
||||
/* struct sockaddr_storage (sys/socket.h) */
|
||||
#undef HAVE_SOCKADDR_STORAGE
|
||||
|
||||
/* Defined when any dynamic module loading is enabled */
|
||||
#undef HAVE_DYNAMIC_LOADING
|
||||
|
||||
|
@ -341,6 +353,9 @@
|
|||
/* Define if you have the ftruncate function. */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* Define if you have the getaddrinfo function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define if you have the getcwd function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
|
@ -353,6 +368,9 @@
|
|||
/* Define if you have the getlogin function. */
|
||||
#undef HAVE_GETLOGIN
|
||||
|
||||
/* Define if you have the getnameinfo function. */
|
||||
#undef HAVE_GETNAMEINFO
|
||||
|
||||
/* Define if you have the getpeername function. */
|
||||
#undef HAVE_GETPEERNAME
|
||||
|
||||
|
|
284
configure.in
284
configure.in
|
@ -368,6 +368,151 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# Check for enable-ipv6
|
||||
OPT="$OPT -Dss_family=__ss_family -Dss_len=__ss_len"
|
||||
AC_MSG_CHECKING([whether to enable ipv6])
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --enable-ipv6 Enable ipv6 (with ipv4) support
|
||||
--disable-ipv6 Disable ipv6 support],
|
||||
[ case "$enableval" in
|
||||
no)
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
;;
|
||||
*) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(ENABLE_IPV6)
|
||||
ipv6=yes
|
||||
;;
|
||||
esac ],
|
||||
|
||||
AC_TRY_RUN([ /* AF_INET6 avalable check */
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
main()
|
||||
{
|
||||
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(ENABLE_IPV6)
|
||||
ipv6=yes,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no,
|
||||
AC_MSG_RESULT(no)
|
||||
ipv6=no
|
||||
))
|
||||
|
||||
ipv6type=unknown
|
||||
ipv6lib=none
|
||||
ipv6trylibc=no
|
||||
|
||||
if test "$ipv6" = "yes"; then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
|
||||
case $i in
|
||||
inria)
|
||||
dnl http://www.kame.net/
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include <netinet/in.h>
|
||||
#ifdef IPV6_INRIA_VERSION
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
OPT="-DINET6 $OPT"])
|
||||
;;
|
||||
kame)
|
||||
dnl http://www.kame.net/
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include <netinet/in.h>
|
||||
#ifdef __KAME__
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=inet6
|
||||
ipv6libdir=/usr/local/v6/lib
|
||||
ipv6trylibc=yes
|
||||
OPT="-DINET6 $OPT"])
|
||||
;;
|
||||
linux-glibc)
|
||||
dnl http://www.v6.linux.or.jp/
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include <features.h>
|
||||
#if defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2))
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6trylibc=yes
|
||||
OPT="-DINET6 $OPT"])
|
||||
;;
|
||||
linux-inet6)
|
||||
dnl http://www.v6.linux.or.jp/
|
||||
if test -d /usr/inet6; then
|
||||
ipv6type=$i
|
||||
ipv6lib=inet6
|
||||
ipv6libdir=/usr/inet6/lib
|
||||
OPT="-DINET6 -I/usr/inet6/include $OPT"
|
||||
fi
|
||||
;;
|
||||
toshiba)
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include <sys/param.h>
|
||||
#ifdef _TOSHIBA_INET6
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=inet6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
OPT="-DINET6 $OPT"])
|
||||
;;
|
||||
v6d)
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include </usr/local/v6/include/sys/v6config.h>
|
||||
#ifdef __V6D__
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=v6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
OPT="-I/usr/local/v6/include $OPT"])
|
||||
;;
|
||||
zeta)
|
||||
AC_EGREP_CPP(yes, [dnl
|
||||
#include <sys/param.h>
|
||||
#ifdef _ZETA_MINAMI_INET6
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=inet6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
OPT="-DINET6 $OPT"])
|
||||
;;
|
||||
esac
|
||||
if test "$ipv6type" != "unknown"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
AC_MSG_RESULT($ipv6type)
|
||||
fi
|
||||
|
||||
if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then
|
||||
if test -d $ipv6libdir -a -f $ipv6libdir/lib$ipv6lib.a; then
|
||||
LIBS="-L$ipv6libdir -l$ipv6lib $LIBS"
|
||||
echo "using lib$ipv6lib"
|
||||
else
|
||||
if test $ipv6trylibc = "yes"; then
|
||||
echo "using libc"
|
||||
else
|
||||
echo 'Fatal: no $ipv6lib library found. cannot continue.'
|
||||
echo "You need to fetch lib$ipv6lib.a from appropriate"
|
||||
echo 'ipv6 kit and compile beforehand.'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl # check for ANSI or K&R ("traditional") preprocessor
|
||||
dnl AC_MSG_CHECKING(for C preprocessor type)
|
||||
dnl AC_TRY_COMPILE([
|
||||
|
@ -1039,6 +1184,110 @@ AC_CHECK_FUNCS(getpgrp, AC_TRY_COMPILE([#include <unistd.h>], [getpgrp(0);], AC_
|
|||
AC_CHECK_FUNCS(setpgrp, AC_TRY_COMPILE([#include <unistd.h>], [setpgrp(0,0);], AC_DEFINE(SETPGRP_HAVE_ARG)))
|
||||
AC_CHECK_FUNCS(gettimeofday, AC_TRY_COMPILE([#include <sys/time.h>], [gettimeofday((struct timeval*)0,(struct timezone*)0);], ,AC_DEFINE(GETTIMEOFDAY_NO_TZ)))
|
||||
|
||||
AC_CHECK_FUNCS(getaddrinfo, [dnl
|
||||
AC_MSG_CHECKING(getaddrinfo bug)
|
||||
AC_TRY_RUN([
|
||||
#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;
|
||||
}
|
||||
switch (ai->ai_family) {
|
||||
case AF_INET:
|
||||
if (strcmp(strport, "54321") != 0) {
|
||||
goto bad;
|
||||
}
|
||||
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 (strcmp(strport, "54321") != 0) {
|
||||
goto bad;
|
||||
}
|
||||
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 (!(inet4 == 0 || inet4 == 2))
|
||||
goto bad;
|
||||
if (!(inet6 == 0 || inet6 == 2))
|
||||
goto bad;
|
||||
|
||||
if (aitop)
|
||||
freeaddrinfo(aitop);
|
||||
exit(0);
|
||||
|
||||
bad:
|
||||
if (aitop)
|
||||
freeaddrinfo(aitop);
|
||||
exit(1);
|
||||
}
|
||||
],
|
||||
AC_MSG_RESULT(good)
|
||||
buggygetaddrinfo=no,
|
||||
AC_MSG_RESULT(buggy)
|
||||
buggygetaddrinfo=yes,
|
||||
AC_MSG_RESULT(buggy)
|
||||
buggygetaddrinfo=yes)], [buggygetaddrinfo=yes])
|
||||
|
||||
if test "$buggygetaddrinfo" = "yes"; then
|
||||
if test "$ipv6" = "yes"; then
|
||||
echo 'Fatal: You must get working getaddrinfo() function.'
|
||||
echo ' or you can specify "--disable-ipv6"'.
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_FUNCS(getaddrinfo getnameinfo)
|
||||
|
||||
# checks for structures
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
@ -1063,6 +1312,31 @@ AC_TRY_COMPILE([
|
|||
], [;], [AC_DEFINE(SYS_SELECT_WITH_SYS_TIME) was_it_defined=yes])
|
||||
AC_MSG_RESULT($was_it_defined)
|
||||
|
||||
AC_MSG_CHECKING(for addrinfo)
|
||||
AC_CACHE_VAL(ac_cv_struct_addrinfo,
|
||||
AC_TRY_COMPILE([
|
||||
# include <netdb.h>],
|
||||
[struct addrinfo a],
|
||||
ac_cv_struct_addrinfo=yes,
|
||||
ac_cv_struct_addrinfo=no))
|
||||
AC_MSG_RESULT($ac_cv_struct_addrinfo)
|
||||
if test $ac_cv_struct_addrinfo = yes; then
|
||||
AC_DEFINE(HAVE_ADDRINFO)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for sockaddr_storage)
|
||||
AC_CACHE_VAL(ac_cv_struct_sockaddr_storage,
|
||||
AC_TRY_COMPILE([
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>],
|
||||
[struct sockaddr_storage s],
|
||||
ac_cv_struct_sockaddr_storage=yes,
|
||||
ac_cv_struct_sockaddr_storage=no))
|
||||
AC_MSG_RESULT($ac_cv_struct_sockaddr_storage)
|
||||
if test $ac_cv_struct_sockaddr_storage = yes; then
|
||||
AC_DEFINE(HAVE_SOCKADDR_STORAGE)
|
||||
fi
|
||||
|
||||
# checks for compiler characteristics
|
||||
|
||||
AC_C_CHAR_UNSIGNED
|
||||
|
@ -1108,6 +1382,16 @@ AC_TRY_COMPILE([#include <unistd.h>], [char **t;execve("@",t,t);], ,
|
|||
AC_MSG_RESULT($bad_prototypes)
|
||||
fi
|
||||
|
||||
# check if sockaddr has sa_len member
|
||||
AC_MSG_CHECKING(if sockaddr has sa_len member)
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <sys/socket.h>],
|
||||
[struct sockaddr x;
|
||||
x.sa_len = 0;],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_SOCKADDR_SA_LEN),
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
bad_forward=no
|
||||
AC_MSG_CHECKING(for bad static forward)
|
||||
AC_TRY_RUN([
|
||||
|
|
Loading…
Reference in a new issue