diff --git a/libc/netdb/getnameinfo.c b/libc/netdb/getnameinfo.c index bd993a77..a84342d8 100644 --- a/libc/netdb/getnameinfo.c +++ b/libc/netdb/getnameinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Jonas 'Sortie' Termansen. + * Copyright (c) 2013, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,10 +17,16 @@ * Address-to-name translation in protocol-independent manner. */ -#include +#include +#include +#include +#include +#include +#include #include #include +#include int getnameinfo(const struct sockaddr* restrict sa, socklen_t salen, @@ -30,13 +36,45 @@ int getnameinfo(const struct sockaddr* restrict sa, socklen_t servlen, int flags) { - (void) sa; - (void) salen; - (void) host; - (void) hostlen; - (void) serv; - (void) servlen; - (void) flags; - fprintf(stderr, "%s is not implemented, aborting.\n", __func__); - abort(); + if ( flags & ~(NI_NOFQDN | NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | + NI_NUMERICSCOPE | NI_DGRAM) ) + return EAI_BADFLAGS; + int af; + if ( salen == sizeof(struct sockaddr_in) && + ((struct sockaddr_in*) sa)->sin_family == AF_INET ) + af = AF_INET; + else if ( salen == sizeof(struct sockaddr_in6) && + ((struct sockaddr_in6*) sa)->sin6_family == AF_INET6 ) + af = AF_INET6; + else + return EAI_FAMILY; + if ( !host && !serv ) + return EAI_NONAME; + if ( host ) + { + if ( flags & NI_NAMEREQD ) + return EAI_NONAME; + const void* addr; + if ( af == AF_INET ) + addr = &(((struct sockaddr_in*) sa)->sin_addr); + else if ( af == AF_INET6 ) + addr = &(((struct sockaddr_in6*) sa)->sin6_addr); + else + return EAI_FAMILY; + if ( !inet_ntop(af, addr, host, hostlen) ) + return errno == ENOSPC ? EAI_OVERFLOW : EAI_NONAME; + } + if ( serv ) + { + in_port_t port; + if ( af == AF_INET ) + port = be16toh(((struct sockaddr_in*) sa)->sin_port); + else if ( af == AF_INET6 ) + port = be16toh(((struct sockaddr_in6*) sa)->sin6_port); + else + return EAI_FAMILY; + if ( servlen <= (size_t) snprintf(serv, servlen, "%u", port) ) + return EAI_OVERFLOW; + } + return 0; }