blob: f38cbdde3335c607be58767cd7c88a8d1261621e [file] [log] [blame]
/*
* 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);