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: releng/10.2/tools/regression/lib/libc/resolv/resolv.c 243346 2012-11-20 19:23:44Z emaste $ */
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';
93145857Sume		for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS))
94145857Sume			sl_add(hosts, strdup(ptr));
95145857Sume		line[len] = c;
96145857Sume	}
97145857Sume
98145857Sume	(void)fclose(fp);
99145857Sume}
100145857Sume
101145860Sumestatic int
102145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port)
103145860Sume{
104145860Sume	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
105145860Sume	struct addrinfo hints, *res;
106145860Sume	int error, len;
107145860Sume
108145860Sume	snprintf(portstr, sizeof(portstr), "%d", port);
109145860Sume	memset(&hints, 0, sizeof(hints));
110145860Sume	hints.ai_family = AF_UNSPEC;
111145860Sume	hints.ai_flags = AI_PASSIVE;
112145860Sume	hints.ai_socktype = SOCK_STREAM;
113145860Sume	error = getaddrinfo(host, portstr, &hints, &res);
114145860Sume	if (debug) {
115145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
116145860Sume		    self, host, error ? "not found" : "ok");
117145860Sume		(void)write(STDOUT_FILENO, buf, len);
118145860Sume	}
119145860Sume	if (error == 0 && reverse) {
120145860Sume		memset(hbuf, 0, sizeof(hbuf));
121145860Sume		memset(pbuf, 0, sizeof(pbuf));
122145860Sume		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
123145860Sume			    pbuf, sizeof(pbuf), 0);
124145860Sume		if (debug) {
125145860Sume			len = snprintf(buf, sizeof(buf),
126145860Sume			    "%p: reverse %s %s\n", self, hbuf, pbuf);
127145860Sume			(void)write(STDOUT_FILENO, buf, len);
128145860Sume		}
129145860Sume	}
130145860Sume	if (error == 0)
131145860Sume		freeaddrinfo(res);
132145860Sume	return error;
133145860Sume}
134145860Sume
135145860Sumestatic int
136145860Sumeresolv_gethostby(pthread_t self, char *host)
137145860Sume{
138145860Sume	char buf[1024];
139145860Sume	struct hostent *hp, *hp2;
140145860Sume	int len;
141145860Sume
142145860Sume	hp = gethostbyname(host);
143145860Sume	if (debug) {
144145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
145145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
146145860Sume		(void)write(STDOUT_FILENO, buf, len);
147145860Sume	}
148145860Sume	if (hp && reverse) {
149145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
150145860Sume		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
151145860Sume		if (hp2 && debug) {
152145860Sume			len = snprintf(buf, sizeof(buf),
153145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
154145860Sume			(void)write(STDOUT_FILENO, buf, len);
155145860Sume		}
156145860Sume	}
157145860Sume	return hp ? 0 : -1;
158145860Sume}
159145860Sume
160145860Sumestatic int
161145860Sumeresolv_getipnodeby(pthread_t self, char *host)
162145860Sume{
163145860Sume	char buf[1024];
164145860Sume	struct hostent *hp, *hp2;
165145860Sume	int len, h_error;
166145860Sume
167145860Sume	hp = getipnodebyname(host, AF_INET, 0, &h_error);
168145860Sume	if (debug) {
169145860Sume		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
170145860Sume		    self, host, (hp == NULL) ? "not found" : "ok");
171145860Sume		(void)write(STDOUT_FILENO, buf, len);
172145860Sume	}
173145860Sume	if (hp && reverse) {
174145860Sume		memcpy(buf, hp->h_addr, hp->h_length);
175145860Sume		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
176145860Sume		    &h_error);
177145860Sume		if (hp2 && debug) {
178145860Sume			len = snprintf(buf, sizeof(buf),
179145860Sume			    "%p: reverse %s\n", self, hp2->h_name);
180145860Sume			(void)write(STDOUT_FILENO, buf, len);
181145860Sume		}
182145860Sume		if (hp2)
183145860Sume			freehostent(hp2);
184145860Sume	}
185145860Sume	if (hp)
186145860Sume		freehostent(hp);
187145860Sume	return hp ? 0 : -1;
188145860Sume}
189145860Sume
190145857Sumestatic void
191145857Sumeresolvone(int n)
192145857Sume{
193145857Sume	char buf[1024];
194145857Sume	pthread_t self = pthread_self();
195145857Sume	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
196145857Sume	char *host = hosts->sl_str[i];
197145860Sume	struct addrinfo hints, *res;
198145857Sume	int error, len;
199145860Sume
200145857Sume	if (debug) {
201145857Sume		len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
202145857Sume		    self, n, host, (int)i);
203145857Sume		(void)write(STDOUT_FILENO, buf, len);
204145857Sume	}
205145860Sume	switch (method) {
206145860Sume	case METHOD_GETADDRINFO:
207145860Sume		error = resolv_getaddrinfo(self, host, i);
208145860Sume		break;
209145860Sume	case METHOD_GETHOSTBY:
210145860Sume		error = resolv_gethostby(self, host);
211145860Sume		break;
212145860Sume	case METHOD_GETIPNODEBY:
213145860Sume		error = resolv_getipnodeby(self, host);
214145860Sume		break;
215145860Sume	default:
216145860Sume		break;
217145857Sume	}
218145857Sume	pthread_mutex_lock(&stats);
219145857Sume	ask[i]++;
220145857Sume	got[i] += error == 0;
221145857Sume	pthread_mutex_unlock(&stats);
222145857Sume}
223145857Sume
224145857Sumestatic void *
225145857Sumeresolvloop(void *p)
226145857Sume{
227145857Sume	int *nhosts = (int *)p;
228145857Sume	if (*nhosts == 0)
229243346Semaste		return NULL;
230145857Sume	do
231145857Sume		resolvone(*nhosts);
232145857Sume	while (--(*nhosts));
233145857Sume	return NULL;
234145857Sume}
235145857Sume
236145857Sumestatic void
237145857Sumerun(int *nhosts)
238145857Sume{
239145857Sume	pthread_t self = pthread_self();
240145857Sume	if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
241145857Sume		err(1, "pthread_create");
242145857Sume}
243145857Sume
244145857Sumeint
245145857Sumemain(int argc, char *argv[])
246145857Sume{
247145857Sume	int nthreads = NTHREADS;
248145857Sume	int nhosts = NHOSTS;
249145857Sume	int i, c, done, *nleft;
250145857Sume	hosts = sl_init();
251145857Sume
252145857Sume	srandom(1234);
253145857Sume
254145860Sume	while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1)
255145857Sume		switch (c) {
256145860Sume		case 'A':
257145860Sume			method = METHOD_GETADDRINFO;
258145860Sume			break;
259145857Sume		case 'd':
260145857Sume			debug++;
261145857Sume			break;
262145857Sume		case 'h':
263145857Sume			nhosts = atoi(optarg);
264145857Sume			break;
265145860Sume		case 'H':
266145860Sume			method = METHOD_GETHOSTBY;
267145860Sume			break;
268145860Sume		case 'I':
269145860Sume			method = METHOD_GETIPNODEBY;
270145860Sume			break;
271145857Sume		case 'n':
272145857Sume			nthreads = atoi(optarg);
273145857Sume			break;
274145860Sume		case 'r':
275145860Sume			reverse++;
276145860Sume			break;
277145857Sume		default:
278145857Sume			usage();
279145857Sume		}
280145857Sume
281145857Sume	for (i = optind; i < argc; i++)
282145857Sume		load(argv[i]);
283145857Sume
284145857Sume	if (hosts->sl_cur == 0)
285145857Sume		usage();
286145857Sume
287145857Sume	if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
288145857Sume		err(1, "malloc");
289145857Sume	if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
290145857Sume		err(1, "calloc");
291145857Sume	if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
292145857Sume		err(1, "calloc");
293145857Sume
294145857Sume
295145857Sume	for (i = 0; i < nthreads; i++) {
296145857Sume		nleft[i] = nhosts;
297145857Sume		run(&nleft[i]);
298145857Sume	}
299145857Sume
300145857Sume	for (done = 0; !done;) {
301145857Sume		done = 1;
302145857Sume		for (i = 0; i < nthreads; i++) {
303145857Sume			if (nleft[i] != 0) {
304145857Sume				done = 0;
305145857Sume				break;
306145857Sume			}
307145857Sume		}
308145857Sume		sleep(1);
309145857Sume	}
310145857Sume	c = 0;
311145857Sume	for (i = 0; i < hosts->sl_cur; i++) {
312145857Sume		if (ask[i] != got[i] && got[i] != 0) {
313145857Sume			warnx("Error: host %s ask %d got %d\n",
314145857Sume			    hosts->sl_str[i], ask[i], got[i]);
315145857Sume			c++;
316145857Sume		}
317145857Sume	}
318145857Sume	free(nleft);
319145857Sume	free(ask);
320145857Sume	free(got);
321145857Sume	sl_free(hosts, 1);
322145857Sume	return c;
323145857Sume}
324