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 <string.h> 43145857Sume#include <stringlist.h> 44145857Sume 45292317Sngie#include <atf-c.h> 46292317Sngie 47145857Sume#define NTHREADS 10 48145857Sume#define NHOSTS 100 49145857Sume#define WS " \t\n\r" 50145857Sume 51145860Sumeenum method { 52145860Sume METHOD_GETADDRINFO, 53145860Sume METHOD_GETHOSTBY, 54145860Sume METHOD_GETIPNODEBY 55145860Sume}; 56145860Sume 57145857Sumestatic StringList *hosts = NULL; 58145860Sumestatic enum method method = METHOD_GETADDRINFO; 59145857Sumestatic int *ask = NULL; 60145857Sumestatic int *got = NULL; 61145857Sume 62145857Sumestatic void load(const char *); 63145857Sumestatic void resolvone(int); 64145857Sumestatic void *resolvloop(void *); 65145857Sumestatic void run(int *); 66145857Sume 67145857Sumestatic pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; 68145857Sume 69145857Sumestatic void 70145857Sumeload(const char *fname) 71145857Sume{ 72145857Sume FILE *fp; 73145857Sume size_t len; 74145857Sume char *line; 75145857Sume 76145857Sume if ((fp = fopen(fname, "r")) == NULL) 77292317Sngie ATF_REQUIRE(fp != NULL); 78145857Sume while ((line = fgetln(fp, &len)) != NULL) { 79145857Sume char c = line[len]; 80145857Sume char *ptr; 81145857Sume line[len] = '\0'; 82291362Sngie for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) { 83291362Sngie if (ptr == '\0' || ptr[0] == '#') 84291362Sngie continue; 85145857Sume sl_add(hosts, strdup(ptr)); 86291362Sngie } 87145857Sume line[len] = c; 88145857Sume } 89145857Sume 90145857Sume (void)fclose(fp); 91145857Sume} 92145857Sume 93145860Sumestatic int 94145860Sumeresolv_getaddrinfo(pthread_t self, char *host, int port) 95145860Sume{ 96145860Sume char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; 97145860Sume struct addrinfo hints, *res; 98145860Sume int error, len; 99145860Sume 100145860Sume snprintf(portstr, sizeof(portstr), "%d", port); 101145860Sume memset(&hints, 0, sizeof(hints)); 102145860Sume hints.ai_family = AF_UNSPEC; 103145860Sume hints.ai_flags = AI_PASSIVE; 104145860Sume hints.ai_socktype = SOCK_STREAM; 105145860Sume error = getaddrinfo(host, portstr, &hints, &res); 106292317Sngie len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 107292317Sngie self, host, error ? "not found" : "ok"); 108292317Sngie (void)write(STDOUT_FILENO, buf, len); 109292317Sngie if (error == 0) { 110145860Sume memset(hbuf, 0, sizeof(hbuf)); 111145860Sume memset(pbuf, 0, sizeof(pbuf)); 112145860Sume getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 113145860Sume pbuf, sizeof(pbuf), 0); 114292317Sngie len = snprintf(buf, sizeof(buf), 115292317Sngie "%p: reverse %s %s\n", self, hbuf, pbuf); 116292317Sngie (void)write(STDOUT_FILENO, buf, len); 117145860Sume } 118145860Sume if (error == 0) 119145860Sume freeaddrinfo(res); 120145860Sume return error; 121145860Sume} 122145860Sume 123145860Sumestatic int 124145860Sumeresolv_gethostby(pthread_t self, char *host) 125145860Sume{ 126145860Sume char buf[1024]; 127145860Sume struct hostent *hp, *hp2; 128145860Sume int len; 129145860Sume 130145860Sume hp = gethostbyname(host); 131292317Sngie len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 132292317Sngie self, host, (hp == NULL) ? "not found" : "ok"); 133292317Sngie (void)write(STDOUT_FILENO, buf, len); 134292317Sngie if (hp) { 135145860Sume memcpy(buf, hp->h_addr, hp->h_length); 136145860Sume hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype); 137292317Sngie if (hp2) { 138145860Sume len = snprintf(buf, sizeof(buf), 139145860Sume "%p: reverse %s\n", self, hp2->h_name); 140145860Sume (void)write(STDOUT_FILENO, buf, len); 141145860Sume } 142145860Sume } 143145860Sume return hp ? 0 : -1; 144145860Sume} 145145860Sume 146145860Sumestatic int 147145860Sumeresolv_getipnodeby(pthread_t self, char *host) 148145860Sume{ 149145860Sume char buf[1024]; 150145860Sume struct hostent *hp, *hp2; 151145860Sume int len, h_error; 152145860Sume 153145860Sume hp = getipnodebyname(host, AF_INET, 0, &h_error); 154292317Sngie len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 155292317Sngie self, host, (hp == NULL) ? "not found" : "ok"); 156292317Sngie (void)write(STDOUT_FILENO, buf, len); 157292317Sngie if (hp) { 158145860Sume memcpy(buf, hp->h_addr, hp->h_length); 159145860Sume hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype, 160145860Sume &h_error); 161292317Sngie if (hp2) { 162145860Sume len = snprintf(buf, sizeof(buf), 163145860Sume "%p: reverse %s\n", self, hp2->h_name); 164145860Sume (void)write(STDOUT_FILENO, buf, len); 165145860Sume } 166145860Sume if (hp2) 167145860Sume freehostent(hp2); 168145860Sume } 169145860Sume if (hp) 170145860Sume freehostent(hp); 171145860Sume return hp ? 0 : -1; 172145860Sume} 173145860Sume 174145857Sumestatic void 175145857Sumeresolvone(int n) 176145857Sume{ 177145857Sume char buf[1024]; 178145857Sume pthread_t self = pthread_self(); 179145857Sume size_t i = (random() & 0x0fffffff) % hosts->sl_cur; 180145857Sume char *host = hosts->sl_str[i]; 181145860Sume struct addrinfo hints, *res; 182145857Sume int error, len; 183145860Sume 184292317Sngie len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", 185292317Sngie self, n, host, (int)i); 186292317Sngie (void)write(STDOUT_FILENO, buf, len); 187145860Sume switch (method) { 188145860Sume case METHOD_GETADDRINFO: 189145860Sume error = resolv_getaddrinfo(self, host, i); 190145860Sume break; 191145860Sume case METHOD_GETHOSTBY: 192145860Sume error = resolv_gethostby(self, host); 193145860Sume break; 194145860Sume case METHOD_GETIPNODEBY: 195145860Sume error = resolv_getipnodeby(self, host); 196145860Sume break; 197145860Sume default: 198145860Sume break; 199145857Sume } 200145857Sume pthread_mutex_lock(&stats); 201145857Sume ask[i]++; 202145857Sume got[i] += error == 0; 203145857Sume pthread_mutex_unlock(&stats); 204145857Sume} 205145857Sume 206145857Sumestatic void * 207145857Sumeresolvloop(void *p) 208145857Sume{ 209145857Sume int *nhosts = (int *)p; 210145857Sume if (*nhosts == 0) 211243346Semaste return NULL; 212145857Sume do 213145857Sume resolvone(*nhosts); 214145857Sume while (--(*nhosts)); 215145857Sume return NULL; 216145857Sume} 217145857Sume 218145857Sumestatic void 219145857Sumerun(int *nhosts) 220145857Sume{ 221292317Sngie pthread_t self; 222292317Sngie int rc; 223292317Sngie 224292317Sngie self = pthread_self(); 225292317Sngie rc = pthread_create(&self, NULL, resolvloop, nhosts); 226292317Sngie ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc)); 227145857Sume} 228145857Sume 229292317Sngiestatic int 230292317Sngierun_tests(const char *hostlist_file, enum method method) 231145857Sume{ 232145857Sume int nthreads = NTHREADS; 233145857Sume int nhosts = NHOSTS; 234145857Sume int i, c, done, *nleft; 235145857Sume hosts = sl_init(); 236145857Sume 237145857Sume srandom(1234); 238145857Sume 239292317Sngie load(hostlist_file); 240145857Sume 241292317Sngie ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file); 242145857Sume 243292317Sngie nleft = malloc(nthreads * sizeof(int)); 244292317Sngie ATF_REQUIRE(nleft != NULL); 245145857Sume 246292317Sngie ask = calloc(hosts->sl_cur, sizeof(int)); 247292317Sngie ATF_REQUIRE(ask != NULL); 248145857Sume 249292317Sngie got = calloc(hosts->sl_cur, sizeof(int)); 250292317Sngie ATF_REQUIRE(got != NULL); 251145857Sume 252145857Sume for (i = 0; i < nthreads; i++) { 253145857Sume nleft[i] = nhosts; 254145857Sume run(&nleft[i]); 255145857Sume } 256145857Sume 257145857Sume for (done = 0; !done;) { 258145857Sume done = 1; 259145857Sume for (i = 0; i < nthreads; i++) { 260145857Sume if (nleft[i] != 0) { 261145857Sume done = 0; 262145857Sume break; 263145857Sume } 264145857Sume } 265145857Sume sleep(1); 266145857Sume } 267145857Sume c = 0; 268145857Sume for (i = 0; i < hosts->sl_cur; i++) { 269145857Sume if (ask[i] != got[i] && got[i] != 0) { 270292317Sngie printf("Error: host %s ask %d got %d\n", 271145857Sume hosts->sl_str[i], ask[i], got[i]); 272145857Sume c++; 273145857Sume } 274145857Sume } 275145857Sume free(nleft); 276145857Sume free(ask); 277145857Sume free(got); 278145857Sume sl_free(hosts, 1); 279145857Sume return c; 280145857Sume} 281292317Sngie 282292317Sngie#define HOSTLIST_FILE "mach" 283292317Sngie 284292317Sngie#define RUN_TESTS(tc, method) \ 285292317Sngiedo { \ 286292317Sngie char *_hostlist_file; \ 287292317Sngie ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ 288292317Sngie atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ 289292317Sngie ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \ 290292317Sngie} while(0) 291292317Sngie 292292665SngieATF_TC(getaddrinfo_test); 293292665SngieATF_TC_HEAD(getaddrinfo_test, tc) { 294304950Sngie atf_tc_set_md_var(tc, "timeout", "1200"); 295292665Sngie} 296292317SngieATF_TC_BODY(getaddrinfo_test, tc) 297292317Sngie{ 298292317Sngie 299292317Sngie RUN_TESTS(tc, METHOD_GETADDRINFO); 300292317Sngie} 301292317Sngie 302292665SngieATF_TC(gethostby_test); 303292665SngieATF_TC_HEAD(gethostby_test, tc) { 304304950Sngie atf_tc_set_md_var(tc, "timeout", "1200"); 305292665Sngie} 306292317SngieATF_TC_BODY(gethostby_test, tc) 307292317Sngie{ 308292317Sngie 309292317Sngie RUN_TESTS(tc, METHOD_GETHOSTBY); 310292317Sngie} 311292317Sngie 312292665SngieATF_TC(getipnodeby_test); 313292665SngieATF_TC_HEAD(getipnodeby_test, tc) { 314292665Sngie 315304950Sngie atf_tc_set_md_var(tc, "timeout", "1200"); 316292665Sngie} 317292317SngieATF_TC_BODY(getipnodeby_test, tc) 318292317Sngie{ 319292317Sngie 320292317Sngie RUN_TESTS(tc, METHOD_GETIPNODEBY); 321292317Sngie} 322292317Sngie 323292317SngieATF_TP_ADD_TCS(tp) 324292317Sngie{ 325292317Sngie 326292317Sngie ATF_TP_ADD_TC(tp, getaddrinfo_test); 327292317Sngie ATF_TP_ADD_TC(tp, gethostby_test); 328292317Sngie ATF_TP_ADD_TC(tp, getipnodeby_test); 329292317Sngie 330292317Sngie return (atf_no_error()); 331292317Sngie} 332