h_resolv.c revision 1.3 1 1.3 christos /* $NetBSD: h_resolv.c,v 1.3 2019/03/06 01:20:15 christos Exp $ */
2 1.1 jmmv
3 1.1 jmmv /*-
4 1.1 jmmv * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
5 1.1 jmmv * All rights reserved.
6 1.1 jmmv *
7 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation
8 1.1 jmmv * by Christos Zoulas.
9 1.1 jmmv *
10 1.1 jmmv * Redistribution and use in source and binary forms, with or without
11 1.1 jmmv * modification, are permitted provided that the following conditions
12 1.1 jmmv * are met:
13 1.1 jmmv * 1. Redistributions of source code must retain the above copyright
14 1.1 jmmv * notice, this list of conditions and the following disclaimer.
15 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jmmv * notice, this list of conditions and the following disclaimer in the
17 1.1 jmmv * documentation and/or other materials provided with the distribution.
18 1.1 jmmv *
19 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE.
30 1.1 jmmv */
31 1.1 jmmv
32 1.1 jmmv #include <sys/cdefs.h>
33 1.1 jmmv __COPYRIGHT("@(#) Copyright (c) 2008\
34 1.1 jmmv The NetBSD Foundation, inc. All rights reserved.");
35 1.3 christos __RCSID("$NetBSD: h_resolv.c,v 1.3 2019/03/06 01:20:15 christos Exp $");
36 1.1 jmmv
37 1.1 jmmv #include <pthread.h>
38 1.1 jmmv #include <stdio.h>
39 1.1 jmmv #include <netdb.h>
40 1.1 jmmv #include <stdlib.h>
41 1.1 jmmv #include <unistd.h>
42 1.1 jmmv #include <err.h>
43 1.1 jmmv #include <string.h>
44 1.1 jmmv #include <stringlist.h>
45 1.1 jmmv
46 1.1 jmmv #define NTHREADS 10
47 1.1 jmmv #define NHOSTS 100
48 1.1 jmmv #define WS " \t\n\r"
49 1.1 jmmv
50 1.1 jmmv static StringList *hosts = NULL;
51 1.1 jmmv static int debug = 0;
52 1.1 jmmv static int *ask = NULL;
53 1.1 jmmv static int *got = NULL;
54 1.1 jmmv
55 1.1 jmmv static void usage(void) __attribute__((__noreturn__));
56 1.1 jmmv static void load(const char *);
57 1.1 jmmv static void resolvone(int);
58 1.1 jmmv static void *resolvloop(void *);
59 1.3 christos static pthread_t run(int *);
60 1.1 jmmv
61 1.1 jmmv static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
62 1.1 jmmv
63 1.1 jmmv static void
64 1.1 jmmv usage(void)
65 1.1 jmmv {
66 1.1 jmmv (void)fprintf(stderr,
67 1.1 jmmv "Usage: %s [-d] [-h <nhosts>] [-n <nthreads>] <file> ...\n",
68 1.1 jmmv getprogname());
69 1.1 jmmv exit(1);
70 1.1 jmmv }
71 1.1 jmmv
72 1.1 jmmv static void
73 1.1 jmmv load(const char *fname)
74 1.1 jmmv {
75 1.1 jmmv FILE *fp;
76 1.1 jmmv size_t len;
77 1.1 jmmv char *line;
78 1.1 jmmv
79 1.1 jmmv if ((fp = fopen(fname, "r")) == NULL)
80 1.3 christos err(EXIT_FAILURE, "Cannot open `%s'", fname);
81 1.1 jmmv while ((line = fgetln(fp, &len)) != NULL) {
82 1.1 jmmv char c = line[len];
83 1.1 jmmv char *ptr;
84 1.1 jmmv line[len] = '\0';
85 1.1 jmmv for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS))
86 1.1 jmmv sl_add(hosts, strdup(ptr));
87 1.1 jmmv line[len] = c;
88 1.1 jmmv }
89 1.1 jmmv
90 1.1 jmmv (void)fclose(fp);
91 1.1 jmmv }
92 1.1 jmmv
93 1.1 jmmv static void
94 1.1 jmmv resolvone(int n)
95 1.1 jmmv {
96 1.1 jmmv char buf[1024];
97 1.1 jmmv pthread_t self = pthread_self();
98 1.1 jmmv size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
99 1.1 jmmv char *host = hosts->sl_str[i];
100 1.1 jmmv struct addrinfo *res;
101 1.1 jmmv int error, len;
102 1.1 jmmv if (debug) {
103 1.1 jmmv len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
104 1.1 jmmv self, n, host, (int)i);
105 1.1 jmmv (void)write(STDOUT_FILENO, buf, len);
106 1.1 jmmv }
107 1.1 jmmv error = getaddrinfo(host, NULL, NULL, &res);
108 1.1 jmmv if (debug) {
109 1.1 jmmv len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
110 1.1 jmmv self, host, error ? "not found" : "ok");
111 1.1 jmmv (void)write(STDOUT_FILENO, buf, len);
112 1.1 jmmv }
113 1.1 jmmv pthread_mutex_lock(&stats);
114 1.1 jmmv ask[i]++;
115 1.1 jmmv got[i] += error == 0;
116 1.1 jmmv pthread_mutex_unlock(&stats);
117 1.1 jmmv if (error == 0)
118 1.1 jmmv freeaddrinfo(res);
119 1.1 jmmv }
120 1.1 jmmv
121 1.1 jmmv static void *
122 1.1 jmmv resolvloop(void *p)
123 1.1 jmmv {
124 1.1 jmmv int *nhosts = (int *)p;
125 1.1 jmmv if (*nhosts == 0)
126 1.1 jmmv return NULL;
127 1.1 jmmv do
128 1.1 jmmv resolvone(*nhosts);
129 1.1 jmmv while (--(*nhosts));
130 1.1 jmmv return NULL;
131 1.1 jmmv }
132 1.1 jmmv
133 1.3 christos static pthread_t
134 1.1 jmmv run(int *nhosts)
135 1.1 jmmv {
136 1.1 jmmv pthread_t self = pthread_self();
137 1.1 jmmv if (pthread_create(&self, NULL, resolvloop, nhosts) != 0)
138 1.3 christos err(EXIT_FAILURE, "pthread_create");
139 1.3 christos return self;
140 1.1 jmmv }
141 1.1 jmmv
142 1.1 jmmv int
143 1.1 jmmv main(int argc, char *argv[])
144 1.1 jmmv {
145 1.1 jmmv int nthreads = NTHREADS;
146 1.3 christos pthread_t *threads;
147 1.1 jmmv int nhosts = NHOSTS;
148 1.1 jmmv int i, c, done, *nleft;
149 1.1 jmmv hosts = sl_init();
150 1.1 jmmv
151 1.1 jmmv srandom(1234);
152 1.1 jmmv
153 1.1 jmmv while ((c = getopt(argc, argv, "dh:n:")) != -1)
154 1.1 jmmv switch (c) {
155 1.1 jmmv case 'd':
156 1.1 jmmv debug++;
157 1.1 jmmv break;
158 1.1 jmmv case 'h':
159 1.1 jmmv nhosts = atoi(optarg);
160 1.1 jmmv break;
161 1.1 jmmv case 'n':
162 1.1 jmmv nthreads = atoi(optarg);
163 1.1 jmmv break;
164 1.1 jmmv default:
165 1.1 jmmv usage();
166 1.1 jmmv }
167 1.1 jmmv
168 1.1 jmmv for (i = optind; i < argc; i++)
169 1.1 jmmv load(argv[i]);
170 1.1 jmmv
171 1.1 jmmv if (hosts->sl_cur == 0)
172 1.1 jmmv usage();
173 1.1 jmmv
174 1.1 jmmv if ((nleft = malloc(nthreads * sizeof(int))) == NULL)
175 1.3 christos err(EXIT_FAILURE, "malloc");
176 1.1 jmmv if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL)
177 1.3 christos err(EXIT_FAILURE, "calloc");
178 1.1 jmmv if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL)
179 1.3 christos err(EXIT_FAILURE, "calloc");
180 1.3 christos if ((threads = malloc(nthreads * sizeof(pthread_t))) == NULL)
181 1.3 christos err(EXIT_FAILURE, "calloc");
182 1.1 jmmv
183 1.1 jmmv
184 1.1 jmmv for (i = 0; i < nthreads; i++) {
185 1.1 jmmv nleft[i] = nhosts;
186 1.3 christos threads[i] = run(&nleft[i]);
187 1.1 jmmv }
188 1.1 jmmv
189 1.1 jmmv for (done = 0; !done;) {
190 1.1 jmmv done = 1;
191 1.1 jmmv for (i = 0; i < nthreads; i++) {
192 1.1 jmmv if (nleft[i] != 0) {
193 1.1 jmmv done = 0;
194 1.1 jmmv break;
195 1.1 jmmv }
196 1.1 jmmv }
197 1.1 jmmv sleep(1);
198 1.1 jmmv }
199 1.1 jmmv c = 0;
200 1.2 christos for (i = 0; i < (int)hosts->sl_cur; i++) {
201 1.1 jmmv if (ask[i] != got[i] && got[i] != 0) {
202 1.1 jmmv warnx("Error: host %s ask %d got %d\n",
203 1.1 jmmv hosts->sl_str[i], ask[i], got[i]);
204 1.1 jmmv c++;
205 1.1 jmmv }
206 1.1 jmmv }
207 1.3 christos for (i = 0; i < nthreads; i++)
208 1.3 christos pthread_join(threads[i], NULL);
209 1.3 christos free(threads);
210 1.1 jmmv free(nleft);
211 1.1 jmmv free(ask);
212 1.1 jmmv free(got);
213 1.1 jmmv sl_free(hosts, 1);
214 1.1 jmmv return c;
215 1.1 jmmv }
216