summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--inet/getnameinfo.c40
-rw-r--r--sysdeps/posix/getaddrinfo.c125
3 files changed, 143 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index f5a2eec483..185ce2201e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2002-11-20  Ulrich Drepper  <drepper@redhat.com>
+
+	* inet/getnameinfo.c: Use extend_alloca where appropriate.
+	* sysdeps/posix/getaddrinfo.c: Likewise.
+
+	* include/alloca.h (extend_alloca): New define.  Based on stack
+	direction it'll try to append to the previouls allocated buffer.
+
+2002-11-07  Thorsten Kukuk  <kukuk@suse.de>
+
+	* sysdeps/posix/getaddrinfo.c (gaih_inet): If AF_UNSPEC is set,
+	use the same service for AF_INET and AF_INET6.
+
+2002-11-19  Ulrich Drepper  <drepper@redhat.com>
+
+	* intl/localealias.c (read_alias_file): Use only about 400 bytes
+	of stack space instead of 16k.
+
 2002-11-18  Wolfram Gloger  <wg@malloc.de>
 
 	* malloc/arena.c
diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c
index 063bec4c79..50197f8672 100644
--- a/inet/getnameinfo.c
+++ b/inet/getnameinfo.c
@@ -82,10 +82,7 @@ nrl_domainname (void)
 				    &herror))
 	    {
 	      if (herror == NETDB_INTERNAL && errno == ERANGE)
-		{
-		  tmpbuflen *= 2;
-		  tmpbuf = alloca (tmpbuflen);
-		}
+		tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
 	      else
 		break;
 	    }
@@ -97,10 +94,7 @@ nrl_domainname (void)
 	      /* The name contains no domain information.  Use the name
 		 now to get more information.  */
 	      while (__gethostname (tmpbuf, tmpbuflen))
-		{
-		  tmpbuflen *= 2;
-		  tmpbuf = alloca (tmpbuflen);
-		}
+		tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
 
 	      if ((c = strchr (tmpbuf, '.')))
 		domain = __strdup (++c);
@@ -113,10 +107,8 @@ nrl_domainname (void)
 					    &h, &herror))
 		    {
 		      if (herror == NETDB_INTERNAL && errno == ERANGE)
-			{
-			  tmpbuflen *= 2;
-			  tmpbuf = alloca (tmpbuflen);
-			}
+			tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+						2 * tmpbuflen);
 		      else
 			break;
 		    }
@@ -135,10 +127,8 @@ nrl_domainname (void)
 						tmpbuflen, &h, &herror))
 			{
 			  if (herror == NETDB_INTERNAL && errno == ERANGE)
-			    {
-			      tmpbuflen *= 2;
-			      tmpbuf = alloca (tmpbuflen);
-			    }
+			    tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+						    2 * tmpbuflen);
 			  else
 			    break;
 			}
@@ -213,10 +203,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
 			if (herrno == NETDB_INTERNAL)
 			  {
 			    if (errno == ERANGE)
-			      {
-				tmpbuflen *= 2;
-				tmpbuf = alloca (tmpbuflen);
-			      }
+			      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+						      2 * tmpbuflen);
 			    else
 			      {
 				__set_h_errno (herrno);
@@ -238,10 +226,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
 					      &h, &herrno))
 		      {
 			if (errno == ERANGE)
-			  {
-			    tmpbuflen *= 2;
-			    tmpbuf = alloca (tmpbuflen);
-			  }
+			  tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+						  2 * tmpbuflen);
 			else
 			  {
 			    break;
@@ -384,10 +370,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
 		if (herrno == NETDB_INTERNAL)
 		  {
 		    if (errno == ERANGE)
-		      {
-			tmpbuflen *= 2;
-			tmpbuf = __alloca (tmpbuflen);
-		      }
+		      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+					      2 * tmpbuflen);
 		    else
 		      {
 			__set_errno (serrno);
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 2dc5e90a32..3ba4bde25e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -50,6 +50,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sys/un.h>
 #include <sys/utsname.h>
 #include <net/if.h>
+#include <nsswitch.h>
 
 #define GAIH_OKIFUNSPEC 0x0100
 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
@@ -269,12 +270,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   int i, herrno;						\
   size_t tmpbuflen;						\
   struct hostent th;						\
-  char *tmpbuf;							\
+  char *tmpbuf = NULL;							\
   tmpbuflen = 512;						\
   no_data = 0;							\
   do {								\
-    tmpbuflen *= 2;						\
-    tmpbuf = __alloca (tmpbuflen);				\
+    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);	\
     rc = __gethostbyname2_r (name, _family, &th, tmpbuf,	\
          tmpbuflen, &h, &herrno);				\
   } while (rc == ERANGE && herrno == NETDB_INTERNAL);		\
@@ -295,7 +295,7 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
       for (i = 0; h->h_addr_list[i]; i++)			\
 	{							\
 	  if (*pat == NULL) {					\
-	    *pat = __alloca (sizeof(struct gaih_addrtuple));	\
+	    *pat = __alloca (sizeof (struct gaih_addrtuple));	\
 	    (*pat)->scopeid = 0;				\
 	  }							\
 	  (*pat)->next = NULL;					\
@@ -307,6 +307,59 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
     }								\
  }
 
+#define gethosts2(_family, _type)				\
+ {								\
+  int i, herrno;						\
+  size_t tmpbuflen;						\
+  struct hostent th;						\
+  char *tmpbuf = NULL;						\
+  tmpbuflen = 512;						\
+  no_data = 0;							\
+  do {								\
+    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);	\
+    rc = 0;							\
+    status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf,	\
+           tmpbuflen, &rc, &herrno));			        \
+  } while (rc == ERANGE && herrno == NETDB_INTERNAL);		\
+  if (status == NSS_STATUS_SUCCESS && rc == 0)			\
+    h = &th;							\
+  else								\
+    h = NULL;							\
+  if (rc != 0)							\
+    {								\
+      if (herrno == NETDB_INTERNAL)				\
+	{							\
+	  __set_h_errno (herrno);				\
+	  return -EAI_SYSTEM;					\
+	}							\
+      if (herrno == TRY_AGAIN)					\
+	no_data = EAI_AGAIN;					\
+      else							\
+	no_data = herrno == NO_DATA;				\
+    }								\
+  else if (h != NULL)						\
+    {								\
+      for (i = 0; h->h_addr_list[i]; i++)			\
+	{							\
+	  if (*pat == NULL) {					\
+	    *pat = __alloca (sizeof (struct gaih_addrtuple));	\
+	    (*pat)->scopeid = 0;				\
+	  }							\
+	  (*pat)->next = NULL;					\
+	  (*pat)->family = _family;				\
+	  memcpy ((*pat)->addr, h->h_addr_list[i],		\
+		 sizeof(_type));				\
+	  pat = &((*pat)->next);				\
+	}							\
+    }								\
+ }
+
+typedef enum nss_status (*nss_gethostbyname2_r)
+  (const char *name, int af, struct hostent *host,
+   char *buffer, size_t buflen, int *errnop,
+   int *h_errnop);
+extern service_user *__nss_hosts_database attribute_hidden;
+
 static int
 gaih_inet (const char *name, const struct gaih_service *service,
 	   const struct addrinfo *req, struct addrinfo **pai)
@@ -488,7 +541,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  struct hostent *h;
 	  struct gaih_addrtuple **pat = &at;
 	  int no_data = 0;
-	  int no_inet6_data;
+	  int no_inet6_data = 0;
 	  int old_res_options = _res.options;
 
 	  /* If we are looking for both IPv4 and IPv6 address we don't
@@ -496,16 +549,64 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	     addresses to IPv6 addresses.  Currently this is decided
 	     by setting the RES_USE_INET6 bit in _res.options.  */
 	  if (req->ai_family == AF_UNSPEC)
-	    _res.options &= ~RES_USE_INET6;
+	    {
+	      service_user *nip = NULL;
+	      enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
+	      int no_more;
+	      nss_gethostbyname2_r fct;
 
-	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
-	    gethosts (AF_INET6, struct in6_addr);
-	  no_inet6_data = no_data;
+	      if (__nss_hosts_database != NULL)
+		{
+		  no_more = 0;
+		  nip = __nss_hosts_database;
+		}
+	      else
+		no_more = __nss_database_lookup ("hosts", NULL,
+						 "dns [!UNAVAIL=return] files", &nip);
 
-	  if (req->ai_family == AF_UNSPEC)
-	    _res.options = old_res_options;
+	      _res.options &= ~RES_USE_INET6;
 
-	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+	      while (!no_more)
+		{
+		  fct = __nss_lookup_function (nip, "gethostbyname2_r");
+
+		  gethosts2 (AF_INET6, struct in6_addr);
+		  no_inet6_data = no_data;
+		  inet6_status = status;
+		  gethosts2 (AF_INET, struct in_addr);
+
+		  /* If we found one address for AF_INET or AF_INET6,
+		     don't continue the search.  */
+		  if (inet6_status == NSS_STATUS_SUCCESS ||
+		      status == NSS_STATUS_SUCCESS)
+		    break;
+
+		  /* We can have different states for AF_INET
+		     and AF_INET6. Try to find a usefull one for
+		     both.  */
+		  if (inet6_status == NSS_STATUS_TRYAGAIN)
+		    status = NSS_STATUS_TRYAGAIN;
+		  else if (status == NSS_STATUS_UNAVAIL &&
+			   inet6_status != NSS_STATUS_UNAVAIL)
+		    status = inet6_status;
+
+		  if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+		    break;
+
+		  if (nip->next == NULL)
+		    no_more = -1;
+		  else
+		    nip = nip->next;
+		}
+
+	      _res.options = old_res_options;
+	    }
+	  else if (req->ai_family == AF_INET6)
+	    {
+	      gethosts (AF_INET6, struct in6_addr);
+	      no_inet6_data = no_data;
+	    }
+	  else if (req->ai_family == AF_INET)
 	    gethosts (AF_INET, struct in_addr);
 
 	  if (no_data != 0 && no_inet6_data != 0)