1145857Sume/* $NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $ */ 2145857Sume 3145857Sume/*- 4145857Sume * Copyright (c) 2004 The NetBSD Foundation, Inc. 5145857Sume * All rights reserved. 6145857Sume * 7145857Sume * This code is derived from software contributed to The NetBSD Foundation 8145857Sume * by Christos Zoulas. 9145857Sume * 10145857Sume * Redistribution and use in source and binary forms, with or without 11145857Sume * modification, are permitted provided that the following conditions 12145857Sume * are met: 13145857Sume * 1. Redistributions of source code must retain the above copyright 14145857Sume * notice, this list of conditions and the following disclaimer. 15145857Sume * 2. Redistributions in binary form must reproduce the above copyright 16145857Sume * notice, this list of conditions and the following disclaimer in the 17145857Sume * documentation and/or other materials provided with the distribution. 18145857Sume * 19145857Sume * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20145857Sume * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21145857Sume * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22145857Sume * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23145857Sume * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24145857Sume * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25145857Sume * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26145857Sume * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27145857Sume * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28145857Sume * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29145857Sume * POSSIBILITY OF SUCH DAMAGE. 30145857Sume */ 31145860Sume/* $FreeBSD$ */ 32145857Sume#include <sys/cdefs.h> 33145857Sume__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $"); 34145857Sume 35145860Sume#include <sys/types.h> 36145860Sume#include <sys/socket.h> 37145857Sume#include <pthread.h> 38145857Sume#include <stdio.h> 39145857Sume#include <netdb.h> 40145857Sume#include <stdlib.h> 41145857Sume#include <unistd.h> 42145857Sume#include <err.h> 43145857Sume#include <string.h> 44145857Sume#include <stringlist.h> 45145857Sume 46145857Sume#define NTHREADS 10 47145857Sume#define NHOSTS 100 48145857Sume#define WS " \t\n\r" 49145857Sume 50145860Sumeenum method { 51145860Sume METHOD_GETADDRINFO, 52145860Sume METHOD_GETHOSTBY, 53145860Sume METHOD_GETIPNODEBY 54145860Sume}; 55145860Sume 56145857Sumestatic StringList *hosts = NULL; 57145857Sumestatic int debug = 0; 58145860Sumestatic enum method method = METHOD_GETADDRINFO; 59145860Sumestatic int reverse = 0; 60145857Sumestatic int *ask = NULL; 61145857Sumestatic int *got = NULL; 62145857Sume 63145857Sumestatic void usage(void) __attribute__((__noreturn__)); 64145857Sumestatic void load(const char *); 65145857Sumestatic void resolvone(int); 66145857Sumestatic void *resolvloop(void *); 67145857Sumestatic void run(int *); 68145857Sume 69145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; 70145857Sume 71145857Sumestatic void 72145857Sumeusage(void) 73145857Sume{ 74145857Sume (void)fprintf(stderr, 75145860Sume "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n", 76145857Sume getprogname()); 77145857Sume exit(1); 78145857Sume} 79145857Sume 80145857Sumestatic void 81145857Sumeload(const char *fname) 82145857Sume{ 83145857Sume FILE *fp; 84145857Sume size_t len; 85145857Sume char *line; 86145857Sume 87145857Sume if ((fp = fopen(fname, "r")) == NULL) 88145857Sume err(1, "Cannot open `%s'", fname); 89145857Sume while ((line = fgetln(fp, &len)) != NULL) { 90145857Sume char c = line[len]; 91145857Sume char *ptr; 92145857Sume line[len] = '\0'; 93291761Sngie for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) { 94291761Sngie if (ptr == '\0' || ptr[0] == '#') 95291761Sngie continue; 96145857Sume sl_add(hosts, strdup(ptr)); 97291761Sngie } 98145857Sume line[len] = c; 99145857Sume } 100145857Sume 101145857Sume (void)fclose(fp); 102145857Sume} 103145857Sume 104145860Sumestatic int 105145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port) 106145860Sume{ 107145860Sume char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; 108145860Sume struct addrinfo hints, *res; 109145860Sume int error, len; 110145860Sume 111145860Sume snprintf(portstr, sizeof(portstr), "%d", port); 112145860Sume memset(&hints, 0, sizeof(hints)); 113145860Sume hints.ai_family = AF_UNSPEC; 114145860Sume hints.ai_flags = AI_PASSIVE; 115145860Sume hints.ai_socktype = SOCK_STREAM; 116145860Sume error = getaddrinfo(host, portstr, &hints, &res); 117145860Sume if (debug) { 118145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 119145860Sume self, host, error ? "not found" : "ok"); 120145860Sume (void)write(STDOUT_FILENO, buf, len); 121145860Sume } 122145860Sume if (error == 0 && reverse) { 123145860Sume memset(hbuf, 0, sizeof(hbuf)); 124145860Sume memset(pbuf, 0, sizeof(pbuf)); 125145860Sume getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 126145860Sume pbuf, sizeof(pbuf), 0); 127145860Sume if (debug) { 128145860Sume len = snprintf(buf, sizeof(buf), 129145860Sume "%p: reverse %s %s\n", self, hbuf, pbuf); 130145860Sume (void)write(STDOUT_FILENO, buf, len); 131145860Sume } 132145860Sume } 133145860Sume if (error == 0) 134145860Sume freeaddrinfo(res); 135145860Sume return error; 136145860Sume} 137145860Sume 138145860Sumestatic int 139145860Sumeresolv_gethostby(pthread_t self, char *host) 140145860Sume{ 141145860Sume char buf[1024]; 142145860Sume struct hostent *hp, *hp2; 143145860Sume int len; 144145860Sume 145145860Sume hp = gethostbyname(host); 146145860Sume if (debug) { 147145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 148145860Sume self, host, (hp == NULL) ? "not found" : "ok"); 149145860Sume (void)write(STDOUT_FILENO, buf, len); 150145860Sume } 151145860Sume if (hp && reverse) { 152145860Sume memcpy(buf, hp->h_addr, hp->h_length); 153145860Sume hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype); 154145860Sume if (hp2 && debug) { 155145860Sume len = snprintf(buf, sizeof(buf), 156145860Sume "%p: reverse %s\n", self, hp2->h_name); 157145860Sume (void)write(STDOUT_FILENO, buf, len); 158145860Sume } 159145860Sume } 160145860Sume return hp ? 0 : -1; 161145860Sume} 162145860Sume 163145860Sumestatic int 164145860Sumeresolv_getipnodeby(pthread_t self, char *host) 165145860Sume{ 166145860Sume char buf[1024]; 167145860Sume struct hostent *hp, *hp2; 168145860Sume int len, h_error; 169145860Sume 170145860Sume hp = getipnodebyname(host, AF_INET, 0, &h_error); 171145860Sume if (debug) { 172145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 173145860Sume self, host, (hp == NULL) ? "not found" : "ok"); 174145860Sume (void)write(STDOUT_FILENO, buf, len); 175145860Sume } 176145860Sume if (hp && reverse) { 177145860Sume memcpy(buf, hp->h_addr, hp->h_length); 178145860Sume hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype, 179145860Sume &h_error); 180145860Sume if (hp2 && debug) { 181145860Sume len = snprintf(buf, sizeof(buf), 182145860Sume "%p: reverse %s\n", self, hp2->h_name); 183145860Sume (void)write(STDOUT_FILENO, buf, len); 184145860Sume } 185145860Sume if (hp2) 186145860Sume freehostent(hp2); 187145860Sume } 188145860Sume if (hp) 189145860Sume freehostent(hp); 190145860Sume return hp ? 0 : -1; 191145860Sume} 192145860Sume 193145857Sumestatic void 194145857Sumeresolvone(int n) 195145857Sume{ 196145857Sume char buf[1024]; 197145857Sume pthread_t self = pthread_self(); 198145857Sume size_t i = (random() & 0x0fffffff) % hosts->sl_cur; 199145857Sume char *host = hosts->sl_str[i]; 200145860Sume struct addrinfo hints, *res; 201145857Sume int error, len; 202145860Sume 203145857Sume if (debug) { 204145857Sume len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", 205145857Sume self, n, host, (int)i); 206145857Sume (void)write(STDOUT_FILENO, buf, len); 207145857Sume } 208145860Sume switch (method) { 209145860Sume case METHOD_GETADDRINFO: 210145860Sume error = resolv_getaddrinfo(self, host, i); 211145860Sume break; 212145860Sume case METHOD_GETHOSTBY: 213145860Sume error = resolv_gethostby(self, host); 214145860Sume break; 215145860Sume case METHOD_GETIPNODEBY: 216145860Sume error = resolv_getipnodeby(self, host); 217145860Sume break; 218145860Sume default: 219145860Sume break; 220145857Sume } 221145857Sume pthread_mutex_lock(&stats); 222145857Sume ask[i]++; 223145857Sume got[i] += error == 0; 224145857Sume pthread_mutex_unlock(&stats); 225145857Sume} 226145857Sume 227145857Sumestatic void * 228145857Sumeresolvloop(void *p) 229145857Sume{ 230145857Sume int *nhosts = (int *)p; 231145857Sume if (*nhosts == 0) 232243346Semaste return NULL; 233145857Sume do 234145857Sume resolvone(*nhosts); 235145857Sume while (--(*nhosts)); 236145857Sume return NULL; 237145857Sume} 238145857Sume 239145857Sumestatic void 240145857Sumerun(int *nhosts) 241145857Sume{ 242145857Sume pthread_t self = pthread_self(); 243145857Sume if (pthread_create(&self, NULL, resolvloop, nhosts) != 0) 244145857Sume err(1, "pthread_create"); 245145857Sume} 246145857Sume 247145857Sumeint 248145857Sumemain(int argc, char *argv[]) 249145857Sume{ 250145857Sume int nthreads = NTHREADS; 251145857Sume int nhosts = NHOSTS; 252145857Sume int i, c, done, *nleft; 253145857Sume hosts = sl_init(); 254145857Sume 255145857Sume srandom(1234); 256145857Sume 257145860Sume while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1) 258145857Sume switch (c) { 259145860Sume case 'A': 260145860Sume method = METHOD_GETADDRINFO; 261145860Sume break; 262145857Sume case 'd': 263145857Sume debug++; 264145857Sume break; 265145857Sume case 'h': 266145857Sume nhosts = atoi(optarg); 267145857Sume break; 268145860Sume case 'H': 269145860Sume method = METHOD_GETHOSTBY; 270145860Sume break; 271145860Sume case 'I': 272145860Sume method = METHOD_GETIPNODEBY; 273145860Sume break; 274145857Sume case 'n': 275145857Sume nthreads = atoi(optarg); 276145857Sume break; 277145860Sume case 'r': 278145860Sume reverse++; 279145860Sume break; 280145857Sume default: 281145857Sume usage(); 282145857Sume } 283145857Sume 284145857Sume for (i = optind; i < argc; i++) 285145857Sume load(argv[i]); 286145857Sume 287145857Sume if (hosts->sl_cur == 0) 288145857Sume usage(); 289145857Sume 290145857Sume if ((nleft = malloc(nthreads * sizeof(int))) == NULL) 291145857Sume err(1, "malloc"); 292145857Sume if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL) 293145857Sume err(1, "calloc"); 294145857Sume if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL) 295145857Sume err(1, "calloc"); 296145857Sume 297145857Sume 298145857Sume for (i = 0; i < nthreads; i++) { 299145857Sume nleft[i] = nhosts; 300145857Sume run(&nleft[i]); 301145857Sume } 302145857Sume 303145857Sume for (done = 0; !done;) { 304145857Sume done = 1; 305145857Sume for (i = 0; i < nthreads; i++) { 306145857Sume if (nleft[i] != 0) { 307145857Sume done = 0; 308145857Sume break; 309145857Sume } 310145857Sume } 311145857Sume sleep(1); 312145857Sume } 313145857Sume c = 0; 314145857Sume for (i = 0; i < hosts->sl_cur; i++) { 315145857Sume if (ask[i] != got[i] && got[i] != 0) { 316145857Sume warnx("Error: host %s ask %d got %d\n", 317145857Sume hosts->sl_str[i], ask[i], got[i]); 318145857Sume c++; 319145857Sume } 320145857Sume } 321145857Sume free(nleft); 322145857Sume free(ask); 323145857Sume free(got); 324145857Sume sl_free(hosts, 1); 325145857Sume return c; 326145857Sume} 327