فهرست منبع

improve gethostbyname2_r using new resolver backend

these changes reduce the size of the function somewhat and remove many
of its dependencies, including free. in principle it should now be
async-signal-safe, but this has not been verified in detail.

minor changes to error handling are also made.
Rich Felker 11 سال پیش
والد
کامیت
e8f39ca489
1فایلهای تغییر یافته به همراه22 افزوده شده و 35 حذف شده
  1. 22 35
      src/network/gethostbyname2_r.c

+ 22 - 35
src/network/gethostbyname2_r.c

@@ -6,41 +6,31 @@
 #include <netinet/in.h>
 #include <errno.h>
 #include <stdint.h>
+#include "lookup.h"
 
 int gethostbyname2_r(const char *name, int af,
 	struct hostent *h, char *buf, size_t buflen,
 	struct hostent **res, int *err)
 {
-	struct addrinfo hint = {
-		.ai_family = af==AF_INET6 ? af : AF_INET,
-		.ai_flags = AI_CANONNAME
-	};
-	struct addrinfo *ai, *p;
-	int i;
-	size_t need;
-	const char *canon;
+	struct address addrs[MAXADDRS];
+	char canon[256];
+	int i, cnt;
+	size_t align, need;
 
-	af = hint.ai_family;
-
-	/* Align buffer */
-	i = (uintptr_t)buf & sizeof(char *)-1;
-	if (i) {
-		if (buflen < sizeof(char *)-i) return ERANGE;
-		buf += sizeof(char *)-i;
-		buflen -= sizeof(char *)-i;
-	}
-
-	switch (getaddrinfo(name, 0, &hint, &ai)) {
+	cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME);
+	if (cnt<0) switch (cnt) {
 	case EAI_NONAME:
 		*err = HOST_NOT_FOUND;
-		return errno;
+		return ENOENT;
 	case EAI_AGAIN:
 		*err = TRY_AGAIN;
-		return errno;
+		return EAGAIN;
 	default:
+	case EAI_FAIL:
+		*err = NO_RECOVERY;
+		return EBADMSG;
 	case EAI_MEMORY:
 	case EAI_SYSTEM:
-	case EAI_FAIL:
 		*err = NO_RECOVERY;
 		return errno;
 	case 0:
@@ -50,22 +40,22 @@ int gethostbyname2_r(const char *name, int af,
 	h->h_addrtype = af;
 	h->h_length = af==AF_INET6 ? 16 : 4;
 
-	canon = ai->ai_canonname ? ai->ai_canonname : name;
+	/* Align buffer */
+	align = -(uintptr_t)buf & sizeof(char *)-1;
+
 	need = 4*sizeof(char *);
-	for (i=0, p=ai; p; i++, p=p->ai_next)
-		need += sizeof(char *) + h->h_length;
+	need += (cnt + 1) * (sizeof(char *) + h->h_length);
 	need += strlen(name)+1;
 	need += strlen(canon)+1;
+	need += align;
 
-	if (need > buflen) {
-		freeaddrinfo(ai);
-		return ERANGE;
-	}
+	if (need > buflen) return ERANGE;
 
+	buf += align;
 	h->h_aliases = (void *)buf;
 	buf += 3*sizeof(char *);
 	h->h_addr_list = (void *)buf;
-	buf += (i+1)*sizeof(char *);
+	buf += (cnt+1)*sizeof(char *);
 
 	h->h_name = h->h_aliases[0] = buf;
 	strcpy(h->h_name, canon);
@@ -79,16 +69,13 @@ int gethostbyname2_r(const char *name, int af,
 
 	h->h_aliases[2] = 0;
 
-	for (i=0, p=ai; p; i++, p=p->ai_next) {
+	for (i=0; i<cnt; i++) {
 		h->h_addr_list[i] = (void *)buf;
 		buf += h->h_length;
-		memcpy(h->h_addr_list[i],
-			&((struct sockaddr_in *)p->ai_addr)->sin_addr,
-			h->h_length);
+		memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length);
 	}
 	h->h_addr_list[i] = 0;
 
 	*res = h;
-	freeaddrinfo(ai);
 	return 0;
 }