diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
commit | 0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch) | |
tree | 6eaef0d8a720fa3da580de87b647fff796fe80b3 /src/network/getnameinfo.c | |
download | musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz |
initial check-in, version 0.5.0v0.5.0
Diffstat (limited to 'src/network/getnameinfo.c')
-rw-r--r-- | src/network/getnameinfo.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c new file mode 100644 index 00000000..0763ca88 --- /dev/null +++ b/src/network/getnameinfo.c @@ -0,0 +1,54 @@ +#include <netdb.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "__dns.h" + +int getnameinfo(const struct sockaddr *sa, socklen_t sl, + char *node, socklen_t nodelen, + char *serv, socklen_t servlen, + int flags) +{ + char buf[256]; + unsigned char reply[512]; + int af = sa->sa_family; + unsigned char *a; + + switch (af) { + case AF_INET: + a = (void *)&((struct sockaddr_in *)sa)->sin_addr; + if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY; + break; + case AF_INET6: + a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; + if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY; + break; + default: + return EAI_FAMILY; + } + + if (node && nodelen) { + if ((flags & NI_NUMERICHOST) + || __dns_query(reply, a, af, 1) <= 0 + || __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0) + { + if (flags & NI_NAMEREQD) return EAI_NONAME; + inet_ntop(af, a, buf, sizeof buf); + } + if (strlen(buf) >= nodelen) return EAI_OVERFLOW; + strcpy(node, buf); + } + + if (serv && servlen) { + if (snprintf(buf, sizeof buf, "%d", + ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen) + return EAI_OVERFLOW; + strcpy(serv, buf); + } + + return 0; +} |