+
+int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
+ char *restrict node, socklen_t nodelen,
+ char *restrict service, socklen_t servicelen,
+ int flags)
+{
+#ifdef WIN32_NATIVE
+ if (use_win32_p ())
+ return getnameinfo_ptr (sa, salen, node, nodelen,
+ service, servicelen, flags);
+#endif
+
+ /* FIXME: Support other flags. */
+ if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
+ (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
+ (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
+ return EAI_BADFLAGS;
+
+ if (sa == NULL || salen < sizeof (sa->sa_family))
+ return EAI_FAMILY;
+
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+ if (salen < sizeof (struct sockaddr_in))
+ return EAI_FAMILY;
+ break;
+#endif
+#if HAVE_IPV6
+ case AF_INET6:
+ if (salen < sizeof (struct sockaddr_in6))
+ return EAI_FAMILY;
+ break;
+#endif
+ default:
+ return EAI_FAMILY;
+ }
+
+ if (node && nodelen > 0 && flags & NI_NUMERICHOST)
+ {
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+ if (!inet_ntop (AF_INET,
+ &(((const struct sockaddr_in *) sa)->sin_addr),
+ node, nodelen))
+ return EAI_SYSTEM;
+ break;
+#endif
+
+#if HAVE_IPV6
+ case AF_INET6:
+ if (!inet_ntop (AF_INET6,
+ &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+ node, nodelen))
+ return EAI_SYSTEM;
+ break;
+#endif
+
+ default:
+ return EAI_FAMILY;
+ }
+ }
+
+ if (service && servicelen > 0 && flags & NI_NUMERICSERV)
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+#endif
+#if HAVE_IPV6
+ case AF_INET6:
+#endif
+ {
+ unsigned short int port
+ = ntohs (((const struct sockaddr_in *) sa)->sin_port);
+ if (servicelen <= snprintf (service, servicelen, "%u", port))
+ return EAI_OVERFLOW;
+ }
+ break;
+ }
+
+ return 0;
+}