resolv_test.c revision 145860
1/*	$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38/* $FreeBSD: head/tools/regression/lib/libc/resolv/resolv.c 145860 2005-05-04 12:02:10Z ume $ */
39#include <sys/cdefs.h>
40__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
41
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <pthread.h>
45#include <stdio.h>
46#include <netdb.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <err.h>
50#include <string.h>
51#include <stringlist.h>
52
53#define NTHREADS	10
54#define NHOSTS		100
55#define WS		" \t\n\r"
56
57enum method {
58	METHOD_GETADDRINFO,
59	METHOD_GETHOSTBY,
60	METHOD_GETIPNODEBY
61};
62
63static StringList *hosts = NULL;
64static int debug = 0;
65static enum method method = METHOD_GETADDRINFO;
66static int reverse = 0;
67static int *ask = NULL;
68static int *got = NULL;
69
70static void usage(void)  __attribute__((__noreturn__));
71static void load(const char *);
72static void resolvone(int);
73static void *resolvloop(void *);
74static void run(int *);
75
76static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
77
78static void
79usage(void)
80{
81	(void)fprintf(stderr,
82	    "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n",
83	    getprogname());
84	exit(1);
85}
86
87static void
88load(const char *fname)
89{
90	FILE *fp;
91	size_t len;
92	char *line;
93
94	if ((fp = fopen(fname, "r")) == NULL)
95		err(1, "Cannot open `%s'", fname);
96	while ((line = fgetln(fp, &len)) != NULL) {
97		char c = line[len];
98		char *ptr;
99		line[len] = '\0';
100		for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS))
101			sl_add(hosts, strdup(ptr));
102		line[len] = c;
103	}
104
105	(void)fclose(fp);
106}
107
108static int
109resolv_getaddrinfo(pthread_t self, char *host, int port)
110{
111	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
112	struct addrinfo hints, *res;
113	int error, len;
114
115	snprintf(portstr, sizeof(portstr), "%d", port);
116	memset(&hints, 0, sizeof(hints));
117	hints.ai_family = AF_UNSPEC;
118	hints.ai_flags = AI_PASSIVE;
119	hints.ai_socktype = SOCK_STREAM;
120	error = getaddrinfo(host, portstr, &hints, &res);
121	if (debug) {
122		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
123		    self, host, error ? "not found" : "ok");
124		(void)write(STDOUT_FILENO, buf, len);
125	}
126	if (error == 0 && reverse) {
127		memset(hbuf, 0, sizeof(hbuf));
128		memset(pbuf, 0, sizeof(pbuf));
129		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
130			    pbuf, sizeof(pbuf), 0);
131		if (debug) {
132			len = snprintf(buf, sizeof(buf),
133			    "%p: reverse %s %s\n", self, hbuf, pbuf);
134			(void)write(STDOUT_FILENO, buf, len);
135		}
136	}
137	if (error == 0)
138		freeaddrinfo(res);
139	return error;
140}
141
142static int
143resolv_gethostby(pthread_t self, char *host)
144{
145	char buf[1024];
146	struct hostent *hp, *hp2;
147	int len;
148
149	hp = gethostbyname(host);
150	if (debug) {
151		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
152		    self, host, (hp == NULL) ? "not found" : "ok");
153		(void)write(STDOUT_FILENO, buf, len);
154	}
155	if (hp && reverse) {
156		memcpy(buf, hp->h_addr, hp->h_length);
157		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
158		if (hp2 && debug) {
159			len = snprintf(buf, sizeof(buf),
160			    "%p: reverse %s\n", self, hp2->h_name);
161			(void)write(STDOUT_FILENO, buf, len);
162		}
163	}
164	return hp ? 0 : -1;
165}
166
167static int
168resolv_getipnodeby(pthread_t self, char *host)
169{
170	char buf[1024];
171	struct hostent *hp, *hp2;
172	int len, h_error;
173
174	hp = getipnodebyname(host, AF_INET, 0, &h_error);
175	if (debug) {
176		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
177		    self, host, (hp == NULL) ? "not found" : "ok");
178		(void)write(STDOUT_FILENO, buf, len);
179	}
180	if (hp && reverse) {
181		memcpy(buf, hp->h_addr, hp->h_length);
182		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
183		    &h_error);
184		if (hp2 && debug) {
185			len = snprintf(buf, sizeof(buf),
186			    "%p: reverse %s\n", self, hp2->h_name);
187			(void)write(STDOUT_FILENO, buf, len);
188		}
189		if (hp2)
190			freehostent(hp2);
191	}
192	if (hp)
193		freehostent(hp);
194	return hp ? 0 : -1;
195}
196
197static void
198resolvone(int n)
199{
200	char buf[1024];
201	pthread_t self = pthread_self();
202	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
203	char *host = hosts->sl_str[i];
204	struct addrinfo hints, *res;
205	int error, len;
206
207	if (debug) {
208		len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
209		    self, n, host, (int)i);
210		(void)write(STDOUT_FILENO, buf, len);
211	}
212	switch (method) {
213	case METHOD_GETADDRINFO:
214		error = resolv_getaddrinfo(self, host, i);
215		break;
216	case METHOD_GETHOSTBY:
217		error = resolv_gethostby(self, host);
218		break;
219	case METHOD_GETIPNODEBY:
220		error = resolv_getipnodeby(self, host);
221		break;
222	default:
223		break;
224	}
225	pthread_mutex_lock(&stats);
226	ask[i]++;
227	got[i] += error == 0;
228	pthread_mutex_unlock(&stats);
229}
230
231static void *
232resolvloop(void *p)
233{
234	int *nhosts = (int *)p;
235	if (*nhosts == 0)
236		return;
237	do
238		resolvone(*nhosts);
239	while (--(*nhosts));
240	return NULL;
241}
242
243static void
244run(int *nhosts)
245{
246	pthread_t self = pthread_self();
247	if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
248		err(1, "pthread_create");
249}
250
251int
252main(int argc, char *argv[])
253{
254	int nthreads = NTHREADS;
255	int nhosts = NHOSTS;
256	int i, c, done, *nleft;
257	hosts = sl_init();
258
259	srandom(1234);
260
261	while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1)
262		switch (c) {
263		case 'A':
264			method = METHOD_GETADDRINFO;
265			break;
266		case 'd':
267			debug++;
268			break;
269		case 'h':
270			nhosts = atoi(optarg);
271			break;
272		case 'H':
273			method = METHOD_GETHOSTBY;
274			break;
275		case 'I':
276			method = METHOD_GETIPNODEBY;
277			break;
278		case 'n':
279			nthreads = atoi(optarg);
280			break;
281		case 'r':
282			reverse++;
283			break;
284		default:
285			usage();
286		}
287
288	for (i = optind; i < argc; i++)
289		load(argv[i]);
290
291	if (hosts->sl_cur == 0)
292		usage();
293
294	if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
295		err(1, "malloc");
296	if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
297		err(1, "calloc");
298	if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
299		err(1, "calloc");
300
301
302	for (i = 0; i < nthreads; i++) {
303		nleft[i] = nhosts;
304		run(&nleft[i]);
305	}
306
307	for (done = 0; !done;) {
308		done = 1;
309		for (i = 0; i < nthreads; i++) {
310			if (nleft[i] != 0) {
311				done = 0;
312				break;
313			}
314		}
315		sleep(1);
316	}
317	c = 0;
318	for (i = 0; i < hosts->sl_cur; i++) {
319		if (ask[i] != got[i] && got[i] != 0) {
320			warnx("Error: host %s ask %d got %d\n",
321			    hosts->sl_str[i], ask[i], got[i]);
322			c++;
323		}
324	}
325	free(nleft);
326	free(ask);
327	free(got);
328	sl_free(hosts, 1);
329	return c;
330}
331