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