/* * Copyright (c) 1996 W. Richard Stevens. All rights reserved. * * Permission to use or modify this software for educational or * for commercial purposes, and without fee, is hereby granted, * provided that the above copyright notice appears in connection * with any and all uses, with clear indication as to any * modifications made. The author RESERVES the sole rights of * reproduction, publication and distribution and hence permission * to print this source code in any book, reference manual, * magazine, or other type of publication, including any digital * medium, must be granted in writing by W. Richard Stevens. * * The author makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express * or implied warranty. */ /* tabs set for 4 spaces, not 8 */ #include #include #include #include /* hostent{}, servent{}, etc. */ #include /* strncpy() */ #include /* We need a way to determine if the compiling host supports IPv4/IPv6. Cannot test for AF_INET6, as some vendors #define it, even though they don't support it. */ #ifdef AF_INET #define IPV4 /* this is tested throughout the code that follows */ #endif #ifdef IPV6ADDR_ANY_INIT #define IPV6 /* this is tested throughout the code that follows */ #endif const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len); /* function prototypes for our own internal functions */ static int do_ipv46(char *, size_t, char *, size_t, void *, size_t, int, int, int flags); int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { switch (sa->sa_family) { #ifdef IPV4 case AF_INET: { struct sockaddr_in *sain = (struct sockaddr_in *) sa; return(do_ipv46(host, hostlen, serv, servlen, &sain->sin_addr, sizeof(struct in_addr), AF_INET, sain->sin_port, flags)); } #endif /* IPV4 */ #ifdef IPV6 case AF_INET6: { struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa; return(do_ipv46(host, hostlen, serv, servlen, &sain->sin6_addr, sizeof(struct in6_addr), AF_INET6, sain->sin6_port, flags)); } #endif /* IPV6 */ default: return(1); } } /* * Handle either an IPv4 or an IPv6 address and port. */ static int do_ipv46(char *host, size_t hostlen, char *serv, size_t servlen, void *aptr, size_t alen, int family, int port, int flags) { char *ptr; struct hostent *hptr; struct servent *sptr; if (hostlen > 0) { if (flags & NI_NUMERICHOST) { if (inet_ntop(family, aptr, host, hostlen) == NULL) return(1); } else { hptr = gethostbyaddr(aptr, alen, family); if (hptr != NULL && hptr->h_name != NULL) { if (flags & NI_NOFQDN) { if ( (ptr = strchr(hptr->h_name, '.')) != NULL) *ptr = 0; /* overwrite first dot */ } strncpy(host, hptr->h_name, hostlen); } else { if (flags & NI_NAMEREQD) return(1); if (inet_ntop(family, aptr, host, hostlen) == NULL) return(1); } } } if (servlen > 0) { if (flags & NI_NUMERICSERV) { snprintf(serv, servlen, "%d", ntohs(port)); } else { sptr = getservbyport(port, (flags & NI_DGRAM) ? "udp" : NULL); if (sptr != NULL && sptr->s_name != NULL) strncpy(serv, sptr->s_name, servlen); else snprintf(serv, servlen, "%d", ntohs(port)); } } return(0); }