svn commit: trunk/uClibc/libc/inet

vda at uclibc.org vda at uclibc.org
Mon Nov 17 02:40:06 UTC 2008


Author: vda
Date: 2008-11-16 18:40:05 -0800 (Sun, 16 Nov 2008)
New Revision: 24067

Log:
resolver: fix some previous TODOs, add new ones.



Modified:
   trunk/uClibc/libc/inet/resolv.c


Changeset:
Modified: trunk/uClibc/libc/inet/resolv.c
===================================================================
--- trunk/uClibc/libc/inet/resolv.c	2008-11-17 00:12:17 UTC (rev 24066)
+++ trunk/uClibc/libc/inet/resolv.c	2008-11-17 02:40:05 UTC (rev 24067)
@@ -239,7 +239,7 @@
 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
 #else
 #define DPRINTF(X,args...)
-#endif /* DEBUG */
+#endif
 
 #undef ARRAY_SIZE
 #define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
@@ -344,7 +344,7 @@
 			char * dest, int maxlen) attribute_hidden;
 extern int __length_dotted(const unsigned char * const message, int offset) attribute_hidden;
 extern int __encode_header(struct resolv_header * h, unsigned char * dest, int maxlen) attribute_hidden;
-extern int __decode_header(unsigned char * data, struct resolv_header * h) attribute_hidden;
+extern void __decode_header(unsigned char * data, struct resolv_header * h) attribute_hidden;
 extern int __encode_question(const struct resolv_question * const q,
 			unsigned char * dest, int maxlen) attribute_hidden;
 extern int __decode_question(const unsigned char * const message, int offset,
@@ -475,7 +475,7 @@
 
 #ifdef L_decodeh
 
-int attribute_hidden __decode_header(unsigned char *data, struct resolv_header *h)
+void attribute_hidden __decode_header(unsigned char *data, struct resolv_header *h)
 {
 	h->id = (data[0] << 8) | data[1];
 	h->qr = (data[2] & 0x80) ? 1 : 0;
@@ -489,8 +489,6 @@
 	h->ancount = (data[6] << 8) | data[7];
 	h->nscount = (data[8] << 8) | data[9];
 	h->arcount = (data[10] << 8) | data[11];
-
-	return HFIXEDSZ;
 }
 #endif
 
@@ -827,7 +825,8 @@
 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
 int __decode_packet(unsigned char *data, struct resolv_header *h)
 {
-	return __decode_header(data, h);
+	__decode_header(data, h);
+	return HFIXEDSZ;
 }
 #endif
 
@@ -1012,7 +1011,15 @@
 		fclose(fp);
 	}
 	if (__nameservers == 0) {
-		__nameserver = (void*) &__local_nameserver;
+		/* Have to handle malloc failure! What a mess...
+		 * And it's not only here, we need to be careful
+		 * to never write into __nameserver[0] if it points
+		 * to constant __local_nameserver, or free it. */
+		__nameserver = malloc(sizeof(__nameserver[0]));
+		if (__nameserver)
+			memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
+		else
+			__nameserver = (void*) &__local_nameserver;
 		__nameservers++;
 	}
 	if (__searchdomains == 0) {
@@ -1063,10 +1070,6 @@
 
 #ifdef L_dnslookup
 
-/* Protected by __resolv_lock */
-static int last_ns_num = 0;
-static uint16_t last_id = 1;
-
 /* On entry:
  *  a.buf(len) = auxiliary buffer for IP addresses after first one
  *  a.add_count = how many additional addresses are there already
@@ -1087,6 +1090,10 @@
 			unsigned char **outpacket,
 			struct resolv_answer *a)
 {
+	/* Protected by __resolv_lock: */
+	static int last_ns_num = 0;
+	static uint16_t last_id = 1;
+
 	int i, j, len, fd, pos, rc;
 	int name_len;
 #ifdef USE_SELECT
@@ -1099,7 +1106,7 @@
 	struct resolv_question q;
 	struct resolv_answer ma;
 	bool first_answer = 1;
-	unsigned retries = 0;
+	int retries_left;
 	unsigned char *packet = malloc(PACKETSZ);
 	char *lookup;
 	int variant = -1;  /* search domain to append, -1: none */
@@ -1118,18 +1125,19 @@
 	if (!packet || !lookup || !name[0])
 		goto fail;
 	ends_with_dot = (name[name_len - 1] == '.');
+	/* no strcpy! paranoia, user might change name[] under us */
+	memcpy(lookup, name, name_len);
+
 	DPRINTF("Looking up type %d answer for '%s'\n", type, name);
+	retries_left = 0; /* for compiler */
+	do {
+		unsigned reply_timeout;
 
-	while (retries < MAX_RETRIES) {
 		if (fd != -1) {
 			close(fd);
 			fd = -1;
 		}
 
-		/* no strcpy! paranoia, user might change name[] under us */
-		memcpy(lookup, name, name_len);
-		lookup[name_len] = '\0';
-
 		/* Mess with globals while under lock */
 		/* NB: even data *pointed to* by globals may vanish
 		 * outside the locks. We should assume any and all
@@ -1142,27 +1150,26 @@
 		__UCLIBC_MUTEX_LOCK(__resolv_lock);
 		__open_nameservers();
 		sdomains = __searchdomains;
+		lookup[name_len] = '\0';
 		if ((unsigned)variant < sdomains) {
 			/* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
 			/* __searchdomain[] is not bigger than MAXLEN_searchdomain */
 			lookup[name_len] = '.';
 			strcpy(&lookup[name_len + 1], __searchdomain[variant]);
 		}
-		if (local_ns_num < 0) { /* first time */
+		/* first time? pick starting server etc */
+		if (local_ns_num < 0) {
 			local_id = last_id;
 //TODO: implement /etc/resolv.conf's "options rotate"
 // (a.k.a. RES_ROTATE bit in _res.options)
 //			local_ns_num = 0;
 //			if (_res.options & RES_ROTATE)
 				local_ns_num = last_ns_num;
+			retries_left = __nameservers * MAX_RETRIES;
 		}
-		if (local_ns_num >= __nameservers) {
+		retries_left--;
+		if (local_ns_num >= __nameservers)
 			local_ns_num = 0;
-//TODO: wrong method of retries++!
-// Should be if (local_ns_num == starting_ns_num) retries++;
-			retries++;
-			/* break if retries >= MAX_RETRIES - *after unlock*! */
-		}
 		local_id++;
 		local_id &= 0xffff;
 		/* write new values back while still under lock */
@@ -1173,8 +1180,6 @@
 		 * is not safe to use outside of locks */
 		sa = __nameserver[local_ns_num];
 		__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
-		if (retries >= MAX_RETRIES)
-			break;
 
 		memset(packet, 0, PACKETSZ);
 		memset(&h, 0, sizeof(h));
@@ -1200,29 +1205,30 @@
 
 		/* send packet */
 		DPRINTF("On try %d, sending query to port %d\n",
-				retries+1, NAMESERVER_PORT);
+				retries_left, NAMESERVER_PORT);
 		fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
-		if (fd < 0) { /* paranoia */
-			retries++;
-			continue;
-		}
+		if (fd < 0) /* paranoia */
+			goto try_next_server;
 		rc = connect(fd, &sa.sa, sizeof(sa));
 		if (rc < 0) {
-			if (errno == ENETUNREACH) {
+			//if (errno == ENETUNREACH) {
 				/* routing error, presume not transient */
 				goto try_next_server;
-			}
-			/* retry */
-			retries++;
-			continue;
+			//}
+//For example, what transient error this can be? Can't think of any
+			///* retry */
+			//continue;
 		}
 		DPRINTF("Xmit packet len:%d id:%d qr:%d\n", len, h.id, h.qr);
+		/* no error check - if it fails, we time out on recv */
 		send(fd, packet, len, 0);
 
 #ifdef USE_SELECT
+		reply_timeout = REPLY_TIMEOUT;
+ wait_again:
 		FD_ZERO(&fds);
 		FD_SET(fd, &fds);
-		tv.tv_sec = REPLY_TIMEOUT;
+		tv.tv_sec = reply_timeout;
 		tv.tv_usec = 0;
 		if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
 			DPRINTF("Timeout\n");
@@ -1230,30 +1236,35 @@
 			 * to next nameserver */
 			goto try_next_server;
 		}
+		reply_timeout--;
 #else
+		reply_timeout = REPLY_TIMEOUT * 1000;
+ wait_again:
 		fds.fd = fd;
 		fds.events = POLLIN;
-		if (poll(&fds, 1, REPLY_TIMEOUT * 1000) <= 0) {
+		if (poll(&fds, 1, reply_timeout) <= 0) {
 			DPRINTF("Timeout\n");
 			/* timed out, so retry send and receive
 			 * to next nameserver */
 			goto try_next_server;
 		}
+//TODO: better timeout accounting?
+		reply_timeout -= 1000;
 #endif
 		len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
 		if (len < HFIXEDSZ) {
-			/* too short! */
-//TODO: why next sdomain? it's just a bogus packet from somewhere,
-// we can as well wait more...
-			goto try_next_sdomain;
+			/* too short!
+			 * it's just a bogus packet from somewhere */
+ bogus_packet:
+			if (reply_timeout)
+				goto wait_again;
+			goto try_next_server;
 		}
-
 		__decode_header(packet, &h);
 		DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
-		if ((h.id != local_id) || (!h.qr)) {
+		if (h.id != local_id || !h.qr) {
 			/* unsolicited */
-//TODO: why next sdomain?...
-			goto try_next_sdomain;
+			goto bogus_packet;
 		}
 
 		DPRINTF("Got response (i think)!\n");
@@ -1262,9 +1273,10 @@
 		DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
 				h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
 
+		/* bug 660 says we treat negative response as an error
+		 * and retry, which is, eh, an error. :)
+		 * We were incurring long delays because of this. */
 		if (h.rcode == NXDOMAIN) {
-// bug 660 says we treat negative response as an error and retry
-// which is, eh, an error. :) We were incurring long delays because of this.
 			/* if possible, try next search domain */
 			if (!ends_with_dot) {
 				DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
@@ -1273,8 +1285,9 @@
 					variant++;
 					continue;
 				}
+				/* no more search domains to try */
 			}
-			/* this is not an error - don't goto again! */
+			/* dont loop, this is "no such host" situation */
 			h_errno = HOST_NOT_FOUND;
 			goto fail1;
 		}
@@ -1291,8 +1304,6 @@
 			DPRINTF("Skipping question %d at %d\n", j, pos);
 			/* returns -1 only if packet == NULL (can't happen) */
 			i = __length_question(packet, pos);
-			//if (i < 0)
-			//	goto try_next_sdomain;
 			DPRINTF("Length of question %d is %d\n", j, i);
 			pos += i;
 		}
@@ -1342,6 +1353,7 @@
 			}
 		}
 
+		/* success! */
 		DPRINTF("Answer name = |%s|\n", a->dotted);
 		DPRINTF("Answer type = |%d|\n", a->atype);
 		if (fd != -1)
@@ -1351,8 +1363,11 @@
 		else
 			free(packet);
 		free(lookup);
-		return len; /* success! */
+		return len;
 
+//TODO: audit whether *any* "goto try_next_sdomain" is actually correct:
+//trying next search domain makes sense only if we got NXDOMAIN!
+//why we do it in other cases too?
  try_next_sdomain:
 		/* if there are searchdomains, try them */
 		if (!ends_with_dot) {
@@ -1366,7 +1381,7 @@
 		/* if there are other nameservers, try them */
 		local_ns_num++;
 		variant = -1;
-	} /* while (retries < MAX_RETRIES) */
+	} while (retries_left > 0);
 
  fail:
 	h_errno = NETDB_INTERNAL;
@@ -1386,12 +1401,11 @@
 {
 	static struct hostent h;
 	static char buf[sizeof(struct in_addr) +
-			sizeof(struct in_addr *)*2 +
+			sizeof(struct in_addr *) * 2 +
 			sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
 	struct hostent *hp;
 
 	gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
-
 	return hp;
 }
 libc_hidden_def(gethostbyname)
@@ -1404,17 +1418,16 @@
 {
 #ifndef __UCLIBC_HAS_IPV6__
 	return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
-#else /* __UCLIBC_HAS_IPV6__ */
+#else
 	static struct hostent h;
 	static char buf[sizeof(struct in6_addr) +
-			sizeof(struct in6_addr *)*2 +
+			sizeof(struct in6_addr *) * 2 +
 			sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
 	struct hostent *hp;
 
 	gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
-
 	return hp;
-#endif /* __UCLIBC_HAS_IPV6__ */
+#endif
 }
 #endif
 
@@ -1430,22 +1443,25 @@
 	struct __res_state *rp = &(_res);
 	int n;
 
-	/* TODO:
-	 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
-	 */
+	/* If we didn't get malloc failure earlier... */
+	if (__nameserver != (void*) &__local_nameserver) {
+		/* TODO:
+		 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
+		 */
 #ifdef __UCLIBC_HAS_IPV6__
-	if (__nameservers > rp->_u._ext.nscount)
-		__nameservers = rp->_u._ext.nscount;
-	n = __nameservers;
-	while (--n >= 0)
-		__nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
-#else /* __UCLIBC_HAS_IPV4__ */
-	if (__nameservers > rp->nscount)
-		__nameservers = rp->nscount;
-	n = __nameservers;
-	while (--n >= 0)
-		__nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
+		if (__nameservers > rp->_u._ext.nscount)
+			__nameservers = rp->_u._ext.nscount;
+		n = __nameservers;
+		while (--n >= 0)
+			__nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
+#else /* IPv4 only */
+		if (__nameservers > rp->nscount)
+			__nameservers = rp->nscount;
+		n = __nameservers;
+		while (--n >= 0)
+			__nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
 #endif
+	}
 	/* Extend and comment what program is known
 	 * to use which _res.XXX member(s).
 	 */
@@ -1521,7 +1537,7 @@
 	rp->_u._ext.nscount = m;
 #endif
 
-#else /* if !__UCLIBC_HAS_IPV4__ (only IPV6) */
+#else /* IPv6 only */
 	while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
 		struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
 		if (sa6) {
@@ -1532,7 +1548,7 @@
 		i++;
 	}
 	rp->_u._ext.nscount = m;
-#endif /* !__UCLIBC_HAS_IPV4__ (only IPV6) */
+#endif
 
 	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
 	return 0;
@@ -1836,7 +1852,6 @@
 	struct hostent *hp;
 
 	gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
-
 	return hp;
 }
 libc_hidden_def(gethostbyaddr)
@@ -1854,12 +1869,15 @@
 	return fp;
 }
 
-int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
-		     enum etc_hosts_action action,
-		     struct hostent * result_buf,
-		     char * buf, size_t buflen,
-		     struct hostent ** result,
-		     int * h_errnop)
+int attribute_hidden __read_etc_hosts_r(
+		FILE * fp,
+		const char * name,
+		int type,
+		enum etc_hosts_action action,
+		struct hostent * result_buf,
+		char * buf, size_t buflen,
+		struct hostent ** result,
+		int * h_errnop)
 {
 	struct in_addr *in = NULL;
 	struct in_addr **addr_list = NULL;
@@ -1879,11 +1897,11 @@
 		buflen -= i;
 	}
 
-	if (buflen < sizeof(char *)*ALIAS_DIM)
+	if (buflen < sizeof(char *) * ALIAS_DIM)
 		return ERANGE;
 	alias = (char **)buf;
-	buf += sizeof(char **)*ALIAS_DIM;
-	buflen -= sizeof(char **)*ALIAS_DIM;
+	buf += sizeof(char **) * ALIAS_DIM;
+	buflen -= sizeof(char **) * ALIAS_DIM;
 
 	if (action != GETHOSTENT) {
 #ifdef __UCLIBC_HAS_IPV6__
@@ -1897,10 +1915,10 @@
 		buf += sizeof(*in);
 		buflen -= sizeof(*in);
 
-		if (buflen < sizeof(*addr_list)*2)
+		if (buflen < sizeof(*addr_list) * 2)
 			return ERANGE;
 		addr_list = (struct in_addr **)buf;
-		buf += sizeof(*addr_list)*2;
+		buf += sizeof(*addr_list) * 2;
 		buflen -= sizeof(*addr_list)*2;
 
 #ifdef __UCLIBC_HAS_IPV6__
@@ -1910,11 +1928,11 @@
 		p += sizeof(*in6);
 		len -= sizeof(*in6);
 
-		if (len < sizeof(*addr_list6)*2)
+		if (len < sizeof(*addr_list6) * 2)
 			return ERANGE;
 		addr_list6 = (struct in6_addr**)p;
-		p += sizeof(*addr_list6)*2;
-		len -= sizeof(*addr_list6)*2;
+		p += sizeof(*addr_list6) * 2;
+		len -= sizeof(*addr_list6) * 2;
 
 		if (len < buflen) {
 			buflen = len;
@@ -1951,7 +1969,7 @@
 			while (*cp && !isspace(*cp))
 				cp++;
 		}
-		alias[aliases] = 0;
+		alias[aliases] = NULL;
 
 		if (aliases < 2)
 			continue; /* syntax error really */
@@ -2075,17 +2093,18 @@
 	static struct hostent h;
 	static char buf[
 #ifndef __UCLIBC_HAS_IPV6__
-			sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+			sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
 #else
-			sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
+			sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
 #endif /* __UCLIBC_HAS_IPV6__ */
-			sizeof(char *)*ALIAS_DIM +
+			sizeof(char *) * ALIAS_DIM +
 			80 /*namebuffer*/ + 2 /* margin */];
 	struct hostent *host;
 
-	__UCLIBC_MUTEX_LOCK(mylock);
+//BUG: the lock is not recursive!
+//	__UCLIBC_MUTEX_LOCK(mylock);
 	gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
-	__UCLIBC_MUTEX_UNLOCK(mylock);
+//	__UCLIBC_MUTEX_UNLOCK(mylock);
 	return host;
 }
 #endif
@@ -2184,31 +2203,31 @@
 		case AF_INET:
 #ifdef __UCLIBC_HAS_IPV6__
 		case AF_INET6:
-#endif /* __UCLIBC_HAS_IPV6__ */
+#endif
 			if (!(flags & NI_NUMERICHOST)) {
+				if (0) /* nothing */;
 #ifdef __UCLIBC_HAS_IPV6__
-				if (sa->sa_family == AF_INET6)
+				else if (sa->sa_family == AF_INET6)
 					h = gethostbyaddr((const void *)
 						&(((const struct sockaddr_in6 *) sa)->sin6_addr),
 						sizeof(struct in6_addr), AF_INET6);
-#endif /* __UCLIBC_HAS_IPV6__ */
-#if defined __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__
-				else
 #endif
 #ifdef __UCLIBC_HAS_IPV4__
+				else
 					h = gethostbyaddr((const void *)
 						&(((const struct sockaddr_in *)sa)->sin_addr),
 						sizeof(struct in_addr), AF_INET);
-#endif /* __UCLIBC_HAS_IPV4__ */
+#endif
 
 				if (h) {
 					char *c;
 #undef min
 #define min(x,y) (((x) > (y)) ? (y) : (x))
 					if ((flags & NI_NOFQDN)
-					    && (__libc_getdomainname(domain, sizeof(domain)) == 0)
-					    && (c = strstr (h->h_name, domain))
-					    && (c != h->h_name) && (*(--c) == '.')) {
+					 && (__libc_getdomainname(domain, sizeof(domain)) == 0)
+					 && (c = strstr(h->h_name, domain)) != NULL
+					 && (c != h->h_name) && (*(--c) == '.')
+					) {
 						strncpy(host, h->h_name,
 							min(hostlen, (size_t) (c - h->h_name)));
 						host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
@@ -2227,8 +2246,9 @@
 					errno = serrno;
 					return EAI_NONAME;
 				}
+				if (0) /* nothing */;
 #ifdef __UCLIBC_HAS_IPV6__
-				if (sa->sa_family == AF_INET6) {
+				else if (sa->sa_family == AF_INET6) {
 					const struct sockaddr_in6 *sin6p;
 
 					sin6p = (const struct sockaddr_in6 *) sa;
@@ -2275,14 +2295,13 @@
 #endif
 				}
 #endif /* __UCLIBC_HAS_IPV6__ */
-#if defined __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__
-				else
-#endif /* __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__ */
 #if defined __UCLIBC_HAS_IPV4__
+				else {
 					c = inet_ntop(AF_INET, (const void *)
 						&(((const struct sockaddr_in *) sa)->sin_addr),
 						host, hostlen);
-#endif /* __UCLIBC_HAS_IPV4__ */
+				}
+#endif
 				if (c == NULL) {
 					errno = serrno;
 					return EAI_SYSTEM;
@@ -2383,6 +2402,7 @@
 	unsigned char *packet;
 	struct resolv_answer a;
 	int i;
+	int wrong_af = 0;
 
 	*result = NULL;
 	if (!name)
@@ -2394,10 +2414,13 @@
 		__set_errno(0);         /* to check for missing /etc/hosts. */
 		i = __get_hosts_byname_r(name, AF_INET, result_buf,
 				buf, buflen, result, h_errnop);
-		if (i == 0)
+		if (i == NETDB_SUCCESS) {
+			__set_errno(old_errno);
 			return i;
+		}
 		switch (*h_errnop) {
 			case HOST_NOT_FOUND:
+				wrong_af = (i == TRY_AGAIN);
 			case NO_ADDRESS:
 				break;
 			case NETDB_INTERNAL:
@@ -2464,6 +2487,14 @@
 		}
 	}
 
+	/* what if /etc/hosts has it but it's not IPv4?
+	 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
+	 * "ping localhost6" should be fast even if DNS server is down! */
+	if (wrong_af) {
+		*h_errnop = HOST_NOT_FOUND;
+		return TRY_AGAIN;
+	}
+
 	/* talk to DNS servers */
 	{
 		a.buf = buf;
@@ -2547,17 +2578,19 @@
 
 #ifdef L_gethostbyname2_r
 
-int gethostbyname2_r(const char *name, int family,
-					 struct hostent * result_buf,
-					 char * buf, size_t buflen,
-					 struct hostent ** result,
-					 int * h_errnop)
+int gethostbyname2_r(const char *name,
+		int family,
+		struct hostent * result_buf,
+		char * buf,
+		size_t buflen,
+		struct hostent ** result,
+		int * h_errnop)
 {
 #ifndef __UCLIBC_HAS_IPV6__
 	return family == (AF_INET)
 		? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
 		: HOST_NOT_FOUND;
-#else /* __UCLIBC_HAS_IPV6__ */
+#else
 	struct in6_addr *in;
 	struct in6_addr **addr_list;
 	unsigned char *packet;
@@ -2584,7 +2617,7 @@
 		i = __get_hosts_byname_r(name, family, result_buf,
 				buf, buflen, result, h_errnop);
 		if (i == NETDB_SUCCESS) {
-//FIXME: restore errno?
+			__set_errno(old_errno);
 			return i;
 		}
 		switch (*h_errnop) {
@@ -2602,30 +2635,28 @@
 		}
 		__set_errno(old_errno);
 	}
-
 	DPRINTF("Nothing found in /etc/hosts\n");
 
 	*h_errnop = NETDB_INTERNAL;
-	if (buflen < sizeof(*in))
-		return ERANGE;
+
+	/* make sure pointer is aligned */
+	i = ALIGN_BUFFER_OFFSET(buf);
+	buf += i;
+	buflen -= i;
+
 	in = (struct in6_addr*)buf;
 	buf += sizeof(*in);
 	buflen -= sizeof(*in);
-
-	if (buflen < sizeof(*addr_list)*2)
+	addr_list = (struct in6_addr**)buf;
+	buf += sizeof(*addr_list) * 2;
+	buflen -= sizeof(*addr_list) * 2;
+	if ((ssize_t)buflen < 256)
 		return ERANGE;
-	addr_list = (struct in6_addr**)buf;
-	buf += sizeof(*addr_list)*2;
-	buflen -= sizeof(*addr_list)*2;
-
 	addr_list[0] = in;
-	addr_list[1] = 0;
-
-	if (buflen < 256)
-		return ERANGE;
+	addr_list[1] = NULL;
 	strncpy(buf, name, buflen);
 
-	/* First check if this is already an address */
+	/* maybe it is already an address? */
 	if (inet_pton(AF_INET6, name, in)) {
 		result_buf->h_name = buf;
 		result_buf->h_addrtype = AF_INET6;
@@ -2636,7 +2667,7 @@
 		return NETDB_SUCCESS;
 	}
 
-	/* What if /etc/hosts has it but it's not IPv6?
+	/* what if /etc/hosts has it but it's not IPv6?
 	 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
 	 * "ping localhost" should be fast even if DNS server is down! */
 	if (wrong_af) {
@@ -2644,8 +2675,9 @@
 		return TRY_AGAIN;
 	}
 
+	/* talk to DNS servers */
+// TODO: why it's so different from gethostbyname_r (IPv4 case)?
 	memset(&a, '\0', sizeof(a));
-
 	for (;;) {
 		i = __dns_lookup(buf, T_AAAA, &packet, &a);
 
@@ -2722,7 +2754,7 @@
 	if (!addr)
 		return EINVAL;
 
-	memset((char *) &a, '\0', sizeof(a));
+	memset(&a, '\0', sizeof(a));
 
 	switch (type) {
 		case AF_INET:
@@ -2752,49 +2784,42 @@
 			return i;
 	}
 
+	*h_errnop = NETDB_INTERNAL;
+
+	/* make sure pointer is aligned */
+	i = ALIGN_BUFFER_OFFSET(buf);
+	buf += i;
+	buflen -= i;
+
 #ifdef __UCLIBC_HAS_IPV6__
 	qp = buf;
 	plen = buflen;
-#endif /* __UCLIBC_HAS_IPV6__ */
-
-	*h_errnop = NETDB_INTERNAL;
-	if (buflen < sizeof(*in))
-		return ERANGE;
+#endif
 	in = (struct in_addr*)buf;
 	buf += sizeof(*in);
 	buflen -= sizeof(*in);
-
-	if (buflen < sizeof(*addr_list)*2)
-		return ERANGE;
 	addr_list = (struct in_addr**)buf;
-	buf += sizeof(*addr_list)*2;
-	buflen -= sizeof(*addr_list)*2;
-
-	if (buflen < sizeof(char *)*ALIAS_DIM)
+	buf += sizeof(*addr_list) * 2;
+	buflen -= sizeof(*addr_list) * 2;
+	alias = (char **)buf;
+	buf += sizeof(*alias) * ALIAS_DIM;
+	buflen -= sizeof(*alias) * ALIAS_DIM;
+	if ((ssize_t)buflen < 0)
 		return ERANGE;
-	alias = (char **)buf;
-	buf += sizeof(*alias)*ALIAS_DIM;
-	buflen -= sizeof(*alias)*ALIAS_DIM;
-
 #ifdef __UCLIBC_HAS_IPV6__
-	if (plen < sizeof(*in6))
-		return ERANGE;
 	in6 = (struct in6_addr*)qp;
 	qp += sizeof(*in6);
 	plen -= sizeof(*in6);
-
-	if (plen < sizeof(*addr_list6)*2)
+	addr_list6 = (struct in6_addr**)qp;
+	qp += sizeof(*addr_list6) * 2;
+	plen -= sizeof(*addr_list6) * 2;
+	if ((ssize_t)plen < 0)
 		return ERANGE;
-	addr_list6 = (struct in6_addr**)qp;
-	qp += sizeof(*addr_list6)*2;
-	plen -= sizeof(*addr_list6)*2;
-
 	if (plen < buflen) {
 		buflen = plen;
 		buf = qp;
 	}
-#endif /* __UCLIBC_HAS_IPV6__ */
-
+#endif
 	if (buflen < 256)
 		return ERANGE;
 
@@ -2802,30 +2827,27 @@
 		unsigned char *tmp_addr = (unsigned char *)addr;
 
 		memcpy(&in->s_addr, addr, len);
-
 		addr_list[0] = in;
-
 		sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
 				tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
+	}
 #ifdef __UCLIBC_HAS_IPV6__
-	} else {
+	else {
 		memcpy(in6->s6_addr, addr, len);
-
 		addr_list6[0] = in6;
 		qp = buf;
-
 		for (i = len - 1; i >= 0; i--) {
-			qp += sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
-						  (in6->s6_addr[i] >> 4) & 0xf);
+			qp += sprintf(qp, "%x.%x.",
+					in6->s6_addr[i] & 0xf,
+					(in6->s6_addr[i] >> 4) & 0xf);
 		}
 		strcpy(qp, "ip6.arpa");
-#endif /* __UCLIBC_HAS_IPV6__ */
 	}
+#endif
+	addr_list[1] = NULL;
 
-	addr_list[1] = 0;
-
 	alias[0] = buf;
-	alias[1] = 0;
+	alias[1] = NULL;
 
 	for (;;) {
 		i = __dns_lookup(buf, T_PTR, &packet, &a);
@@ -2838,7 +2860,7 @@
 		strncpy(buf, a.dotted, buflen);
 		free(a.dotted);
 
-		if (a.atype == T_CNAME) {		/* CNAME */
+		if (a.atype == T_CNAME) { /* CNAME */
 			DPRINTF("Got a CNAME in gethostbyaddr()\n");
 			i = __decode_dotted(packet, a.rdoffset, buf, buflen);
 			free(packet);
@@ -2860,15 +2882,12 @@
 
 			result_buf->h_name = buf;
 			result_buf->h_addrtype = type;
-
-			if (type == AF_INET) {
+			if (type == AF_INET)
 				result_buf->h_length = sizeof(*in);
 #ifdef __UCLIBC_HAS_IPV6__
-			} else {
+			else
 				result_buf->h_length = sizeof(*in6);
-#endif /* __UCLIBC_HAS_IPV6__ */
-			}
-
+#endif
 			result_buf->h_addr_list = (char **) addr_list;
 			result_buf->h_aliases = alias;
 			break;




More information about the uClibc-cvs mailing list