| /*  | 
 |  * This file is part of the UCB release of Plan 9. It is subject to the license | 
 |  * terms in the LICENSE file found in the top-level directory of this | 
 |  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No | 
 |  * part of the UCB release of Plan 9, including this file, may be copied, | 
 |  * modified, propagated, or distributed except according to the terms contained | 
 |  * in the LICENSE file. | 
 |  */ | 
 |  | 
 | /* posix */ | 
 | #include <sys/types.h> | 
 | #include <unistd.h> | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <fcntl.h> | 
 | #include <string.h> | 
 | #include <errno.h> | 
 |  | 
 | /* bsd extensions */ | 
 | #include <sys/uio.h> | 
 | #include <sys/socket.h> | 
 | #include <netinet/in.h> | 
 | #include <netdb.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #include <sys/plan9_helpers.h> | 
 |  | 
 | enum { | 
 | 	Nname = 6, | 
 | }; | 
 |  | 
 | int __gethostbyname2_r(const char *name, int af, struct hostent *ret, | 
 |                        char *buf, size_t buflen, | 
 |                        struct hostent **result, int *h_errnop) | 
 | { | 
 | 	int i, t, fd, m; | 
 | 	char *p, *bp; | 
 | 	int nn, na; | 
 | 	unsigned long x; | 
 | 	size_t csmsg_len = 0; | 
 | 	/* These three used to be: | 
 | 		static char *nptr[Nname + 1]; | 
 | 		static char *aptr[Nname + 1]; | 
 | 		static char addr[Nname][4]; | 
 | 	 * we need to use space in buf for them */ | 
 | 	char **nptr, **aptr; | 
 | 	char (*addr)[4]; | 
 | 	size_t nptr_sz, aptr_sz, addr_sz; | 
 | 	nptr_sz = sizeof(char *) * (Nname + 1); | 
 | 	aptr_sz = sizeof(char *) * (Nname + 1); | 
 | 	addr_sz = sizeof(char[Nname][4]); | 
 |  | 
 | 	if (nptr_sz + aptr_sz + addr_sz >= buflen) { | 
 | 		*result = 0; | 
 | 		return -ERANGE; | 
 | 	} | 
 | 	nptr = buf; buf += nptr_sz; buflen -= nptr_sz; | 
 | 	aptr = buf; buf += aptr_sz; buflen -= aptr_sz; | 
 | 	addr = buf; buf += addr_sz; buflen -= addr_sz; | 
 |  | 
 | 	/* for inet addresses only */ | 
 | 	if (af != AF_INET) { | 
 | 		*result = 0; | 
 | 		return -EAFNOSUPPORT; | 
 | 	} | 
 |  | 
 | 	ret->h_name = 0; | 
 | 	t = _sock_ipattr(name); | 
 |  | 
 | 	/* connect to server */ | 
 | 	fd = open("/net/cs", O_RDWR); | 
 | 	if (fd < 0) { | 
 | 		*h_errnop = NO_RECOVERY; | 
 | 		*result = 0; | 
 | 		return -errno; | 
 | 	} | 
 |  | 
 | 	/* construct the query, always expect an ip# back */ | 
 | 	switch (t) { | 
 | 		case Tsys: | 
 | 			csmsg_len = snprintf(buf, buflen, "!sys=%s ip=*", name); | 
 | 			break; | 
 | 		case Tdom: | 
 | 			csmsg_len = snprintf(buf, buflen, "!dom=%s ip=*", name); | 
 | 			break; | 
 | 		case Tip: | 
 | 			csmsg_len = snprintf(buf, buflen, "!ip=%s", name); | 
 | 			break; | 
 | 		default: | 
 | 			/* we can't get here, but want to be safe for changes to | 
 | 			 * _sock_ipattr() */ | 
 | 			close(fd); | 
 | 			*result = 0; | 
 | 			return -EINVAL; | 
 | 	} | 
 | 	/* we don't update buflen, since we're just going to reuse the space after | 
 | 	 * our nptr/aptr/addr/etc. */ | 
 | 	if (csmsg_len >= buflen) { | 
 | 		close(fd); | 
 | 		*result = 0; | 
 | 		return -ERANGE; | 
 | 	} | 
 | 	/* query the server */ | 
 | 	if (write(fd, buf, csmsg_len) < 0) { | 
 | 		*h_errnop = TRY_AGAIN; | 
 | 		close(fd); | 
 | 		*result = 0; | 
 | 		return -1; | 
 | 	} | 
 | 	lseek(fd, 0, 0); | 
 | 	for (i = 0; i < buflen - 1; i += m) { | 
 | 		m = read(fd, buf + i, buflen - 1 - i); | 
 | 		if (m <= 0) | 
 | 			break; | 
 | 		buf[i + m++] = ' '; | 
 | 	} | 
 | 	close(fd); | 
 | 	buf[i] = 0; | 
 |  | 
 | 	/* parse the reply */ | 
 | 	nn = na = 0; | 
 | 	for (bp = buf;;) { | 
 | 		p = strchr(bp, '='); | 
 | 		if (p == 0) | 
 | 			break; | 
 | 		*p++ = 0; | 
 | 		if (strcmp(bp, "dom") == 0) { | 
 | 			if (ret->h_name == 0) | 
 | 				ret->h_name = p; | 
 | 			if (nn < Nname) | 
 | 				nptr[nn++] = p; | 
 | 		} else if (strcmp(bp, "sys") == 0) { | 
 | 			if (nn < Nname) | 
 | 				nptr[nn++] = p; | 
 | 		} else if (strcmp(bp, "ip") == 0) { | 
 | 			x = inet_addr(p); | 
 | 			x = ntohl(x); | 
 | 			if (na < Nname) { | 
 | 				addr[na][0] = x >> 24; | 
 | 				addr[na][1] = x >> 16; | 
 | 				addr[na][2] = x >> 8; | 
 | 				addr[na][3] = x; | 
 | 				aptr[na] = addr[na]; | 
 | 				na++; | 
 | 			} | 
 | 		} | 
 | 		while (*p && *p != ' ') | 
 | 			p++; | 
 | 		if (*p) | 
 | 			*p++ = 0; | 
 | 		bp = p; | 
 | 	} | 
 | 	if (nn + na == 0) { | 
 | 		*h_errnop = HOST_NOT_FOUND; | 
 | 		*result = 0; | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	nptr[nn] = 0; | 
 | 	aptr[na] = 0; | 
 | 	ret->h_aliases = nptr; | 
 | 	ret->h_addr_list = aptr; | 
 | 	ret->h_length = 4; | 
 | 	ret->h_addrtype = AF_INET; | 
 | 	if (ret->h_name == 0) | 
 | 		ret->h_name = nptr[0]; | 
 | 	if (ret->h_name == 0) | 
 | 		ret->h_name = aptr[0]; | 
 |  | 
 | 	*result = ret; | 
 | 	return 0; | 
 | } | 
 | weak_alias(__gethostbyname2_r, gethostbyname2_r); |