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: releng/10.2/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