1/* $NetBSD: h_resolv.c,v 1.2 2010/11/03 16:10:22 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2004, 2008 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 32#include <sys/cdefs.h> 33__COPYRIGHT("@(#) Copyright (c) 2008\ 34 The NetBSD Foundation, inc. All rights reserved."); 35__RCSID("$NetBSD: h_resolv.c,v 1.2 2010/11/03 16:10:22 christos Exp $"); 36 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 50static StringList *hosts = NULL; 51static int debug = 0; 52static int *ask = NULL; 53static int *got = NULL; 54 55static void usage(void) __attribute__((__noreturn__)); 56static void load(const char *); 57static void resolvone(int); 58static void *resolvloop(void *); 59static void run(int *); 60 61static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; 62 63static void 64usage(void) 65{ 66 (void)fprintf(stderr, 67 "Usage: %s [-d] [-h <nhosts>] [-n <nthreads>] <file> ...\n", 68 getprogname()); 69 exit(1); 70} 71 72static void 73load(const char *fname) 74{ 75 FILE *fp; 76 size_t len; 77 char *line; 78 79 if ((fp = fopen(fname, "r")) == NULL) 80 err(1, "Cannot open `%s'", fname); 81 while ((line = fgetln(fp, &len)) != NULL) { 82 char c = line[len]; 83 char *ptr; 84 line[len] = '\0'; 85 for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) 86 sl_add(hosts, strdup(ptr)); 87 line[len] = c; 88 } 89 90 (void)fclose(fp); 91} 92 93static void 94resolvone(int n) 95{ 96 char buf[1024]; 97 pthread_t self = pthread_self(); 98 size_t i = (random() & 0x0fffffff) % hosts->sl_cur; 99 char *host = hosts->sl_str[i]; 100 struct addrinfo *res; 101 int error, len; 102 if (debug) { 103 len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", 104 self, n, host, (int)i); 105 (void)write(STDOUT_FILENO, buf, len); 106 } 107 error = getaddrinfo(host, NULL, NULL, &res); 108 if (debug) { 109 len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 110 self, host, error ? "not found" : "ok"); 111 (void)write(STDOUT_FILENO, buf, len); 112 } 113 pthread_mutex_lock(&stats); 114 ask[i]++; 115 got[i] += error == 0; 116 pthread_mutex_unlock(&stats); 117 if (error == 0) 118 freeaddrinfo(res); 119} 120 121static void * 122resolvloop(void *p) 123{ 124 int *nhosts = (int *)p; 125 if (*nhosts == 0) 126 return NULL; 127 do 128 resolvone(*nhosts); 129 while (--(*nhosts)); 130 return NULL; 131} 132 133static void 134run(int *nhosts) 135{ 136 pthread_t self = pthread_self(); 137 if (pthread_create(&self, NULL, resolvloop, nhosts) != 0) 138 err(1, "pthread_create"); 139} 140 141int 142main(int argc, char *argv[]) 143{ 144 int nthreads = NTHREADS; 145 int nhosts = NHOSTS; 146 int i, c, done, *nleft; 147 hosts = sl_init(); 148 149 srandom(1234); 150 151 while ((c = getopt(argc, argv, "dh:n:")) != -1) 152 switch (c) { 153 case 'd': 154 debug++; 155 break; 156 case 'h': 157 nhosts = atoi(optarg); 158 break; 159 case 'n': 160 nthreads = atoi(optarg); 161 break; 162 default: 163 usage(); 164 } 165 166 for (i = optind; i < argc; i++) 167 load(argv[i]); 168 169 if (hosts->sl_cur == 0) 170 usage(); 171 172 if ((nleft = malloc(nthreads * sizeof(int))) == NULL) 173 err(1, "malloc"); 174 if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL) 175 err(1, "calloc"); 176 if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL) 177 err(1, "calloc"); 178 179 180 for (i = 0; i < nthreads; i++) { 181 nleft[i] = nhosts; 182 run(&nleft[i]); 183 } 184 185 for (done = 0; !done;) { 186 done = 1; 187 for (i = 0; i < nthreads; i++) { 188 if (nleft[i] != 0) { 189 done = 0; 190 break; 191 } 192 } 193 sleep(1); 194 } 195 c = 0; 196 for (i = 0; i < (int)hosts->sl_cur; i++) { 197 if (ask[i] != got[i] && got[i] != 0) { 198 warnx("Error: host %s ask %d got %d\n", 199 hosts->sl_str[i], ask[i], got[i]); 200 c++; 201 } 202 } 203 free(nleft); 204 free(ask); 205 free(got); 206 sl_free(hosts, 1); 207 return c; 208} 209