resolv_test.c revision 243346
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 243346 2012-11-20 19:23:44Z emaste $ */
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			sl_add(hosts, strdup(ptr));
95		line[len] = c;
96	}
97
98	(void)fclose(fp);
99}
100
101static int
102resolv_getaddrinfo(pthread_t self, char *host, int port)
103{
104	char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
105	struct addrinfo hints, *res;
106	int error, len;
107
108	snprintf(portstr, sizeof(portstr), "%d", port);
109	memset(&hints, 0, sizeof(hints));
110	hints.ai_family = AF_UNSPEC;
111	hints.ai_flags = AI_PASSIVE;
112	hints.ai_socktype = SOCK_STREAM;
113	error = getaddrinfo(host, portstr, &hints, &res);
114	if (debug) {
115		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
116		    self, host, error ? "not found" : "ok");
117		(void)write(STDOUT_FILENO, buf, len);
118	}
119	if (error == 0 && reverse) {
120		memset(hbuf, 0, sizeof(hbuf));
121		memset(pbuf, 0, sizeof(pbuf));
122		getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
123			    pbuf, sizeof(pbuf), 0);
124		if (debug) {
125			len = snprintf(buf, sizeof(buf),
126			    "%p: reverse %s %s\n", self, hbuf, pbuf);
127			(void)write(STDOUT_FILENO, buf, len);
128		}
129	}
130	if (error == 0)
131		freeaddrinfo(res);
132	return error;
133}
134
135static int
136resolv_gethostby(pthread_t self, char *host)
137{
138	char buf[1024];
139	struct hostent *hp, *hp2;
140	int len;
141
142	hp = gethostbyname(host);
143	if (debug) {
144		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
145		    self, host, (hp == NULL) ? "not found" : "ok");
146		(void)write(STDOUT_FILENO, buf, len);
147	}
148	if (hp && reverse) {
149		memcpy(buf, hp->h_addr, hp->h_length);
150		hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
151		if (hp2 && debug) {
152			len = snprintf(buf, sizeof(buf),
153			    "%p: reverse %s\n", self, hp2->h_name);
154			(void)write(STDOUT_FILENO, buf, len);
155		}
156	}
157	return hp ? 0 : -1;
158}
159
160static int
161resolv_getipnodeby(pthread_t self, char *host)
162{
163	char buf[1024];
164	struct hostent *hp, *hp2;
165	int len, h_error;
166
167	hp = getipnodebyname(host, AF_INET, 0, &h_error);
168	if (debug) {
169		len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
170		    self, host, (hp == NULL) ? "not found" : "ok");
171		(void)write(STDOUT_FILENO, buf, len);
172	}
173	if (hp && reverse) {
174		memcpy(buf, hp->h_addr, hp->h_length);
175		hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
176		    &h_error);
177		if (hp2 && debug) {
178			len = snprintf(buf, sizeof(buf),
179			    "%p: reverse %s\n", self, hp2->h_name);
180			(void)write(STDOUT_FILENO, buf, len);
181		}
182		if (hp2)
183			freehostent(hp2);
184	}
185	if (hp)
186		freehostent(hp);
187	return hp ? 0 : -1;
188}
189
190static void
191resolvone(int n)
192{
193	char buf[1024];
194	pthread_t self = pthread_self();
195	size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
196	char *host = hosts->sl_str[i];
197	struct addrinfo hints, *res;
198	int error, len;
199
200	if (debug) {
201		len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
202		    self, n, host, (int)i);
203		(void)write(STDOUT_FILENO, buf, len);
204	}
205	switch (method) {
206	case METHOD_GETADDRINFO:
207		error = resolv_getaddrinfo(self, host, i);
208		break;
209	case METHOD_GETHOSTBY:
210		error = resolv_gethostby(self, host);
211		break;
212	case METHOD_GETIPNODEBY:
213		error = resolv_getipnodeby(self, host);
214		break;
215	default:
216		break;
217	}
218	pthread_mutex_lock(&stats);
219	ask[i]++;
220	got[i] += error == 0;
221	pthread_mutex_unlock(&stats);
222}
223
224static void *
225resolvloop(void *p)
226{
227	int *nhosts = (int *)p;
228	if (*nhosts == 0)
229		return NULL;
230	do
231		resolvone(*nhosts);
232	while (--(*nhosts));
233	return NULL;
234}
235
236static void
237run(int *nhosts)
238{
239	pthread_t self = pthread_self();
240	if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
241		err(1, "pthread_create");
242}
243
244int
245main(int argc, char *argv[])
246{
247	int nthreads = NTHREADS;
248	int nhosts = NHOSTS;
249	int i, c, done, *nleft;
250	hosts = sl_init();
251
252	srandom(1234);
253
254	while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1)
255		switch (c) {
256		case 'A':
257			method = METHOD_GETADDRINFO;
258			break;
259		case 'd':
260			debug++;
261			break;
262		case 'h':
263			nhosts = atoi(optarg);
264			break;
265		case 'H':
266			method = METHOD_GETHOSTBY;
267			break;
268		case 'I':
269			method = METHOD_GETIPNODEBY;
270			break;
271		case 'n':
272			nthreads = atoi(optarg);
273			break;
274		case 'r':
275			reverse++;
276			break;
277		default:
278			usage();
279		}
280
281	for (i = optind; i < argc; i++)
282		load(argv[i]);
283
284	if (hosts->sl_cur == 0)
285		usage();
286
287	if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
288		err(1, "malloc");
289	if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
290		err(1, "calloc");
291	if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
292		err(1, "calloc");
293
294
295	for (i = 0; i < nthreads; i++) {
296		nleft[i] = nhosts;
297		run(&nleft[i]);
298	}
299
300	for (done = 0; !done;) {
301		done = 1;
302		for (i = 0; i < nthreads; i++) {
303			if (nleft[i] != 0) {
304				done = 0;
305				break;
306			}
307		}
308		sleep(1);
309	}
310	c = 0;
311	for (i = 0; i < hosts->sl_cur; i++) {
312		if (ask[i] != got[i] && got[i] != 0) {
313			warnx("Error: host %s ask %d got %d\n",
314			    hosts->sl_str[i], ask[i], got[i]);
315			c++;
316		}
317	}
318	free(nleft);
319	free(ask);
320	free(got);
321	sl_free(hosts, 1);
322	return c;
323}
324