Admin Panel
/*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /* hostent{}, servent{}, etc. */
#include <string.h> /* strncpy() */
#include <stdio.h>
/* 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);
}