gethostbyname2_r.c 1.9 KB
Newer Older
R
Rich Felker 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#define _GNU_SOURCE

#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <inttypes.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;

	af = hint.ai_family;

	/* Align buffer */
	i = (uintptr_t)buf & sizeof(char *)-1;
	if (i) {
28
		if (buflen < sizeof(char *)-i) return ERANGE;
R
Rich Felker 已提交
29 30 31 32 33 34 35 36
		buf += sizeof(char *)-i;
		buflen -= sizeof(char *)-i;
	}

	getaddrinfo(name, 0, &hint, &ai);
	switch (getaddrinfo(name, 0, &hint, &ai)) {
	case EAI_NONAME:
		*err = HOST_NOT_FOUND;
37
		return errno;
R
Rich Felker 已提交
38 39
	case EAI_AGAIN:
		*err = TRY_AGAIN;
40
		return errno;
R
Rich Felker 已提交
41 42 43 44 45
	default:
	case EAI_MEMORY:
	case EAI_SYSTEM:
	case EAI_FAIL:
		*err = NO_RECOVERY;
46
		return errno;
R
Rich Felker 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
	case 0:
		break;
	}

	h->h_addrtype = af;
	h->h_length = af==AF_INET6 ? 16 : 4;

	canon = ai->ai_canonname ? ai->ai_canonname : name;
	need = 4*sizeof(char *);
	for (i=0, p=ai; p; i++, p=p->ai_next)
		need += sizeof(char *) + h->h_length;
	need += strlen(name)+1;
	need += strlen(canon)+1;

	if (need > buflen) {
		freeaddrinfo(ai);
63
		return ERANGE;
R
Rich Felker 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
	}

	h->h_aliases = (void *)buf;
	buf += 3*sizeof(char *);
	h->h_addr_list = (void *)buf;
	buf += (i+1)*sizeof(char *);

	h->h_name = h->h_aliases[0] = buf;
	strcpy(h->h_name, canon);
	buf += strlen(h->h_name)+1;

	if (strcmp(h->h_name, name)) {
		h->h_aliases[1] = buf;
		strcpy(h->h_aliases[1], name);
		buf += strlen(h->h_aliases[1])+1;
	} else h->h_aliases[1] = 0;

	h->h_aliases[2] = 0;

	for (i=0, p=ai; p; i++, p=p->ai_next) {
		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);
	}
	h->h_addr_list[i] = 0;

	*res = h;
	freeaddrinfo(ai);
	return 0;
}