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