resolv.c revision 145860
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 * 3. All advertising materials mentioning features or use of this software 19145857Sume * must display the following acknowledgement: 20145857Sume * This product includes software developed by the NetBSD 21145857Sume * Foundation, Inc. and its contributors. 22145857Sume * 4. Neither the name of The NetBSD Foundation nor the names of its 23145857Sume * contributors may be used to endorse or promote products derived 24145857Sume * from this software without specific prior written permission. 25145857Sume * 26145857Sume * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27145857Sume * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28145857Sume * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29145857Sume * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30145857Sume * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31145857Sume * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32145857Sume * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33145857Sume * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34145857Sume * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35145857Sume * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36145857Sume * POSSIBILITY OF SUCH DAMAGE. 37145857Sume */ 38145860Sume/* $FreeBSD: head/tools/regression/lib/libc/resolv/resolv.c 145860 2005-05-04 12:02:10Z ume $ */ 39145857Sume#include <sys/cdefs.h> 40145857Sume__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $"); 41145857Sume 42145860Sume#include <sys/types.h> 43145860Sume#include <sys/socket.h> 44145857Sume#include <pthread.h> 45145857Sume#include <stdio.h> 46145857Sume#include <netdb.h> 47145857Sume#include <stdlib.h> 48145857Sume#include <unistd.h> 49145857Sume#include <err.h> 50145857Sume#include <string.h> 51145857Sume#include <stringlist.h> 52145857Sume 53145857Sume#define NTHREADS 10 54145857Sume#define NHOSTS 100 55145857Sume#define WS " \t\n\r" 56145857Sume 57145860Sumeenum method { 58145860Sume METHOD_GETADDRINFO, 59145860Sume METHOD_GETHOSTBY, 60145860Sume METHOD_GETIPNODEBY 61145860Sume}; 62145860Sume 63145857Sumestatic StringList *hosts = NULL; 64145857Sumestatic int debug = 0; 65145860Sumestatic enum method method = METHOD_GETADDRINFO; 66145860Sumestatic int reverse = 0; 67145857Sumestatic int *ask = NULL; 68145857Sumestatic int *got = NULL; 69145857Sume 70145857Sumestatic void usage(void) __attribute__((__noreturn__)); 71145857Sumestatic void load(const char *); 72145857Sumestatic void resolvone(int); 73145857Sumestatic void *resolvloop(void *); 74145857Sumestatic void run(int *); 75145857Sume 76145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; 77145857Sume 78145857Sumestatic void 79145857Sumeusage(void) 80145857Sume{ 81145857Sume (void)fprintf(stderr, 82145860Sume "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n", 83145857Sume getprogname()); 84145857Sume exit(1); 85145857Sume} 86145857Sume 87145857Sumestatic void 88145857Sumeload(const char *fname) 89145857Sume{ 90145857Sume FILE *fp; 91145857Sume size_t len; 92145857Sume char *line; 93145857Sume 94145857Sume if ((fp = fopen(fname, "r")) == NULL) 95145857Sume err(1, "Cannot open `%s'", fname); 96145857Sume while ((line = fgetln(fp, &len)) != NULL) { 97145857Sume char c = line[len]; 98145857Sume char *ptr; 99145857Sume line[len] = '\0'; 100145857Sume for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) 101145857Sume sl_add(hosts, strdup(ptr)); 102145857Sume line[len] = c; 103145857Sume } 104145857Sume 105145857Sume (void)fclose(fp); 106145857Sume} 107145857Sume 108145860Sumestatic int 109145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port) 110145860Sume{ 111145860Sume char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; 112145860Sume struct addrinfo hints, *res; 113145860Sume int error, len; 114145860Sume 115145860Sume snprintf(portstr, sizeof(portstr), "%d", port); 116145860Sume memset(&hints, 0, sizeof(hints)); 117145860Sume hints.ai_family = AF_UNSPEC; 118145860Sume hints.ai_flags = AI_PASSIVE; 119145860Sume hints.ai_socktype = SOCK_STREAM; 120145860Sume error = getaddrinfo(host, portstr, &hints, &res); 121145860Sume if (debug) { 122145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 123145860Sume self, host, error ? "not found" : "ok"); 124145860Sume (void)write(STDOUT_FILENO, buf, len); 125145860Sume } 126145860Sume if (error == 0 && reverse) { 127145860Sume memset(hbuf, 0, sizeof(hbuf)); 128145860Sume memset(pbuf, 0, sizeof(pbuf)); 129145860Sume getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 130145860Sume pbuf, sizeof(pbuf), 0); 131145860Sume if (debug) { 132145860Sume len = snprintf(buf, sizeof(buf), 133145860Sume "%p: reverse %s %s\n", self, hbuf, pbuf); 134145860Sume (void)write(STDOUT_FILENO, buf, len); 135145860Sume } 136145860Sume } 137145860Sume if (error == 0) 138145860Sume freeaddrinfo(res); 139145860Sume return error; 140145860Sume} 141145860Sume 142145860Sumestatic int 143145860Sumeresolv_gethostby(pthread_t self, char *host) 144145860Sume{ 145145860Sume char buf[1024]; 146145860Sume struct hostent *hp, *hp2; 147145860Sume int len; 148145860Sume 149145860Sume hp = gethostbyname(host); 150145860Sume if (debug) { 151145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 152145860Sume self, host, (hp == NULL) ? "not found" : "ok"); 153145860Sume (void)write(STDOUT_FILENO, buf, len); 154145860Sume } 155145860Sume if (hp && reverse) { 156145860Sume memcpy(buf, hp->h_addr, hp->h_length); 157145860Sume hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype); 158145860Sume if (hp2 && debug) { 159145860Sume len = snprintf(buf, sizeof(buf), 160145860Sume "%p: reverse %s\n", self, hp2->h_name); 161145860Sume (void)write(STDOUT_FILENO, buf, len); 162145860Sume } 163145860Sume } 164145860Sume return hp ? 0 : -1; 165145860Sume} 166145860Sume 167145860Sumestatic int 168145860Sumeresolv_getipnodeby(pthread_t self, char *host) 169145860Sume{ 170145860Sume char buf[1024]; 171145860Sume struct hostent *hp, *hp2; 172145860Sume int len, h_error; 173145860Sume 174145860Sume hp = getipnodebyname(host, AF_INET, 0, &h_error); 175145860Sume if (debug) { 176145860Sume len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 177145860Sume self, host, (hp == NULL) ? "not found" : "ok"); 178145860Sume (void)write(STDOUT_FILENO, buf, len); 179145860Sume } 180145860Sume if (hp && reverse) { 181145860Sume memcpy(buf, hp->h_addr, hp->h_length); 182145860Sume hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype, 183145860Sume &h_error); 184145860Sume if (hp2 && debug) { 185145860Sume len = snprintf(buf, sizeof(buf), 186145860Sume "%p: reverse %s\n", self, hp2->h_name); 187145860Sume (void)write(STDOUT_FILENO, buf, len); 188145860Sume } 189145860Sume if (hp2) 190145860Sume freehostent(hp2); 191145860Sume } 192145860Sume if (hp) 193145860Sume freehostent(hp); 194145860Sume return hp ? 0 : -1; 195145860Sume} 196145860Sume 197145857Sumestatic void 198145857Sumeresolvone(int n) 199145857Sume{ 200145857Sume char buf[1024]; 201145857Sume pthread_t self = pthread_self(); 202145857Sume size_t i = (random() & 0x0fffffff) % hosts->sl_cur; 203145857Sume char *host = hosts->sl_str[i]; 204145860Sume struct addrinfo hints, *res; 205145857Sume int error, len; 206145860Sume 207145857Sume if (debug) { 208145857Sume len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", 209145857Sume self, n, host, (int)i); 210145857Sume (void)write(STDOUT_FILENO, buf, len); 211145857Sume } 212145860Sume switch (method) { 213145860Sume case METHOD_GETADDRINFO: 214145860Sume error = resolv_getaddrinfo(self, host, i); 215145860Sume break; 216145860Sume case METHOD_GETHOSTBY: 217145860Sume error = resolv_gethostby(self, host); 218145860Sume break; 219145860Sume case METHOD_GETIPNODEBY: 220145860Sume error = resolv_getipnodeby(self, host); 221145860Sume break; 222145860Sume default: 223145860Sume break; 224145857Sume } 225145857Sume pthread_mutex_lock(&stats); 226145857Sume ask[i]++; 227145857Sume got[i] += error == 0; 228145857Sume pthread_mutex_unlock(&stats); 229145857Sume} 230145857Sume 231145857Sumestatic void * 232145857Sumeresolvloop(void *p) 233145857Sume{ 234145857Sume int *nhosts = (int *)p; 235145857Sume if (*nhosts == 0) 236145857Sume return; 237145857Sume do 238145857Sume resolvone(*nhosts); 239145857Sume while (--(*nhosts)); 240145857Sume return NULL; 241145857Sume} 242145857Sume 243145857Sumestatic void 244145857Sumerun(int *nhosts) 245145857Sume{ 246145857Sume pthread_t self = pthread_self(); 247145857Sume if (pthread_create(&self, NULL, resolvloop, nhosts) != 0) 248145857Sume err(1, "pthread_create"); 249145857Sume} 250145857Sume 251145857Sumeint 252145857Sumemain(int argc, char *argv[]) 253145857Sume{ 254145857Sume int nthreads = NTHREADS; 255145857Sume int nhosts = NHOSTS; 256145857Sume int i, c, done, *nleft; 257145857Sume hosts = sl_init(); 258145857Sume 259145857Sume srandom(1234); 260145857Sume 261145860Sume while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1) 262145857Sume switch (c) { 263145860Sume case 'A': 264145860Sume method = METHOD_GETADDRINFO; 265145860Sume break; 266145857Sume case 'd': 267145857Sume debug++; 268145857Sume break; 269145857Sume case 'h': 270145857Sume nhosts = atoi(optarg); 271145857Sume break; 272145860Sume case 'H': 273145860Sume method = METHOD_GETHOSTBY; 274145860Sume break; 275145860Sume case 'I': 276145860Sume method = METHOD_GETIPNODEBY; 277145860Sume break; 278145857Sume case 'n': 279145857Sume nthreads = atoi(optarg); 280145857Sume break; 281145860Sume case 'r': 282145860Sume reverse++; 283145860Sume break; 284145857Sume default: 285145857Sume usage(); 286145857Sume } 287145857Sume 288145857Sume for (i = optind; i < argc; i++) 289145857Sume load(argv[i]); 290145857Sume 291145857Sume if (hosts->sl_cur == 0) 292145857Sume usage(); 293145857Sume 294145857Sume if ((nleft = malloc(nthreads * sizeof(int))) == NULL) 295145857Sume err(1, "malloc"); 296145857Sume if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL) 297145857Sume err(1, "calloc"); 298145857Sume if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL) 299145857Sume err(1, "calloc"); 300145857Sume 301145857Sume 302145857Sume for (i = 0; i < nthreads; i++) { 303145857Sume nleft[i] = nhosts; 304145857Sume run(&nleft[i]); 305145857Sume } 306145857Sume 307145857Sume for (done = 0; !done;) { 308145857Sume done = 1; 309145857Sume for (i = 0; i < nthreads; i++) { 310145857Sume if (nleft[i] != 0) { 311145857Sume done = 0; 312145857Sume break; 313145857Sume } 314145857Sume } 315145857Sume sleep(1); 316145857Sume } 317145857Sume c = 0; 318145857Sume for (i = 0; i < hosts->sl_cur; i++) { 319145857Sume if (ask[i] != got[i] && got[i] != 0) { 320145857Sume warnx("Error: host %s ask %d got %d\n", 321145857Sume hosts->sl_str[i], ask[i], got[i]); 322145857Sume c++; 323145857Sume } 324145857Sume } 325145857Sume free(nleft); 326145857Sume free(ask); 327145857Sume free(got); 328145857Sume sl_free(hosts, 1); 329145857Sume return c; 330145857Sume} 331