1145857Sume/*	$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $	*/
2145857Sume
3145857Sume/*-
4145857Sume * Copyright (c) 2004 The NetBSD Foundation, Inc.
5145857Sume * All rights reserved.
6145857Sume *
7145857Sume * This code is derived from software contributed to The NetBSD Foundation
8145857Sume * by Christos Zoulas.
9145857Sume *
10145857Sume * Redistribution and use in source and binary forms, with or without
11145857Sume * modification, are permitted provided that the following conditions
12145857Sume * are met:
13145857Sume * 1. Redistributions of source code must retain the above copyright
14145857Sume *    notice, this list of conditions and the following disclaimer.
15145857Sume * 2. Redistributions in binary form must reproduce the above copyright
16145857Sume *    notice, this list of conditions and the following disclaimer in the
17145857Sume *    documentation and/or other materials provided with the distribution.
18145857Sume *
19145857Sume * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20145857Sume * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21145857Sume * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22145857Sume * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23145857Sume * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24145857Sume * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25145857Sume * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26145857Sume * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27145857Sume * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28145857Sume * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29145857Sume * POSSIBILITY OF SUCH DAMAGE.
30145857Sume */
31145860Sume/* $FreeBSD$ */
32145857Sume#include <sys/cdefs.h>
33145857Sume__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
34145857Sume
35145860Sume#include <sys/types.h>
36145860Sume#include <sys/socket.h>
37145857Sume#include <pthread.h>
38145857Sume#include <stdio.h>
39145857Sume#include <netdb.h>
40145857Sume#include <stdlib.h>
41145857Sume#include <unistd.h>
42145857Sume#include <string.h>
43145857Sume#include <stringlist.h>
44145857Sume
45292317Sngie#include <atf-c.h>
46292317Sngie
47145857Sume#define NTHREADS	10
48145857Sume#define NHOSTS		100
49145857Sume#define WS		" \t\n\r"
50145857Sume
51145860Sumeenum method {
52145860Sume	METHOD_GETADDRINFO,
53145860Sume	METHOD_GETHOSTBY,
54145860Sume	METHOD_GETIPNODEBY
55145860Sume};
56145860Sume
57145857Sumestatic StringList *hosts = NULL;
58145860Sumestatic enum method method = METHOD_GETADDRINFO;
59145857Sumestatic int *ask = NULL;
60145857Sumestatic int *got = NULL;
61145857Sume
62145857Sumestatic void load(const char *);
63145857Sumestatic void resolvone(int);
64145857Sumestatic void *resolvloop(void *);
65145857Sumestatic void run(int *);
66145857Sume
67145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
68145857Sume
69145857Sumestatic void
70145857Sumeload(const char *fname)
71145857Sume{
72145857Sume	FILE *fp;
73145857Sume	size_t len;
74145857Sume	char *line;
75145857Sume
76145857Sume	if ((fp = fopen(fname, "r")) == NULL)
77292317Sngie	ATF_REQUIRE(fp != NULL);
78145857Sume	while ((line = fgetln(fp, &len)) != NULL) {
79145857Sume		char c = line[len];
80145857Sume		char *ptr;
81145857Sume		line[len] = '\0';
82291362Sngie		for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) {
83291362Sngie			if (ptr == '\0' || ptr[0] == '#')
84291362Sngie				continue;
85145857Sume			sl_add(hosts, strdup(ptr));
86291362Sngie		}
87145857Sume		line[len] = c;
88145857Sume	}
89145857Sume
90145857Sume	(void)fclose(fp);
91145857Sume}
92145857Sume
93145860Sumestatic int
94145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port)
95145860Sume{
96145860Sume	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
97145860Sume	struct addrinfo hints, *res;
98145860Sume	int error, len;
99145860Sume
100145860Sume	snprintf(portstr, sizeof(portstr), "%d", port);
101145860Sume	memset(&hints, 0, sizeof(hints));
102145860Sume	hints.ai_family = AF_UNSPEC;
103145860Sume	hints.ai_flags = AI_PASSIVE;
104145860Sume	hints.ai_socktype = SOCK_STREAM;
105145860Sume	error = getaddrinfo(host, portstr, &hints, &res);
106292317Sngie	len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
107292317Sngie	    self, host, error ? "not found" : "ok");
108292317Sngie	(void)write(STDOUT_FILENO, buf, len);
109292317Sngie	if (error == 0) {
110145860Sume		memset(hbuf, 0, sizeof(hbuf));
111145860Sume		memset(pbuf, 0, sizeof(pbuf));
112145860Sume		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
113145860Sume			    pbuf, sizeof(pbuf), 0);
114292317Sngie		len = snprintf(buf, sizeof(buf),
115292317Sngie		    "%p: reverse %s %s\n", self, hbuf, pbuf);
116292317Sngie		(void)write(STDOUT_FILENO, buf, len);
117145860Sume	}
118145860Sume	if (error == 0)
119145860Sume		freeaddrinfo(res);
120145860Sume	return error;
121145860Sume}
122145860Sume
123145860Sumestatic int
124145860Sumeresolv_gethostby(pthread_t self, char *host)
125145860Sume{
126145860Sume	char buf[1024];
127145860Sume	struct hostent *hp, *hp2;
128145860Sume	int len;
129145860Sume
130145860Sume	hp = gethostbyname(host);
131292317Sngie	len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
132292317Sngie	    self, host, (hp == NULL) ? "not found" : "ok");
133292317Sngie	(void)write(STDOUT_FILENO, buf, len);
134292317Sngie	if (hp) {
135145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
136145860Sume		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
137292317Sngie		if (hp2) {
138145860Sume			len = snprintf(buf, sizeof(buf),
139145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
140145860Sume			(void)write(STDOUT_FILENO, buf, len);
141145860Sume		}
142145860Sume	}
143145860Sume	return hp ? 0 : -1;
144145860Sume}
145145860Sume
146145860Sumestatic int
147145860Sumeresolv_getipnodeby(pthread_t self, char *host)
148145860Sume{
149145860Sume	char buf[1024];
150145860Sume	struct hostent *hp, *hp2;
151145860Sume	int len, h_error;
152145860Sume
153145860Sume	hp = getipnodebyname(host, AF_INET, 0, &h_error);
154292317Sngie	len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
155292317Sngie	    self, host, (hp == NULL) ? "not found" : "ok");
156292317Sngie	(void)write(STDOUT_FILENO, buf, len);
157292317Sngie	if (hp) {
158145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
159145860Sume		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
160145860Sume		    &h_error);
161292317Sngie		if (hp2) {
162145860Sume			len = snprintf(buf, sizeof(buf),
163145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
164145860Sume			(void)write(STDOUT_FILENO, buf, len);
165145860Sume		}
166145860Sume		if (hp2)
167145860Sume			freehostent(hp2);
168145860Sume	}
169145860Sume	if (hp)
170145860Sume		freehostent(hp);
171145860Sume	return hp ? 0 : -1;
172145860Sume}
173145860Sume
174145857Sumestatic void
175145857Sumeresolvone(int n)
176145857Sume{
177145857Sume	char buf[1024];
178145857Sume	pthread_t self = pthread_self();
179145857Sume	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
180145857Sume	char *host = hosts->sl_str[i];
181145860Sume	struct addrinfo hints, *res;
182145857Sume	int error, len;
183145860Sume
184292317Sngie	len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
185292317Sngie	    self, n, host, (int)i);
186292317Sngie	(void)write(STDOUT_FILENO, buf, len);
187145860Sume	switch (method) {
188145860Sume	case METHOD_GETADDRINFO:
189145860Sume		error = resolv_getaddrinfo(self, host, i);
190145860Sume		break;
191145860Sume	case METHOD_GETHOSTBY:
192145860Sume		error = resolv_gethostby(self, host);
193145860Sume		break;
194145860Sume	case METHOD_GETIPNODEBY:
195145860Sume		error = resolv_getipnodeby(self, host);
196145860Sume		break;
197145860Sume	default:
198145860Sume		break;
199145857Sume	}
200145857Sume	pthread_mutex_lock(&stats);
201145857Sume	ask[i]++;
202145857Sume	got[i] += error == 0;
203145857Sume	pthread_mutex_unlock(&stats);
204145857Sume}
205145857Sume
206145857Sumestatic void *
207145857Sumeresolvloop(void *p)
208145857Sume{
209145857Sume	int *nhosts = (int *)p;
210145857Sume	if (*nhosts == 0)
211243346Semaste		return NULL;
212145857Sume	do
213145857Sume		resolvone(*nhosts);
214145857Sume	while (--(*nhosts));
215145857Sume	return NULL;
216145857Sume}
217145857Sume
218145857Sumestatic void
219145857Sumerun(int *nhosts)
220145857Sume{
221292317Sngie	pthread_t self;
222292317Sngie	int rc;
223292317Sngie
224292317Sngie	self = pthread_self();
225292317Sngie	rc = pthread_create(&self, NULL, resolvloop, nhosts);
226292317Sngie	ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc));
227145857Sume}
228145857Sume
229292317Sngiestatic int
230292317Sngierun_tests(const char *hostlist_file, enum method method)
231145857Sume{
232145857Sume	int nthreads = NTHREADS;
233145857Sume	int nhosts = NHOSTS;
234145857Sume	int i, c, done, *nleft;
235145857Sume	hosts = sl_init();
236145857Sume
237145857Sume	srandom(1234);
238145857Sume
239292317Sngie	load(hostlist_file);
240145857Sume
241292317Sngie	ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file);
242145857Sume
243292317Sngie	nleft = malloc(nthreads * sizeof(int));
244292317Sngie	ATF_REQUIRE(nleft != NULL);
245145857Sume
246292317Sngie	ask = calloc(hosts->sl_cur, sizeof(int));
247292317Sngie	ATF_REQUIRE(ask != NULL);
248145857Sume
249292317Sngie	got = calloc(hosts->sl_cur, sizeof(int));
250292317Sngie	ATF_REQUIRE(got != NULL);
251145857Sume
252145857Sume	for (i = 0; i < nthreads; i++) {
253145857Sume		nleft[i] = nhosts;
254145857Sume		run(&nleft[i]);
255145857Sume	}
256145857Sume
257145857Sume	for (done = 0; !done;) {
258145857Sume		done = 1;
259145857Sume		for (i = 0; i < nthreads; i++) {
260145857Sume			if (nleft[i] != 0) {
261145857Sume				done = 0;
262145857Sume				break;
263145857Sume			}
264145857Sume		}
265145857Sume		sleep(1);
266145857Sume	}
267145857Sume	c = 0;
268145857Sume	for (i = 0; i < hosts->sl_cur; i++) {
269145857Sume		if (ask[i] != got[i] && got[i] != 0) {
270292317Sngie			printf("Error: host %s ask %d got %d\n",
271145857Sume			    hosts->sl_str[i], ask[i], got[i]);
272145857Sume			c++;
273145857Sume		}
274145857Sume	}
275145857Sume	free(nleft);
276145857Sume	free(ask);
277145857Sume	free(got);
278145857Sume	sl_free(hosts, 1);
279145857Sume	return c;
280145857Sume}
281292317Sngie
282292317Sngie#define	HOSTLIST_FILE	"mach"
283292317Sngie
284292317Sngie#define	RUN_TESTS(tc, method) \
285292317Sngiedo {									\
286292317Sngie	char *_hostlist_file;						\
287292317Sngie	ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s",		\
288292317Sngie	    atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE));	\
289292317Sngie	ATF_REQUIRE(run_tests(_hostlist_file, method) == 0);		\
290292317Sngie} while(0)
291292317Sngie
292292665SngieATF_TC(getaddrinfo_test);
293292665SngieATF_TC_HEAD(getaddrinfo_test, tc) {
294304950Sngie	atf_tc_set_md_var(tc, "timeout", "1200");
295292665Sngie}
296292317SngieATF_TC_BODY(getaddrinfo_test, tc)
297292317Sngie{
298292317Sngie
299292317Sngie	RUN_TESTS(tc, METHOD_GETADDRINFO);
300292317Sngie}
301292317Sngie
302292665SngieATF_TC(gethostby_test);
303292665SngieATF_TC_HEAD(gethostby_test, tc) {
304304950Sngie	atf_tc_set_md_var(tc, "timeout", "1200");
305292665Sngie}
306292317SngieATF_TC_BODY(gethostby_test, tc)
307292317Sngie{
308292317Sngie
309292317Sngie	RUN_TESTS(tc, METHOD_GETHOSTBY);
310292317Sngie}
311292317Sngie
312292665SngieATF_TC(getipnodeby_test);
313292665SngieATF_TC_HEAD(getipnodeby_test, tc) {
314292665Sngie
315304950Sngie	atf_tc_set_md_var(tc, "timeout", "1200");
316292665Sngie}
317292317SngieATF_TC_BODY(getipnodeby_test, tc)
318292317Sngie{
319292317Sngie
320292317Sngie	RUN_TESTS(tc, METHOD_GETIPNODEBY);
321292317Sngie}
322292317Sngie
323292317SngieATF_TP_ADD_TCS(tp)
324292317Sngie{
325292317Sngie
326292317Sngie	ATF_TP_ADD_TC(tp, getaddrinfo_test);
327292317Sngie	ATF_TP_ADD_TC(tp, gethostby_test);
328292317Sngie	ATF_TP_ADD_TC(tp, getipnodeby_test);
329292317Sngie
330292317Sngie	return (atf_no_error());
331292317Sngie}
332