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