summary refs log tree commit diff
path: root/sysdeps/posix/getaddrinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/posix/getaddrinfo.c')
-rw-r--r--sysdeps/posix/getaddrinfo.c913
1 files changed, 423 insertions, 490 deletions
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index fb9709fee7..fec30f97d7 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -44,92 +44,98 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /* getaddrinfo() v1.13 */
 
-/* To do what POSIX says, even when it's broken: */
-#define BROKEN_LIKE_POSIX 1
-#define LOCAL 1
-#define INET6 1
-#define HOSTTABLE 0
-#define RESOLVER 1
-
 #include <sys/types.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/socket.h>
-#if LOCAL
 #include <stdio.h>
 #include <string.h>
 #include <sys/utsname.h>
 #include <sys/un.h>
-#endif /* LOCAL */
 #include <netinet/in.h>
 #include <netdb.h>
 #include <errno.h>
 #include <arpa/inet.h>
 
-#ifndef AF_LOCAL
-#define AF_LOCAL AF_UNIX
-#endif /* AF_LOCAL */
-#ifndef PF_LOCAL
-#define PF_LOCAL PF_UNIX
-#endif /* PF_LOCAL */
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
-#endif /* UNIX_PATH_MAX */
-
 #define GAIH_OKIFUNSPEC 0x0100
 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
 
-#if HOSTTABLE
-struct hostent *_hostname2addr_hosts(const char *name, int);
-struct hostent *_addr2hostname_hosts(const char *name, int, int);
-#endif /* HOSTTABLE */
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX  108
+#endif
 
-static struct addrinfo nullreq =
-{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
+struct gaih_service
+  {
+    const char *name;
+    int num;
+  };
 
-struct gaih_service {
-  char *name;
-  int num;
-};
+struct gaih_servtuple
+  {
+    struct gaih_servtuple *next;
+    int socktype;
+    int protocol;
+    int port;
+  };
 
-struct gaih_servtuple {
-  struct gaih_servtuple *next;
-  int socktype;
-  int protocol;
-  int port;
-};
+static struct gaih_servtuple nullserv = { NULL, 0, 0, 0 };
 
-static struct gaih_servtuple nullserv = {
-  NULL, 0, 0, 0
-};
+struct gaih_addrtuple
+  {
+    struct gaih_addrtuple *next;
+    int family;
+    char addr[16];
+  };
 
-struct gaih_addrtuple {
-  struct gaih_addrtuple *next;
-  int family;
-  char addr[16];
-};
+struct gaih_typeproto
+  {
+    int socktype;
+    int protocol;
+    char *name;
+  };
 
-struct gaih_typeproto {
-  int socktype;
-  int protocol;
-  char *name;
+static struct gaih_typeproto gaih_inet_typeproto[] =
+{
+  { 0, 0, NULL },
+  { SOCK_STREAM, IPPROTO_TCP, (char *) "tcp" },
+  { SOCK_DGRAM, IPPROTO_UDP, (char *) "udp" },
+  { 0, 0, NULL }
 };
 
-#if LOCAL
-static int gaih_local(const char *name, const struct gaih_service *service,
-		     const struct addrinfo *req, struct addrinfo **pai)
+struct gaih
+  {
+    int family;
+    int (*gaih)(const char *name, const struct gaih_service *service,
+		const struct addrinfo *req, struct addrinfo **pai);
+  };
+
+static struct addrinfo default_hints =
+	{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
+
+
+static int
+gaih_local (const char *name, const struct gaih_service *service,
+	    const struct addrinfo *req, struct addrinfo **pai)
 {
   struct utsname utsname;
 
-  if (name || (req->ai_flags & AI_CANONNAME))
+  if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
     if (uname(&utsname))
       return -EAI_SYSTEM;
-  if (name) {
-    if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename))
-      return (GAIH_OKIFUNSPEC | -EAI_NONAME);
-  };
 
-  if (!(*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0))))
+  if (name != NULL)
+    {
+      if (strcmp(name, "localhost") &&
+	  strcmp(name, "local") &&
+	  strcmp(name, "unix") &&
+	  strcmp(name, utsname.nodename))
+	return GAIH_OKIFUNSPEC | -EAI_NONAME;
+    }
+
+  *pai = malloc (sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
+		 + ((req->ai_flags & AI_CANONNAME)
+		    ? (strlen(utsname.nodename) + 1): 0));
+  if (*pai == NULL)
     return -EAI_MEMORY;
 
   (*pai)->ai_next = NULL;
@@ -139,63 +145,79 @@ static int gaih_local(const char *name, const struct gaih_service *service,
   (*pai)->ai_protocol = req->ai_protocol;
   (*pai)->ai_addrlen = sizeof(struct sockaddr_un);
   (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
+
 #if SALEN
-  ((struct sockaddr_un *)(*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un);
+  ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
+    sizeof (struct sockaddr_un);
 #endif /* SALEN */
+
   ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
   memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
-  if (service) {
-    char *c;
-    if (c = strchr(service->name, '/')) {
-      if (strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
-        return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
-      strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
-    } else {
-      if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
-        return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
-      strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, P_tmpdir "/");
-      strcat(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
-    };
-  } else {
-    if (!tmpnam(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
-      return -EAI_SYSTEM;
-  };
+
+  if (service)
+    {
+      struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
+
+      if (strchr (service->name, '/') != NULL)
+	{
+	  if (strlen (service->name) >= sizeof (sunp->sun_path))
+	    return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+
+	  strcpy (sunp->sun_path, service->name);
+	}
+      else
+	{
+	  if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
+	      sizeof (sunp->sun_path))
+	    return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+
+	  __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
+	}
+    }
+  else
+    {
+      if (tmpnam (((struct sockaddr_un *) (*pai)->ai_addr)->sun_path) == NULL)
+	return -EAI_SYSTEM;
+    }
+
   if (req->ai_flags & AI_CANONNAME)
-    strcpy((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + sizeof(struct sockaddr_un), utsname.nodename);
+    strcpy ((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) +
+	    sizeof(struct sockaddr_un), utsname.nodename);
   else
     (*pai)->ai_canonname = NULL;
   return 0;
-};
-#endif /* LOCAL */
-
-static struct gaih_typeproto gaih_inet_typeproto[] =
-{
-  { 0, 0, NULL },
-  { SOCK_STREAM, IPPROTO_TCP, (char *) "tcp" },
-  { SOCK_DGRAM, IPPROTO_UDP, (char *) "udp" },
-  { 0, 0, NULL }
-};
+}
 
-static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st)
+static int
+gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp,
+	       struct gaih_servtuple **st)
 {
   struct servent *s;
-  int tmpbuflen = 1024;
+  size_t tmpbuflen = 1024;
   struct servent ts;
-  char *tmpbuf = __alloca (tmpbuflen);
-  while (__getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s))
+  char *tmpbuf;
+  int r;
+
+  do
     {
-      if (errno == ERANGE)
-	{
-	  tmpbuflen *= 2;
-	  tmpbuf = __alloca (tmpbuflen);
-	}
-      else
+      tmpbuf = __alloca (tmpbuflen);
+      if (tmpbuf == NULL)
+	return -EAI_MEMORY;
+
+      r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
+			     &s);
+      if (r)
 	{
-	  return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+	  if (errno == ERANGE)
+	    tmpbuflen *= 2;
+	  else
+	    return GAIH_OKIFUNSPEC | -EAI_SERVICE;
 	}
     }
+  while (r);
 
-  if (!(*st = malloc (sizeof (struct gaih_servtuple))))
+  *st = malloc (sizeof (struct gaih_servtuple));
+  if (*st == NULL)
     return -EAI_MEMORY;
 
   (*st)->next = NULL;
@@ -206,426 +228,330 @@ static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct g
   return 0;
 }
 
-static int gaih_inet(const char *name, const struct gaih_service *service,
-		     const struct addrinfo *req, struct addrinfo **pai)
+#define gethosts(_family, _type)				\
+ {								\
+  int i, herrno;						\
+  size_t tmpbuflen;						\
+  struct hostent th;						\
+  char *tmpbuf;							\
+  tmpbuflen = 512;						\
+  do {								\
+    tmpbuflen *= 2;						\
+    tmpbuf = __alloca (tmpbuflen);				\
+    if (tmpbuf == NULL)						\
+      return -EAI_MEMORY;					\
+    rc = __gethostbyname2_r (name, _family, &th, tmpbuf,	\
+         tmpbuflen, &h, &herrno);				\
+  } while ((rc != 0) &&						\
+    (herrno == NETDB_INTERNAL) && (errno == ERANGE));		\
+  if ((rc != 0) && (herrno == NETDB_INTERNAL))			\
+    {								\
+      __set_h_errno (herrno);					\
+      return -EAI_SYSTEM;					\
+    }								\
+  if (h != NULL)						\
+    {								\
+      for (i = 0; h->h_addr_list[i]; i++)			\
+	{							\
+	  if (*pat == NULL)					\
+	    {							\
+	      *pat = __alloca (sizeof(struct gaih_addrtuple));	\
+	      if (*pat == NULL)					\
+		return -EAI_MEMORY;				\
+	    }							\
+	  (*pat)->next = NULL;					\
+	  (*pat)->family = _family;				\
+	  memcpy ((*pat)->addr, h->h_addr_list[i],		\
+		 sizeof(_type));				\
+	  pat = &((*pat)->next);				\
+	}							\
+    }								\
+ }
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+	   const struct addrinfo *req, struct addrinfo **pai)
 {
   struct gaih_typeproto *tp = gaih_inet_typeproto;
   struct gaih_servtuple *st = &nullserv;
   struct gaih_addrtuple *at = NULL;
-  int i;
-
-  if (req->ai_protocol || req->ai_socktype) {
-    for (tp++; tp->name &&
-	  ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
-	  ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
-    if (!tp->name)
-      if (req->ai_socktype)
-	return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
-      else
-	return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
-  }
+  int rc;
 
-  if (service) {
-    if (service->num < 0) {
-      if (tp->name) {
-	if (i = gaih_inet_serv(service->name, tp, &st))
-	  return i;
-      } else {
-	struct gaih_servtuple **pst = &st;
-	for (tp++; tp->name; tp++) {
-	  if (i = gaih_inet_serv(service->name, tp, pst)) {
-	    if (i & GAIH_OKIFUNSPEC)
-	      continue;
-	    goto ret;
-	  }
-	  pst = &((*pst)->next);
+  if (req->ai_protocol || req->ai_socktype)
+    {
+      for (tp++; tp->name &&
+	     ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
+	     ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
+      if (tp->name == NULL)
+	if (req->ai_socktype)
+	  return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+	else
+	  return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+    }
+
+  if (service != NULL)
+    {
+      if (service->num < 0)
+	{
+	  if (tp->name != NULL)
+	    {
+	      if (rc = gaih_inet_serv (service->name, tp, &st))
+		return rc;
+	    }
+	  else
+	    {
+	      struct gaih_servtuple **pst = &st;
+	      for (tp++; tp->name; tp++)
+		{
+		  if (rc = gaih_inet_serv (service->name, tp, pst))
+		    {
+		      if (rc & GAIH_OKIFUNSPEC)
+			continue;
+		      return rc;
+		    }
+		  pst = &((*pst)->next);
+		}
+	      if (st == &nullserv)
+		return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+	    }
 	}
-	if (st == &nullserv) {
-	  i = (GAIH_OKIFUNSPEC | -EAI_SERVICE);
-	  goto ret;
+      else
+	{
+	  st = __alloca (sizeof(struct gaih_servtuple));
+	  if (st == NULL)
+	    return -EAI_MEMORY;
+
+	  st->next = NULL;
+	  st->socktype = tp->socktype;
+	  st->protocol = tp->protocol;
+	  st->port = htons (service->num);
 	}
-      }
-    } else {
-      if (!(st = malloc(sizeof(struct gaih_servtuple))))
+    }
+
+  if (name != NULL)
+    {
+      at = __alloca (sizeof(struct gaih_addrtuple));
+      if (at == NULL)
 	return -EAI_MEMORY;
 
-      st->next = NULL;
-      st->socktype = tp->socktype;
-      st->protocol = tp->protocol;
-      st->port = htons(service->num);
-    }
-  }
+      at->family = 0;
+      at->next = NULL;
 
-  if (name) {
-    if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
-      i = -EAI_MEMORY;
-      goto ret;
-    }
+      if (at->family || !req->ai_family || (req->ai_family == AF_INET))
+	if (inet_pton (AF_INET, name, at->addr) > 0)
+	  at->family = AF_INET;
 
-    at->family = 0;
-    at->next = NULL;
-
-    if (!at->family || !req->ai_family || (req->ai_family == AF_INET))
-      if (inet_pton(AF_INET, name, at->addr) > 0)
-	at->family = AF_INET;
-
-#if INET6
-    if (!at->family && (!req->ai_family || (req->ai_family == AF_INET6)))
-      if (inet_pton(AF_INET6, name, at->addr) > 0)
-	at->family = AF_INET6;
-#endif /* INET6 */
-
-#if HOSTTABLE
-    if (!at->family) {
-      struct hostent *h;
-      struct gaih_addrtuple **pat = &at;
-
-#if INET6
-      if (!req->ai_family || (req->ai_family == AF_INET6))
-	if (h = _hostname2addr_hosts(name, AF_INET6)) {
-	  for (i = 0; h->h_addr_list[i]; i++) {
-	    if (!*pat) {
-	      if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
-		i = -EAI_MEMORY;
-		goto ret;
-	      }
-	    }
-	    (*pat)->next = NULL;
-	    (*pat)->family = AF_INET6;
-	    memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr));
-	    pat = &((*pat)->next);
-	  }
-	}
-#endif /* INET6 */
-
-      if (!req->ai_family || (req->ai_family == AF_INET))
-	if (h = _hostname2addr_hosts(name, AF_INET)) {
-	  for (i = 0; h->h_addr_list[i]; i++) {
-	    if (!*pat) {
-	      if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
-		i = -EAI_MEMORY;
-		goto ret;
-	      }
-	    }
-	    (*pat)->next = NULL;
-	    (*pat)->family = AF_INET;
-	    memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr));
-	    pat = &((*pat)->next);
-	  }
+      if (!at->family && (!req->ai_family || (req->ai_family == AF_INET6)))
+	if (inet_pton (AF_INET6, name, at->addr) > 0)
+	  at->family = AF_INET6;
+
+      if (at->family == AF_UNSPEC)
+	{
+	  struct hostent *h;
+	  struct gaih_addrtuple **pat = &at;
+
+	  if ((req->ai_family == AF_UNSPEC) || (req->ai_family == AF_INET6))
+	    gethosts (AF_INET6, struct in6_addr);
+
+	  if ((req->ai_family == AF_UNSPEC) || (req->ai_family == AF_INET))
+	    gethosts (AF_INET, struct in_addr);
 	}
+
+      if (at->family == AF_UNSPEC)
+	return (GAIH_OKIFUNSPEC | -EAI_NONAME);
+
     }
-#endif /* HOSTTABLE */
-
-#if RESOLVER
-    if (!at->family) {
-      struct hostent *h;
-      struct gaih_addrtuple **pat = &at;
-
-#if INET6
-      if (!req->ai_family || (req->ai_family == AF_INET6)) {
-	int herrno;
-	int tmpbuflen = 1024;
-	struct hostent th;
-	char *tmpbuf = __alloca(tmpbuflen);
-	while (__gethostbyname2_r(name, AF_INET6, &th, tmpbuf, tmpbuflen,
-				  &h, &herrno)) {
-	  if (herrno == NETDB_INTERNAL) {
-	    if (errno == ERANGE) {
-	      /* Need more buffer */
-	      tmpbuflen *= 2;
-	      tmpbuf = __alloca(tmpbuflen);
-	    } else {
-	      /* Bail out */
-	      __set_h_errno(herrno);
-	      i = -EAI_SYSTEM;
-	      goto ret;
-	    }
-	  } else {
-	    break;
-	  }
-	}
-	if (h) {
-	  for (i = 0; h->h_addr_list[i]; i++) {
-	    if (!*pat) {
-	      if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
-		i = -EAI_MEMORY;
-		goto ret;
-	      }
-	    }
-	    (*pat)->next = NULL;
-	    (*pat)->family = AF_INET6;
-	    memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr));
-	    pat = &((*pat)->next);
-	  }
-	}
-      }
-#endif /* INET6 */
-
-      if (!req->ai_family || (req->ai_family == AF_INET)) {
-	int herrno;
-	struct hostent th;
-	int tmpbuflen = 1024;
-	char *tmpbuf = __alloca(tmpbuflen);
-	while (__gethostbyname2_r(name, AF_INET, &th, tmpbuf, tmpbuflen,
-				&h, &herrno)) {
-	  if (herrno == NETDB_INTERNAL) {
-	    if (errno == ERANGE) {
-	      /* Need more buffer */
-	      tmpbuflen *= 2;
-	      tmpbuf = __alloca(tmpbuflen);
-	    } else {
-	      /* Bail out */
-	      __set_h_errno(herrno);
-	      i = -EAI_SYSTEM;
-	      goto ret;
-	    }
-	  } else {
-	    break;
-	  }
-	}
-	if (h) {
-	  for (i = 0; h->h_addr_list[i]; i++) {
-	    if (!*pat) {
-	      if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
-		i = -EAI_MEMORY;
-		goto ret;
-	      }
-	    }
-	    (*pat)->next = NULL;
-	    (*pat)->family = AF_INET;
-	    memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr));
-	    pat = &((*pat)->next);
-	  }
-	}
-      }
+  else
+    {
+      at = __alloca (sizeof(struct gaih_addrtuple));
+      if (at == NULL)
+	return -EAI_MEMORY;
+
+      memset (at, 0, sizeof(struct gaih_addrtuple));
+
+      at->next = __alloca (sizeof(struct gaih_addrtuple));
+      if (at->next == NULL)
+	return -EAI_MEMORY;
+
+      at->family = AF_INET6;
+
+      memset (at->next, 0, sizeof(struct gaih_addrtuple));
+      at->next->family = AF_INET;
     }
-#endif /* RESOLVER */
-
-    if (!at->family)
-      return (GAIH_OKIFUNSPEC | -EAI_NONAME);
-  } else {
-    if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
-      i = -EAI_MEMORY;
-      goto ret;
-    };
-
-    memset(at, 0, sizeof(struct gaih_addrtuple));
-
-#if INET6
-    if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) {
-      i = -EAI_MEMORY;
-      goto ret;
-    };
-
-    at->family = AF_INET6;
-
-    memset(at->next, 0, sizeof(struct gaih_addrtuple));
-    at->next->family = AF_INET;
-#else /* INET6 */
-    at->family = AF_INET;
-#endif /* INET6 */
-  };
 
-  if (!pai) {
-    i = 0;
-    goto ret;
-  };
+  if (pai == NULL)
+    return 0;
 
   {
     const char *c = NULL;
     struct gaih_servtuple *st2;
     struct gaih_addrtuple *at2 = at;
-    int j;
+    size_t socklen, namelen;
+
     /*
       buffer is the size of an unformatted IPv6 address in printable format.
      */
     char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
 
-    while(at2) {
-      if (req->ai_flags & AI_CANONNAME) {
-        struct hostent *h = NULL;
-
-#if RESOLVER
-        int herrno;
-	struct hostent th;
-	int tmpbuflen = 1024;
-	char *tmpbuf = __alloca(tmpbuflen);
-	while (__gethostbyaddr_r(at2->addr,
-#if INET6
-	    (at2->family == AF_INET6) ? sizeof(struct in6_addr) :
-#endif /* INET6 */
-				 sizeof(struct in_addr), at2->family,
-				 &th, tmpbuf, tmpbuflen, &h, &herrno)) {
-	  if (herrno == NETDB_INTERNAL) {
-	    if (errno == ERANGE) {
-	      /* Need more buffer */
-	      tmpbuflen *= 2;
-	      tmpbuf = __alloca(tmpbuflen);
-	    } else {
-	      /* Bail out */
-	      __set_h_errno(herrno);
-	      i = -EAI_SYSTEM;
-	      goto ret;
-	    }
-	  } else {
-	    break;
-	  }
-	}
-#endif /* RESOLVER */
-#if HOSTTABLE
-	if (!h)
-	  h = _addr2hostname_hosts(at2->addr,
-#if INET6
-	    (at2->family == AF_INET6) ? sizeof(struct in6_addr) :
-#endif /* INET6 */
-	    sizeof(struct in_addr), at2->family);
-#endif /* HOSTTABLE */
-
-	if (!h)
-          c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
-	else
-          c = h->h_name;
+    while (at2 != NULL)
+      {
+	if (req->ai_flags & AI_CANONNAME)
+	  {
+	    struct hostent *h = NULL;
 
-	if (!c) {
-	  i = (GAIH_OKIFUNSPEC | -EAI_NONAME);
-	  goto ret;
-	}
+	    int herrno;
+	    struct hostent th;
+	    size_t tmpbuflen = 512;
+	    char *tmpbuf;
 
-	j = strlen(c) + 1;
-      } else
-	j = 0;
+	    do
+	      {
+		tmpbuflen *= 2;
+		tmpbuf = __alloca (tmpbuflen);
 
-#if INET6
-      if (at2->family == AF_INET6)
-	i = sizeof(struct sockaddr_in6);
-      else
-#endif /* INET6 */
-	i = sizeof(struct sockaddr_in);
-
-      st2 = st;
-      while(st2) {
-	if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) {
-	  i = -EAI_MEMORY;
-	  goto ret;
-	}
-	(*pai)->ai_flags = req->ai_flags;
-	(*pai)->ai_family = at2->family;
-	(*pai)->ai_socktype = st2->socktype;
-	(*pai)->ai_protocol = st2->protocol;
-	(*pai)->ai_addrlen = i;
-	(*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
+		if (tmpbuf == NULL)
+		  return -EAI_MEMORY;
+
+		rc = __gethostbyaddr_r (at2->addr,
+					((at2->family == AF_INET6)
+					 ? sizeof(struct in6_addr)
+					 : sizeof(struct in_addr)),
+					at2->family, &th, tmpbuf, tmpbuflen,
+					&h, &herrno);
+
+	      }
+	    while ((rc != 0) && (herrno == NETDB_INTERNAL)
+		   && (errno == ERANGE));
+
+	    if ((rc != 0) && (herrno == NETDB_INTERNAL))
+	      {
+		__set_h_errno (herrno);
+		return -EAI_SYSTEM;
+	      }
+
+	    if (h == NULL)
+	      c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
+	    else
+	      c = h->h_name;
+
+	    if (c == NULL)
+	      return GAIH_OKIFUNSPEC | -EAI_NONAME;
+
+	    namelen = strlen (c) + 1;
+	  }
+	else
+	  namelen = 0;
+
+	if (at2->family == AF_INET6)
+	  socklen = sizeof (struct sockaddr_in6);
+	else
+	  socklen = sizeof (struct sockaddr_in);
+
+	for (st2 = st; st2 != NULL; st2 = st2->next)
+	  {
+	    *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
+	    if (*pai == NULL)
+	      return -EAI_MEMORY;
+
+	    (*pai)->ai_flags = req->ai_flags;
+	    (*pai)->ai_family = at2->family;
+	    (*pai)->ai_socktype = st2->socktype;
+	    (*pai)->ai_protocol = st2->protocol;
+	    (*pai)->ai_addrlen = socklen;
+	    (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
 #if SALEN
-	((struct sockaddr_in *)(*pai)->ai_addr)->sin_len = i;
+	    ((struct sockaddr_in *) (*pai)->ai_addr)->sin_len = i;
 #endif /* SALEN */
-	((struct sockaddr_in *)(*pai)->ai_addr)->sin_family = at2->family;
-	((struct sockaddr_in *)(*pai)->ai_addr)->sin_port = st2->port;
-
-#if INET6
-	if (at2->family == AF_INET6) {
-	  ((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_flowinfo = 0;
-	  memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr));
-	} else
-#endif /* INET6 */
-	{
-	  memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr));
-	  memset(((struct sockaddr_in *)(*pai)->ai_addr)->sin_zero, 0, sizeof(((struct sockaddr_in *)(*pai)->ai_addr)->sin_zero));
-	}
+	    ((struct sockaddr_in *) (*pai)->ai_addr)->sin_family = at2->family;
+	    ((struct sockaddr_in *) (*pai)->ai_addr)->sin_port = st2->port;
 
-	if (c) {
-	  (*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i;
-	  strcpy((*pai)->ai_canonname, c);
-	} else
-	  (*pai)->ai_canonname = NULL;
-	(*pai)->ai_next = NULL;
+	    if (at2->family == AF_INET6)
+	      {
+		struct sockaddr_in6 *sin6p =
+		  (struct sockaddr_in6 *) (*pai)->ai_addr;
 
-	pai = &((*pai)->ai_next);
+		sin6p->sin6_flowinfo = 0;
+		memcpy (&sin6p->sin6_addr,
+			at2->addr, sizeof (struct in6_addr));
+	      }
+	    else
+	      {
+		struct sockaddr_in *sinp =
+		  (struct sockaddr_in *) (*pai)->ai_addr;
+		memcpy (&sinp->sin_addr,
+			at2->addr, sizeof (struct in_addr));
+		memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+	      }
 
-	st2 = st2->next;
-      }
-      at2 = at2->next;
-    }
-  }
+	    if (c)
+	      {
+		(*pai)->ai_canonname = ((void *) (*pai) +
+					sizeof (struct addrinfo) + socklen);
+		strcpy ((*pai)->ai_canonname, c);
+	      }
+	    else
+	      (*pai)->ai_canonname = NULL;
 
-  i = 0;
+	    (*pai)->ai_next = NULL;
+	    pai = &((*pai)->ai_next);
+	  }
 
-ret:
-  if (st != &nullserv) {
-    struct gaih_servtuple *st2 = st;
-    while(st) {
-      st2 = st->next;
-      free(st);
-      st = st2;
-    }
-  }
-  if (at) {
-    struct gaih_addrtuple *at2 = at;
-    while(at) {
-      at2 = at->next;
-      free(at);
-      at = at2;
-    }
+	at2 = at2->next;
+      }
   }
-  return i;
+  return 0;
 }
 
-struct gaih {
-  int family;
-  int (*gaih)(const char *name, const struct gaih_service *service,
-	      const struct addrinfo *req, struct addrinfo **pai);
-};
-
-static struct gaih gaih[] = {
-#if INET6
-  { PF_INET6, gaih_inet },
-#endif /* INET6 */
-  { PF_INET, gaih_inet },
-#if LOCAL
-  { PF_LOCAL, gaih_local },
-#endif /* LOCAL */
-  { PF_UNSPEC, NULL }
-};
+static struct gaih gaih[] =
+  {
+    { PF_INET6, gaih_inet },
+    { PF_INET, gaih_inet },
+    { PF_LOCAL, gaih_local },
+    { PF_UNSPEC, NULL }
+  };
 
-int getaddrinfo(const char *name, const char *service,
-		const struct addrinfo *req, struct addrinfo **pai)
+int
+getaddrinfo (const char *name, const char *service,
+	     const struct addrinfo *hints, struct addrinfo **pai)
 {
   int i = 0, j = 0;
   struct addrinfo *p = NULL, **end;
   struct gaih *g = gaih, *pg = NULL;
   struct gaih_service gaih_service, *pservice;
 
-  if (name && (name[0] == '*') && !name[1])
+  if (name != NULL && name[0] == '*' && name[1] == 0)
     name = NULL;
 
-  if (service && (service[0] == '*') && !service[1])
+  if (service != NULL && service[0] == '*' && service[1] == 0)
     service = NULL;
 
-#if BROKEN_LIKE_POSIX
-  if (!name && !service)
+  if (name == NULL && service == NULL)
     return EAI_NONAME;
-#endif /* BROKEN_LIKE_POSIX */
 
-  if (!req)
-    req = &nullreq;
+  if (hints == NULL)
+    hints = &default_hints;
 
-  if (req->ai_flags & ~3)
+  if (hints->ai_flags & ~3)
     return EAI_BADFLAGS;
 
-  if ((req->ai_flags & AI_CANONNAME) && !name)
+  if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
     return EAI_BADFLAGS;
 
-  if (service && *service) {
-    char *c;
-    gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10);
-    if (*c) {
-      gaih_service.num = -1;
-    }
-#if BROKEN_LIKE_POSIX
+  if (service && service[0])
+    {
+      char *c;
+      gaih_service.name = service;
+      gaih_service.num = strtoul (gaih_service.name, &c, 10);
+      if (*c)
+	gaih_service.num = -1;
       else
-        if (!req->ai_socktype)
+	/* Can't specify a numerical socket unless a protocol family was
+	   given. */
+        if (hints->ai_socktype == 0)
           return EAI_SERVICE;
-#endif /* BROKEN_LIKE_POSIX */
-    pservice = &gaih_service;
-  } else
+      pservice = &gaih_service;
+    }
+  else
     pservice = NULL;
 
   if (pai)
@@ -633,51 +559,58 @@ int getaddrinfo(const char *name, const char *service,
   else
     end = NULL;
 
-  while(g->gaih) {
-    if ((req->ai_family == g->family) || !req->ai_family) {
-      j++;
-      if (!((pg && (pg->gaih == g->gaih)))) {
-	pg = g;
-	if (i = g->gaih(name, pservice, req, end)) {
-	  if (!req->ai_family && (i & GAIH_OKIFUNSPEC))
-	    continue;
-	  goto gaih_err;
+  while (g->gaih)
+    {
+      if ((hints->ai_family == g->family) || (hints->ai_family == AF_UNSPEC))
+	{
+	  j++;
+	  if ((pg == NULL) || (pg->gaih != g->gaih))
+	    {
+	      pg = g;
+	      if (i = g->gaih (name, pservice, hints, end))
+		{
+		  if ((hints->ai_family == AF_UNSPEC) && (i & GAIH_OKIFUNSPEC))
+		    continue;
+
+		  if (p)
+		    freeaddrinfo (p);
+
+		  return (i)?-(i & GAIH_EAI):EAI_NONAME;
+		}
+	      if (end)
+		while(*end) end = &((*end)->ai_next);
+	    }
 	}
-	if (end)
-          while(*end) end = &((*end)->ai_next);
-      }
+      ++g;
     }
-    g++;
-  }
 
-  if (!j)
+  if (j == 0)
     return EAI_FAMILY;
 
-  if (p) {
-    *pai = p;
-    return 0;
-  }
+  if (p)
+    {
+      *pai = p;
+      return 0;
+    }
 
-  if (!pai && !i)
+  if (pai == NULL && i == 0)
     return 0;
 
-gaih_err:
   if (p)
-    freeaddrinfo(p);
-
-  if (i)
-    return -(i & GAIH_EAI);
+    freeaddrinfo (p);
 
-  return EAI_NONAME;
+  return i ? -(i & GAIH_EAI) : EAI_NONAME;
 }
 
-void freeaddrinfo(struct addrinfo *ai)
+void
+freeaddrinfo (struct addrinfo *ai)
 {
   struct addrinfo *p;
 
-  while(ai) {
-    p = ai;
-    ai = ai->ai_next;
-    free((void *)p);
-  }
+  while (ai != NULL)
+    {
+      p = ai;
+      ai = ai->ai_next;
+      free (p);
+    }
 }