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 <err.h>
43145857Sume#include <string.h>
44145857Sume#include <stringlist.h>
45145857Sume
46145857Sume#define NTHREADS	10
47145857Sume#define NHOSTS		100
48145857Sume#define WS		" \t\n\r"
49145857Sume
50145860Sumeenum method {
51145860Sume	METHOD_GETADDRINFO,
52145860Sume	METHOD_GETHOSTBY,
53145860Sume	METHOD_GETIPNODEBY
54145860Sume};
55145860Sume
56145857Sumestatic StringList *hosts = NULL;
57145857Sumestatic int debug = 0;
58145860Sumestatic enum method method = METHOD_GETADDRINFO;
59145860Sumestatic int reverse = 0;
60145857Sumestatic int *ask = NULL;
61145857Sumestatic int *got = NULL;
62145857Sume
63145857Sumestatic void usage(void)  __attribute__((__noreturn__));
64145857Sumestatic void load(const char *);
65145857Sumestatic void resolvone(int);
66145857Sumestatic void *resolvloop(void *);
67145857Sumestatic void run(int *);
68145857Sume
69145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
70145857Sume
71145857Sumestatic void
72145857Sumeusage(void)
73145857Sume{
74145857Sume	(void)fprintf(stderr,
75145860Sume	    "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n",
76145857Sume	    getprogname());
77145857Sume	exit(1);
78145857Sume}
79145857Sume
80145857Sumestatic void
81145857Sumeload(const char *fname)
82145857Sume{
83145857Sume	FILE *fp;
84145857Sume	size_t len;
85145857Sume	char *line;
86145857Sume
87145857Sume	if ((fp = fopen(fname, "r")) == NULL)
88145857Sume		err(1, "Cannot open `%s'", fname);
89145857Sume	while ((line = fgetln(fp, &len)) != NULL) {
90145857Sume		char c = line[len];
91145857Sume		char *ptr;
92145857Sume		line[len] = '\0';
93291761Sngie		for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) {
94291761Sngie			if (ptr == '\0' || ptr[0] == '#')
95291761Sngie				continue;
96145857Sume			sl_add(hosts, strdup(ptr));
97291761Sngie		}
98145857Sume		line[len] = c;
99145857Sume	}
100145857Sume
101145857Sume	(void)fclose(fp);
102145857Sume}
103145857Sume
104145860Sumestatic int
105145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port)
106145860Sume{
107145860Sume	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
108145860Sume	struct addrinfo hints, *res;
109145860Sume	int error, len;
110145860Sume
111145860Sume	snprintf(portstr, sizeof(portstr), "%d", port);
112145860Sume	memset(&hints, 0, sizeof(hints));
113145860Sume	hints.ai_family = AF_UNSPEC;
114145860Sume	hints.ai_flags = AI_PASSIVE;
115145860Sume	hints.ai_socktype = SOCK_STREAM;
116145860Sume	error = getaddrinfo(host, portstr, &hints, &res);
117145860Sume	if (debug) {
118145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
119145860Sume		    self, host, error ? "not found" : "ok");
120145860Sume		(void)write(STDOUT_FILENO, buf, len);
121145860Sume	}
122145860Sume	if (error == 0 && reverse) {
123145860Sume		memset(hbuf, 0, sizeof(hbuf));
124145860Sume		memset(pbuf, 0, sizeof(pbuf));
125145860Sume		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
126145860Sume			    pbuf, sizeof(pbuf), 0);
127145860Sume		if (debug) {
128145860Sume			len = snprintf(buf, sizeof(buf),
129145860Sume			    "%p: reverse %s %s\n", self, hbuf, pbuf);
130145860Sume			(void)write(STDOUT_FILENO, buf, len);
131145860Sume		}
132145860Sume	}
133145860Sume	if (error == 0)
134145860Sume		freeaddrinfo(res);
135145860Sume	return error;
136145860Sume}
137145860Sume
138145860Sumestatic int
139145860Sumeresolv_gethostby(pthread_t self, char *host)
140145860Sume{
141145860Sume	char buf[1024];
142145860Sume	struct hostent *hp, *hp2;
143145860Sume	int len;
144145860Sume
145145860Sume	hp = gethostbyname(host);
146145860Sume	if (debug) {
147145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
148145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
149145860Sume		(void)write(STDOUT_FILENO, buf, len);
150145860Sume	}
151145860Sume	if (hp && reverse) {
152145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
153145860Sume		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
154145860Sume		if (hp2 && debug) {
155145860Sume			len = snprintf(buf, sizeof(buf),
156145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
157145860Sume			(void)write(STDOUT_FILENO, buf, len);
158145860Sume		}
159145860Sume	}
160145860Sume	return hp ? 0 : -1;
161145860Sume}
162145860Sume
163145860Sumestatic int
164145860Sumeresolv_getipnodeby(pthread_t self, char *host)
165145860Sume{
166145860Sume	char buf[1024];
167145860Sume	struct hostent *hp, *hp2;
168145860Sume	int len, h_error;
169145860Sume
170145860Sume	hp = getipnodebyname(host, AF_INET, 0, &h_error);
171145860Sume	if (debug) {
172145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
173145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
174145860Sume		(void)write(STDOUT_FILENO, buf, len);
175145860Sume	}
176145860Sume	if (hp && reverse) {
177145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
178145860Sume		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
179145860Sume		    &h_error);
180145860Sume		if (hp2 && debug) {
181145860Sume			len = snprintf(buf, sizeof(buf),
182145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
183145860Sume			(void)write(STDOUT_FILENO, buf, len);
184145860Sume		}
185145860Sume		if (hp2)
186145860Sume			freehostent(hp2);
187145860Sume	}
188145860Sume	if (hp)
189145860Sume		freehostent(hp);
190145860Sume	return hp ? 0 : -1;
191145860Sume}
192145860Sume
193145857Sumestatic void
194145857Sumeresolvone(int n)
195145857Sume{
196145857Sume	char buf[1024];
197145857Sume	pthread_t self = pthread_self();
198145857Sume	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
199145857Sume	char *host = hosts->sl_str[i];
200145860Sume	struct addrinfo hints, *res;
201145857Sume	int error, len;
202145860Sume
203145857Sume	if (debug) {
204145857Sume		len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
205145857Sume		    self, n, host, (int)i);
206145857Sume		(void)write(STDOUT_FILENO, buf, len);
207145857Sume	}
208145860Sume	switch (method) {
209145860Sume	case METHOD_GETADDRINFO:
210145860Sume		error = resolv_getaddrinfo(self, host, i);
211145860Sume		break;
212145860Sume	case METHOD_GETHOSTBY:
213145860Sume		error = resolv_gethostby(self, host);
214145860Sume		break;
215145860Sume	case METHOD_GETIPNODEBY:
216145860Sume		error = resolv_getipnodeby(self, host);
217145860Sume		break;
218145860Sume	default:
219145860Sume		break;
220145857Sume	}
221145857Sume	pthread_mutex_lock(&stats);
222145857Sume	ask[i]++;
223145857Sume	got[i] += error == 0;
224145857Sume	pthread_mutex_unlock(&stats);
225145857Sume}
226145857Sume
227145857Sumestatic void *
228145857Sumeresolvloop(void *p)
229145857Sume{
230145857Sume	int *nhosts = (int *)p;
231145857Sume	if (*nhosts == 0)
232243346Semaste		return NULL;
233145857Sume	do
234145857Sume		resolvone(*nhosts);
235145857Sume	while (--(*nhosts));
236145857Sume	return NULL;
237145857Sume}
238145857Sume
239145857Sumestatic void
240145857Sumerun(int *nhosts)
241145857Sume{
242145857Sume	pthread_t self = pthread_self();
243145857Sume	if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
244145857Sume		err(1, "pthread_create");
245145857Sume}
246145857Sume
247145857Sumeint
248145857Sumemain(int argc, char *argv[])
249145857Sume{
250145857Sume	int nthreads = NTHREADS;
251145857Sume	int nhosts = NHOSTS;
252145857Sume	int i, c, done, *nleft;
253145857Sume	hosts = sl_init();
254145857Sume
255145857Sume	srandom(1234);
256145857Sume
257145860Sume	while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1)
258145857Sume		switch (c) {
259145860Sume		case 'A':
260145860Sume			method = METHOD_GETADDRINFO;
261145860Sume			break;
262145857Sume		case 'd':
263145857Sume			debug++;
264145857Sume			break;
265145857Sume		case 'h':
266145857Sume			nhosts = atoi(optarg);
267145857Sume			break;
268145860Sume		case 'H':
269145860Sume			method = METHOD_GETHOSTBY;
270145860Sume			break;
271145860Sume		case 'I':
272145860Sume			method = METHOD_GETIPNODEBY;
273145860Sume			break;
274145857Sume		case 'n':
275145857Sume			nthreads = atoi(optarg);
276145857Sume			break;
277145860Sume		case 'r':
278145860Sume			reverse++;
279145860Sume			break;
280145857Sume		default:
281145857Sume			usage();
282145857Sume		}
283145857Sume
284145857Sume	for (i = optind; i < argc; i++)
285145857Sume		load(argv[i]);
286145857Sume
287145857Sume	if (hosts->sl_cur == 0)
288145857Sume		usage();
289145857Sume
290145857Sume	if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
291145857Sume		err(1, "malloc");
292145857Sume	if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
293145857Sume		err(1, "calloc");
294145857Sume	if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
295145857Sume		err(1, "calloc");
296145857Sume
297145857Sume
298145857Sume	for (i = 0; i < nthreads; i++) {
299145857Sume		nleft[i] = nhosts;
300145857Sume		run(&nleft[i]);
301145857Sume	}
302145857Sume
303145857Sume	for (done = 0; !done;) {
304145857Sume		done = 1;
305145857Sume		for (i = 0; i < nthreads; i++) {
306145857Sume			if (nleft[i] != 0) {
307145857Sume				done = 0;
308145857Sume				break;
309145857Sume			}
310145857Sume		}
311145857Sume		sleep(1);
312145857Sume	}
313145857Sume	c = 0;
314145857Sume	for (i = 0; i < hosts->sl_cur; i++) {
315145857Sume		if (ask[i] != got[i] && got[i] != 0) {
316145857Sume			warnx("Error: host %s ask %d got %d\n",
317145857Sume			    hosts->sl_str[i], ask[i], got[i]);
318145857Sume			c++;
319145857Sume		}
320145857Sume	}
321145857Sume	free(nleft);
322145857Sume	free(ask);
323145857Sume	free(got);
324145857Sume	sl_free(hosts, 1);
325145857Sume	return c;
326145857Sume}
327