📄 getaddrinfo.c
字号:
return 0; hp = gethostbyname(hostname);#ifdef HAVE_H_ERRNO 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 intexplore_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 intexplore_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) { u_int32_t v4a;#ifdef INET6 u_char pfx;#endif switch (afd->a_af) { case AF_INET: v4a = (u_int32_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 intexplore_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 intget_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 intget_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 intget_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 intget_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 + -