📄 getaddrinfo.c
字号:
h_error = h_errno;
#else
h_error = EINVAL;
#endif
#endif /*HAVE_GETHOSTBYNAME2*/
#endif /*USE_GETIPNODEBY*/
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:
case NETDB_INTERNAL:
default:
error = EAI_FAIL;
break;
}
} else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
|| (hp->h_addr_list[0] == NULL)) {
#ifdef USE_GETIPNODEBY
freehostent(hp);
#endif
hp = NULL;
error = EAI_FAIL;
}
if (hp == NULL)
goto free;
#ifdef USE_GETIPNODEBY
aplist = hp->h_addr_list;
#else
/*
* hp will be overwritten if we use gethostbyname2().
* always deep copy for simplification.
*/
for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
;
naddrs++;
aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
apbuf = (char *)malloc(hp->h_length * naddrs);
if (aplist == NULL || apbuf == NULL) {
error = EAI_MEMORY;
goto free;
}
memset(aplist, 0, sizeof(aplist[0]) * naddrs);
for (i = 0; i < naddrs; i++) {
if (hp->h_addr_list[i] == NULL) {
aplist[i] = NULL;
continue;
}
memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
hp->h_length);
aplist[i] = &apbuf[i * hp->h_length];
}
#endif
for (i = 0; aplist[i] != NULL; i++) {
af = hp->h_addrtype;
ap = aplist[i];
#ifdef AF_INET6
if (af == AF_INET6
&& IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
af = AF_INET;
ap = ap + sizeof(struct in6_addr)
- sizeof(struct in_addr);
}
#endif
if (af != pai->ai_family)
continue;
if ((pai->ai_flags & AI_CANONNAME) == 0) {
GET_AI(cur->ai_next, afd, ap);
GET_PORT(cur->ai_next, servname);
} else {
/*
* 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(ap, afd, &cur->ai_next,
ap, pai, servname);
}
while (cur && cur->ai_next)
cur = cur->ai_next;
}
*res = sentinel.ai_next;
return 0;
free:
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
if (aplist)
free(aplist);
if (apbuf)
free(apbuf);
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return error;
}
/*
* hostname == NULL.
* passive socket -> anyaddr (0.0.0.0 or ::)
* non-passive socket -> localhost (127.0.0.1 or ::1)
*/
static int
explore_null(pai, hostname, servname, res)
const struct addrinfo *pai;
const char *hostname;
const char *servname;
struct addrinfo **res;
{
int s;
const struct afd *afd;
struct addrinfo *cur;
struct addrinfo sentinel;
int error;
*res = NULL;
sentinel.ai_next = NULL;
cur = &sentinel;
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
*/
s = socket(pai->ai_family, SOCK_DGRAM, 0);
if (s < 0) {
if (errno != EMFILE)
return 0;
} else
close(s);
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
afd = find_afd(pai->ai_family);
if (pai->ai_flags & AI_PASSIVE) {
GET_AI(cur->ai_next, afd, afd->a_addrany);
/* xxx meaningless?
* GET_CANONNAME(cur->ai_next, "anyaddr");
*/
GET_PORT(cur->ai_next, servname);
} else {
GET_AI(cur->ai_next, afd, afd->a_loopback);
/* xxx meaningless?
* GET_CANONNAME(cur->ai_next, "localhost");
*/
GET_PORT(cur->ai_next, servname);
}
cur = cur->ai_next;
*res = sentinel.ai_next;
return 0;
free:
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return error;
}
/*
* numeric hostname
*/
static int
explore_numeric(pai, hostname, servname, res)
const struct addrinfo *pai;
const char *hostname;
const char *servname;
struct addrinfo **res;
{
const struct afd *afd;
struct addrinfo *cur;
struct addrinfo sentinel;
int error;
char pton[PTON_MAX];
int flags;
*res = NULL;
sentinel.ai_next = NULL;
cur = &sentinel;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
afd = find_afd(pai->ai_family);
flags = pai->ai_flags;
if (inet_pton(afd->a_af, hostname, pton) == 1) {
uint32_t v4a;
#ifdef INET6
u_char pfx;
#endif
switch (afd->a_af) {
case AF_INET:
v4a = (uint32_t)ntohl(((struct in_addr *)pton)->s_addr);
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
flags &= ~AI_CANONNAME;
v4a >>= IN_CLASSA_NSHIFT;
if (v4a == 0 || v4a == IN_LOOPBACKNET)
flags &= ~AI_CANONNAME;
break;
#ifdef INET6
case AF_INET6:
pfx = ((struct in6_addr *)pton)->s6_addr[0];
if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
flags &= ~AI_CANONNAME;
break;
#endif
}
if (pai->ai_family == afd->a_af ||
pai->ai_family == PF_UNSPEC /*?*/) {
if ((flags & AI_CANONNAME) == 0) {
GET_AI(cur->ai_next, afd, pton);
GET_PORT(cur->ai_next, servname);
} else {
/*
* 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, afd, &cur->ai_next,
pton, pai, servname);
}
while (cur && cur->ai_next)
cur = cur->ai_next;
} else
ERR(EAI_FAMILY); /*xxx*/
}
*res = sentinel.ai_next;
return 0;
free:
bad:
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return error;
}
/*
* numeric hostname with scope
*/
static int
explore_numeric_scope(pai, hostname, servname, res)
const struct addrinfo *pai;
const char *hostname;
const char *servname;
struct addrinfo **res;
{
#ifndef SCOPE_DELIMITER
return explore_numeric(pai, hostname, servname, res);
#else
const struct afd *afd;
struct addrinfo *cur;
int error;
char *cp, *hostname2 = NULL;
int scope;
struct sockaddr_in6 *sin6;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
afd = find_afd(pai->ai_family);
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res);
cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
return explore_numeric(pai, hostname, servname, res);
/*
* Handle special case of <scoped_address><delimiter><scope id>
*/
hostname2 = strdup(hostname);
if (hostname2 == NULL)
return EAI_MEMORY;
/* terminate at the delimiter */
hostname2[cp - hostname] = '\0';
cp++;
switch (pai->ai_family) {
#ifdef INET6
case AF_INET6:
scope = if_nametoindex(cp);
if (scope == 0) {
free(hostname2);
return (EAI_NONAME);
}
break;
#endif
}
error = explore_numeric(pai, hostname2, servname, res);
if (error == 0) {
for (cur = *res; cur; cur = cur->ai_next) {
if (cur->ai_family != AF_INET6)
continue;
sin6 = (struct sockaddr_in6 *)cur->ai_addr;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
sin6->sin6_scope_id = scope;
}
}
free(hostname2);
return error;
#endif
}
static int
get_name(addr, afd, res, numaddr, pai, servname)
const char *addr;
const struct afd *afd;
struct addrinfo **res;
char *numaddr;
const struct addrinfo *pai;
const char *servname;
{
struct hostent *hp = NULL;
struct addrinfo *cur = NULL;
int error = 0;
char *ap = NULL, *cn = NULL;
#ifdef USE_GETIPNODEBY
int h_error;
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
#else
hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
#endif
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
#ifdef USE_GETIPNODEBY
GET_AI(cur, afd, hp->h_addr_list[0]);
GET_PORT(cur, servname);
GET_CANONNAME(cur, hp->h_name);
#else
/* hp will be damaged if we use gethostbyaddr() */
if ((ap = (char *)malloc(hp->h_length)) == NULL) {
error = EAI_MEMORY;
goto free;
}
memcpy(ap, hp->h_addr_list[0], hp->h_length);
if ((cn = strdup(hp->h_name)) == NULL) {
error = EAI_MEMORY;
goto free;
}
GET_AI(cur, afd, ap);
GET_PORT(cur, servname);
GET_CANONNAME(cur, cn);
free(ap); ap = NULL;
free(cn); cn = NULL;
#endif
} else {
GET_AI(cur, afd, numaddr);
GET_PORT(cur, servname);
}
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
*res = cur;
return SUCCESS;
free:
if (cur)
freeaddrinfo(cur);
if (ap)
free(ap);
if (cn)
free(cn);
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
*res = NULL;
return error;
}
static int
get_canonname(pai, ai, str)
const struct addrinfo *pai;
struct addrinfo *ai;
const char *str;
{
if ((pai->ai_flags & AI_CANONNAME) != 0) {
ai->ai_canonname = (char *)malloc(strlen(str) + 1);
if (ai->ai_canonname == NULL)
return EAI_MEMORY;
strcpy(ai->ai_canonname, str);
}
return 0;
}
static struct addrinfo *
get_ai(pai, afd, addr)
const struct addrinfo *pai;
const struct afd *afd;
const char *addr;
{
char *p;
struct addrinfo *ai;
ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ (afd->a_socklen));
if (ai == NULL)
return NULL;
memcpy(ai, pai, sizeof(struct addrinfo));
ai->ai_addr = (struct sockaddr *)(ai + 1);
memset(ai->ai_addr, 0, afd->a_socklen);
#ifdef HAVE_SOCKADDR_SA_LEN
ai->ai_addr->sa_len = afd->a_socklen;
#endif
ai->ai_addrlen = afd->a_socklen;
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
p = (char *)(ai->ai_addr);
memcpy(p + afd->a_off, addr, afd->a_addrlen);
return ai;
}
static int
get_portmatch(ai, servname)
const struct addrinfo *ai;
const char *servname;
{
/* get_port does not touch first argument. when matchonly == 1. */
return get_port((struct addrinfo *)ai, servname, 1);
}
static int
get_port(ai, servname, matchonly)
struct addrinfo *ai;
const char *servname;
int matchonly;
{
const char *proto;
struct servent *sp;
int port;
int allownumeric;
if (servname == NULL)
return 0;
switch (ai->ai_family) {
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
break;
default:
return 0;
}
switch (ai->ai_socktype) {
case SOCK_RAW:
return EAI_SERVICE;
case SOCK_DGRAM:
case SOCK_STREAM:
allownumeric = 1;
break;
case ANY:
allownumeric = 0;
break;
default:
return EAI_SOCKTYPE;
}
if (str_isnumber(servname)) {
if (!allownumeric)
return EAI_SERVICE;
port = htons(atoi(servname));
if (port < 0 || port > 65535)
return EAI_SERVICE;
} else {
switch (ai->ai_socktype) {
case SOCK_DGRAM:
proto = "udp";
break;
case SOCK_STREAM:
proto = "tcp";
break;
default:
proto = NULL;
break;
}
if ((sp = getservbyname(servname, proto)) == NULL)
return EAI_SERVICE;
port = sp->s_port;
}
if (!matchonly) {
switch (ai->ai_family) {
case AF_INET:
((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
break;
#ifdef INET6
case AF_INET6:
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
break;
#endif
}
}
return 0;
}
static const struct afd *
find_afd(af)
int af;
{
const struct afd *afd;
if (af == PF_UNSPEC)
return NULL;
for (afd = afdl; afd->a_af; afd++) {
if (afd->a_af == af)
return afd;
}
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -