resolv.c revision 145860
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 * 3. All advertising materials mentioning features or use of this software
19145857Sume *    must display the following acknowledgement:
20145857Sume *        This product includes software developed by the NetBSD
21145857Sume *        Foundation, Inc. and its contributors.
22145857Sume * 4. Neither the name of The NetBSD Foundation nor the names of its
23145857Sume *    contributors may be used to endorse or promote products derived
24145857Sume *    from this software without specific prior written permission.
25145857Sume *
26145857Sume * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27145857Sume * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28145857Sume * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29145857Sume * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30145857Sume * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31145857Sume * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32145857Sume * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33145857Sume * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34145857Sume * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35145857Sume * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36145857Sume * POSSIBILITY OF SUCH DAMAGE.
37145857Sume */
38145860Sume/* $FreeBSD: head/tools/regression/lib/libc/resolv/resolv.c 145860 2005-05-04 12:02:10Z ume $ */
39145857Sume#include <sys/cdefs.h>
40145857Sume__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
41145857Sume
42145860Sume#include <sys/types.h>
43145860Sume#include <sys/socket.h>
44145857Sume#include <pthread.h>
45145857Sume#include <stdio.h>
46145857Sume#include <netdb.h>
47145857Sume#include <stdlib.h>
48145857Sume#include <unistd.h>
49145857Sume#include <err.h>
50145857Sume#include <string.h>
51145857Sume#include <stringlist.h>
52145857Sume
53145857Sume#define NTHREADS	10
54145857Sume#define NHOSTS		100
55145857Sume#define WS		" \t\n\r"
56145857Sume
57145860Sumeenum method {
58145860Sume	METHOD_GETADDRINFO,
59145860Sume	METHOD_GETHOSTBY,
60145860Sume	METHOD_GETIPNODEBY
61145860Sume};
62145860Sume
63145857Sumestatic StringList *hosts = NULL;
64145857Sumestatic int debug = 0;
65145860Sumestatic enum method method = METHOD_GETADDRINFO;
66145860Sumestatic int reverse = 0;
67145857Sumestatic int *ask = NULL;
68145857Sumestatic int *got = NULL;
69145857Sume
70145857Sumestatic void usage(void)  __attribute__((__noreturn__));
71145857Sumestatic void load(const char *);
72145857Sumestatic void resolvone(int);
73145857Sumestatic void *resolvloop(void *);
74145857Sumestatic void run(int *);
75145857Sume
76145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
77145857Sume
78145857Sumestatic void
79145857Sumeusage(void)
80145857Sume{
81145857Sume	(void)fprintf(stderr,
82145860Sume	    "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n",
83145857Sume	    getprogname());
84145857Sume	exit(1);
85145857Sume}
86145857Sume
87145857Sumestatic void
88145857Sumeload(const char *fname)
89145857Sume{
90145857Sume	FILE *fp;
91145857Sume	size_t len;
92145857Sume	char *line;
93145857Sume
94145857Sume	if ((fp = fopen(fname, "r")) == NULL)
95145857Sume		err(1, "Cannot open `%s'", fname);
96145857Sume	while ((line = fgetln(fp, &len)) != NULL) {
97145857Sume		char c = line[len];
98145857Sume		char *ptr;
99145857Sume		line[len] = '\0';
100145857Sume		for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS))
101145857Sume			sl_add(hosts, strdup(ptr));
102145857Sume		line[len] = c;
103145857Sume	}
104145857Sume
105145857Sume	(void)fclose(fp);
106145857Sume}
107145857Sume
108145860Sumestatic int
109145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port)
110145860Sume{
111145860Sume	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
112145860Sume	struct addrinfo hints, *res;
113145860Sume	int error, len;
114145860Sume
115145860Sume	snprintf(portstr, sizeof(portstr), "%d", port);
116145860Sume	memset(&hints, 0, sizeof(hints));
117145860Sume	hints.ai_family = AF_UNSPEC;
118145860Sume	hints.ai_flags = AI_PASSIVE;
119145860Sume	hints.ai_socktype = SOCK_STREAM;
120145860Sume	error = getaddrinfo(host, portstr, &hints, &res);
121145860Sume	if (debug) {
122145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
123145860Sume		    self, host, error ? "not found" : "ok");
124145860Sume		(void)write(STDOUT_FILENO, buf, len);
125145860Sume	}
126145860Sume	if (error == 0 && reverse) {
127145860Sume		memset(hbuf, 0, sizeof(hbuf));
128145860Sume		memset(pbuf, 0, sizeof(pbuf));
129145860Sume		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
130145860Sume			    pbuf, sizeof(pbuf), 0);
131145860Sume		if (debug) {
132145860Sume			len = snprintf(buf, sizeof(buf),
133145860Sume			    "%p: reverse %s %s\n", self, hbuf, pbuf);
134145860Sume			(void)write(STDOUT_FILENO, buf, len);
135145860Sume		}
136145860Sume	}
137145860Sume	if (error == 0)
138145860Sume		freeaddrinfo(res);
139145860Sume	return error;
140145860Sume}
141145860Sume
142145860Sumestatic int
143145860Sumeresolv_gethostby(pthread_t self, char *host)
144145860Sume{
145145860Sume	char buf[1024];
146145860Sume	struct hostent *hp, *hp2;
147145860Sume	int len;
148145860Sume
149145860Sume	hp = gethostbyname(host);
150145860Sume	if (debug) {
151145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
152145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
153145860Sume		(void)write(STDOUT_FILENO, buf, len);
154145860Sume	}
155145860Sume	if (hp && reverse) {
156145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
157145860Sume		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
158145860Sume		if (hp2 && debug) {
159145860Sume			len = snprintf(buf, sizeof(buf),
160145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
161145860Sume			(void)write(STDOUT_FILENO, buf, len);
162145860Sume		}
163145860Sume	}
164145860Sume	return hp ? 0 : -1;
165145860Sume}
166145860Sume
167145860Sumestatic int
168145860Sumeresolv_getipnodeby(pthread_t self, char *host)
169145860Sume{
170145860Sume	char buf[1024];
171145860Sume	struct hostent *hp, *hp2;
172145860Sume	int len, h_error;
173145860Sume
174145860Sume	hp = getipnodebyname(host, AF_INET, 0, &h_error);
175145860Sume	if (debug) {
176145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
177145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
178145860Sume		(void)write(STDOUT_FILENO, buf, len);
179145860Sume	}
180145860Sume	if (hp && reverse) {
181145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
182145860Sume		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
183145860Sume		    &h_error);
184145860Sume		if (hp2 && debug) {
185145860Sume			len = snprintf(buf, sizeof(buf),
186145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
187145860Sume			(void)write(STDOUT_FILENO, buf, len);
188145860Sume		}
189145860Sume		if (hp2)
190145860Sume			freehostent(hp2);
191145860Sume	}
192145860Sume	if (hp)
193145860Sume		freehostent(hp);
194145860Sume	return hp ? 0 : -1;
195145860Sume}
196145860Sume
197145857Sumestatic void
198145857Sumeresolvone(int n)
199145857Sume{
200145857Sume	char buf[1024];
201145857Sume	pthread_t self = pthread_self();
202145857Sume	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
203145857Sume	char *host = hosts->sl_str[i];
204145860Sume	struct addrinfo hints, *res;
205145857Sume	int error, len;
206145860Sume
207145857Sume	if (debug) {
208145857Sume		len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
209145857Sume		    self, n, host, (int)i);
210145857Sume		(void)write(STDOUT_FILENO, buf, len);
211145857Sume	}
212145860Sume	switch (method) {
213145860Sume	case METHOD_GETADDRINFO:
214145860Sume		error = resolv_getaddrinfo(self, host, i);
215145860Sume		break;
216145860Sume	case METHOD_GETHOSTBY:
217145860Sume		error = resolv_gethostby(self, host);
218145860Sume		break;
219145860Sume	case METHOD_GETIPNODEBY:
220145860Sume		error = resolv_getipnodeby(self, host);
221145860Sume		break;
222145860Sume	default:
223145860Sume		break;
224145857Sume	}
225145857Sume	pthread_mutex_lock(&stats);
226145857Sume	ask[i]++;
227145857Sume	got[i] += error == 0;
228145857Sume	pthread_mutex_unlock(&stats);
229145857Sume}
230145857Sume
231145857Sumestatic void *
232145857Sumeresolvloop(void *p)
233145857Sume{
234145857Sume	int *nhosts = (int *)p;
235145857Sume	if (*nhosts == 0)
236145857Sume		return;
237145857Sume	do
238145857Sume		resolvone(*nhosts);
239145857Sume	while (--(*nhosts));
240145857Sume	return NULL;
241145857Sume}
242145857Sume
243145857Sumestatic void
244145857Sumerun(int *nhosts)
245145857Sume{
246145857Sume	pthread_t self = pthread_self();
247145857Sume	if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
248145857Sume		err(1, "pthread_create");
249145857Sume}
250145857Sume
251145857Sumeint
252145857Sumemain(int argc, char *argv[])
253145857Sume{
254145857Sume	int nthreads = NTHREADS;
255145857Sume	int nhosts = NHOSTS;
256145857Sume	int i, c, done, *nleft;
257145857Sume	hosts = sl_init();
258145857Sume
259145857Sume	srandom(1234);
260145857Sume
261145860Sume	while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1)
262145857Sume		switch (c) {
263145860Sume		case 'A':
264145860Sume			method = METHOD_GETADDRINFO;
265145860Sume			break;
266145857Sume		case 'd':
267145857Sume			debug++;
268145857Sume			break;
269145857Sume		case 'h':
270145857Sume			nhosts = atoi(optarg);
271145857Sume			break;
272145860Sume		case 'H':
273145860Sume			method = METHOD_GETHOSTBY;
274145860Sume			break;
275145860Sume		case 'I':
276145860Sume			method = METHOD_GETIPNODEBY;
277145860Sume			break;
278145857Sume		case 'n':
279145857Sume			nthreads = atoi(optarg);
280145857Sume			break;
281145860Sume		case 'r':
282145860Sume			reverse++;
283145860Sume			break;
284145857Sume		default:
285145857Sume			usage();
286145857Sume		}
287145857Sume
288145857Sume	for (i = optind; i < argc; i++)
289145857Sume		load(argv[i]);
290145857Sume
291145857Sume	if (hosts->sl_cur == 0)
292145857Sume		usage();
293145857Sume
294145857Sume	if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
295145857Sume		err(1, "malloc");
296145857Sume	if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
297145857Sume		err(1, "calloc");
298145857Sume	if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
299145857Sume		err(1, "calloc");
300145857Sume
301145857Sume
302145857Sume	for (i = 0; i < nthreads; i++) {
303145857Sume		nleft[i] = nhosts;
304145857Sume		run(&nleft[i]);
305145857Sume	}
306145857Sume
307145857Sume	for (done = 0; !done;) {
308145857Sume		done = 1;
309145857Sume		for (i = 0; i < nthreads; i++) {
310145857Sume			if (nleft[i] != 0) {
311145857Sume				done = 0;
312145857Sume				break;
313145857Sume			}
314145857Sume		}
315145857Sume		sleep(1);
316145857Sume	}
317145857Sume	c = 0;
318145857Sume	for (i = 0; i < hosts->sl_cur; i++) {
319145857Sume		if (ask[i] != got[i] && got[i] != 0) {
320145857Sume			warnx("Error: host %s ask %d got %d\n",
321145857Sume			    hosts->sl_str[i], ask[i], got[i]);
322145857Sume			c++;
323145857Sume		}
324145857Sume	}
325145857Sume	free(nleft);
326145857Sume	free(ask);
327145857Sume	free(got);
328145857Sume	sl_free(hosts, 1);
329145857Sume	return c;
330145857Sume}
331