📄 su_addrinfo.c
字号:
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; #if SU_HAVE_IN6 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); #if SU_HAVE_IN6 if (hp) freehostent(hp);#endif *res = cur; return SUCCESS; free: if (cur) freeaddrinfo(cur);#if SU_HAVE_IN6 if (hp) freehostent(hp);#endif /* bad: */ *res = NULL; return error;}static intget_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; top = NULL; sentinel.ai_next = NULL; cur = &sentinel;#if SU_HAVE_IN6 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) {#if SU_HAVE_IN6 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;#if SU_HAVE_IN6 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; }#if SU_HAVE_IN6 freehostent(hp);#endif *res = top; return SUCCESS; free: if (top) freeaddrinfo(top);#if SU_HAVE_IN6 if (hp) freehostent(hp);#endif bad: *res = NULL; return error;}/* * 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(). */#define SUCCESS 0#define YES 1#define NO 0static struct gni_afd { int a_af; int a_addrlen; int a_socklen; int a_off;} gni_afdl [] = {#if SU_HAVE_IN6 {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 EAI_FAIL#define ENI_NOSERVNAME EAI_NONAME#define ENI_NOHOSTNAME EAI_NONAME#define ENI_MEMORY EAI_MEMORY#define ENI_SYSTEM EAI_SYSTEM#define ENI_FAMILY EAI_FAMILY#define ENI_SALEN EAI_MEMORYstaticintgetnameinfo(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;#if SU_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;#if SU_HAVE_IN6 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 {#if SU_HAVE_IN6 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) {#if SU_HAVE_IN6 freehostent(hp);#endif return ENI_MEMORY; } strcpy(host, hp->h_name);#if SU_HAVE_IN6 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;}#endif /* !HAVE_GETNAMEINFO */#if !HAVE_FREEADDRINFOstatic voidfreeaddrinfo(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);}#endif#if !HAVE_GAI_STRERRORstatic char *gai_strerror(ecode) int ecode;{ switch (ecode) { case 0: return "success.";#if defined(EAI_ADDRFAMILY) case EAI_ADDRFAMILY: return "address family for hostname not supported.";#endif#if defined(EAI_AGAIN) case EAI_AGAIN: return "temporary failure in name resolution.";#endif#if defined(EAI_BADFLAGS) case EAI_BADFLAGS: return "invalid value for ai_flags.";#endif#if defined(EAI_FAIL) case EAI_FAIL: return "non-recoverable failure in name resolution.";#endif#if defined(EAI_FAMILY) case EAI_FAMILY: return "ai_family not supported.";#endif#if defined(EAI_MEMORY) case EAI_MEMORY: return "memory allocation failure.";#endif#if defined(EAI_NODATA) case EAI_NODATA: return "no address associated with hostname.";#endif#if defined(EAI_NONAME) case EAI_NONAME: return "hostname nor servname provided, or not known.";#endif#if defined(EAI_SERVICE) case EAI_SERVICE: return "servname not supported for ai_socktype.";#endif#if defined(EAI_SOCKTYPE) case EAI_SOCKTYPE: return "ai_socktype not supported.";#endif#if defined(EAI_SYSTEM) case EAI_SYSTEM: return "system error returned in errno.";#endif#if defined(EAI_BADHINTS) case EAI_BADHINTS: return "invalid value for hints.";#endif#if defined(EAI_PROTOCOL) case EAI_PROTOCOL: return "resolved protocol is unknown.";#endif default: return "unknown error."; }}#endif/** Translate address and service. * * This is a getaddrinfo() supporting SCTP and other exotic protocols. */int su_getaddrinfo(char const *node, char const *service, su_addrinfo_t const *hints, su_addrinfo_t **res){#if HAVE_SCTP if (res && hints && hints->ai_protocol == IPPROTO_SCTP) { su_addrinfo_t *ai, system_hints[1]; int retval, socktype; socktype = hints->ai_socktype; if (!(socktype == 0 || socktype == SOCK_SEQPACKET || socktype == SOCK_STREAM || socktype == SOCK_DGRAM)) return EAI_SOCKTYPE; *system_hints = *hints; system_hints->ai_protocol = IPPROTO_TCP; system_hints->ai_socktype = SOCK_STREAM; retval = getaddrinfo(node, service, system_hints, res); if (retval) return retval; if (socktype == 0) socktype = SOCK_STREAM; for (ai = *res; ai; ai = ai->ai_next) { ai->ai_protocol = IPPROTO_SCTP; ai->ai_socktype = socktype; } return 0; }#endif return getaddrinfo(node, service, hints, res);}/** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */void su_freeaddrinfo(su_addrinfo_t *res){ freeaddrinfo(res);}/** Return string describing address translation error. */char const *su_gai_strerror(int errcode){ return gai_strerror(errcode);}/** Resolve socket address into hostname and service name */intsu_getnameinfo(const su_sockaddr_t *su, size_t sulen, char *return_host, size_t hostlen, char *return_serv, size_t servlen, int flags){ return getnameinfo(&su->su_sa, sulen, return_host, hostlen, return_serv, servlen, flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -