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$ */ 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 <string.h> 43 #include <stringlist.h> 44 45 #include <atf-c.h> 46 47 #define NTHREADS 10 48 #define NHOSTS 100 49 #define WS " \t\n\r" 50 51 enum method { 52 METHOD_GETADDRINFO, 53 METHOD_GETHOSTBY, 54 METHOD_GETIPNODEBY 55 }; 56 57 static StringList *hosts = NULL; 58 static enum method method = METHOD_GETADDRINFO; 59 static int *ask = NULL; 60 static int *got = NULL; 61 62 static void load(const char *); 63 static void resolvone(int); 64 static void *resolvloop(void *); 65 static void run(int *); 66 67 static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; 68 69 static void 70 load(const char *fname) 71 { 72 FILE *fp; 73 size_t len; 74 char *line; 75 76 if ((fp = fopen(fname, "r")) == NULL) 77 ATF_REQUIRE(fp != NULL); 78 while ((line = fgetln(fp, &len)) != NULL) { 79 char c = line[len]; 80 char *ptr; 81 line[len] = '\0'; 82 for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) { 83 if (ptr == '\0' || ptr[0] == '#') 84 continue; 85 sl_add(hosts, strdup(ptr)); 86 } 87 line[len] = c; 88 } 89 90 (void)fclose(fp); 91 } 92 93 static int 94 resolv_getaddrinfo(pthread_t self, char *host, int port) 95 { 96 char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; 97 struct addrinfo hints, *res; 98 int error, len; 99 100 snprintf(portstr, sizeof(portstr), "%d", port); 101 memset(&hints, 0, sizeof(hints)); 102 hints.ai_family = AF_UNSPEC; 103 hints.ai_flags = AI_PASSIVE; 104 hints.ai_socktype = SOCK_STREAM; 105 error = getaddrinfo(host, portstr, &hints, &res); 106 len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 107 self, host, error ? "not found" : "ok"); 108 (void)write(STDOUT_FILENO, buf, len); 109 if (error == 0) { 110 memset(hbuf, 0, sizeof(hbuf)); 111 memset(pbuf, 0, sizeof(pbuf)); 112 getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 113 pbuf, sizeof(pbuf), 0); 114 len = snprintf(buf, sizeof(buf), 115 "%p: reverse %s %s\n", self, hbuf, pbuf); 116 (void)write(STDOUT_FILENO, buf, len); 117 } 118 if (error == 0) 119 freeaddrinfo(res); 120 return error; 121 } 122 123 static int 124 resolv_gethostby(pthread_t self, char *host) 125 { 126 char buf[1024]; 127 struct hostent *hp, *hp2; 128 int len; 129 130 hp = gethostbyname(host); 131 len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 132 self, host, (hp == NULL) ? "not found" : "ok"); 133 (void)write(STDOUT_FILENO, buf, len); 134 if (hp) { 135 memcpy(buf, hp->h_addr, hp->h_length); 136 hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype); 137 if (hp2) { 138 len = snprintf(buf, sizeof(buf), 139 "%p: reverse %s\n", self, hp2->h_name); 140 (void)write(STDOUT_FILENO, buf, len); 141 } 142 } 143 return hp ? 0 : -1; 144 } 145 146 static int 147 resolv_getipnodeby(pthread_t self, char *host) 148 { 149 char buf[1024]; 150 struct hostent *hp, *hp2; 151 int len, h_error; 152 153 hp = getipnodebyname(host, AF_INET, 0, &h_error); 154 len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", 155 self, host, (hp == NULL) ? "not found" : "ok"); 156 (void)write(STDOUT_FILENO, buf, len); 157 if (hp) { 158 memcpy(buf, hp->h_addr, hp->h_length); 159 hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype, 160 &h_error); 161 if (hp2) { 162 len = snprintf(buf, sizeof(buf), 163 "%p: reverse %s\n", self, hp2->h_name); 164 (void)write(STDOUT_FILENO, buf, len); 165 } 166 if (hp2) 167 freehostent(hp2); 168 } 169 if (hp) 170 freehostent(hp); 171 return hp ? 0 : -1; 172 } 173 174 static void 175 resolvone(int n) 176 { 177 char buf[1024]; 178 pthread_t self = pthread_self(); 179 size_t i = (random() & 0x0fffffff) % hosts->sl_cur; 180 char *host = hosts->sl_str[i]; 181 struct addrinfo hints, *res; 182 int error, len; 183 184 len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", 185 self, n, host, (int)i); 186 (void)write(STDOUT_FILENO, buf, len); 187 switch (method) { 188 case METHOD_GETADDRINFO: 189 error = resolv_getaddrinfo(self, host, i); 190 break; 191 case METHOD_GETHOSTBY: 192 error = resolv_gethostby(self, host); 193 break; 194 case METHOD_GETIPNODEBY: 195 error = resolv_getipnodeby(self, host); 196 break; 197 default: 198 break; 199 } 200 pthread_mutex_lock(&stats); 201 ask[i]++; 202 got[i] += error == 0; 203 pthread_mutex_unlock(&stats); 204 } 205 206 static void * 207 resolvloop(void *p) 208 { 209 int *nhosts = (int *)p; 210 if (*nhosts == 0) 211 return NULL; 212 do 213 resolvone(*nhosts); 214 while (--(*nhosts)); 215 return NULL; 216 } 217 218 static void 219 run(int *nhosts) 220 { 221 pthread_t self; 222 int rc; 223 224 self = pthread_self(); 225 rc = pthread_create(&self, NULL, resolvloop, nhosts); 226 ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc)); 227 } 228 229 static int 230 run_tests(const char *hostlist_file, enum method method) 231 { 232 int nthreads = NTHREADS; 233 int nhosts = NHOSTS; 234 int i, c, done, *nleft; 235 hosts = sl_init(); 236 237 srandom(1234); 238 239 load(hostlist_file); 240 241 ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file); 242 243 nleft = malloc(nthreads * sizeof(int)); 244 ATF_REQUIRE(nleft != NULL); 245 246 ask = calloc(hosts->sl_cur, sizeof(int)); 247 ATF_REQUIRE(ask != NULL); 248 249 got = calloc(hosts->sl_cur, sizeof(int)); 250 ATF_REQUIRE(got != NULL); 251 252 for (i = 0; i < nthreads; i++) { 253 nleft[i] = nhosts; 254 run(&nleft[i]); 255 } 256 257 for (done = 0; !done;) { 258 done = 1; 259 for (i = 0; i < nthreads; i++) { 260 if (nleft[i] != 0) { 261 done = 0; 262 break; 263 } 264 } 265 sleep(1); 266 } 267 c = 0; 268 for (i = 0; i < hosts->sl_cur; i++) { 269 if (ask[i] != got[i] && got[i] != 0) { 270 printf("Error: host %s ask %d got %d\n", 271 hosts->sl_str[i], ask[i], got[i]); 272 c++; 273 } 274 } 275 free(nleft); 276 free(ask); 277 free(got); 278 sl_free(hosts, 1); 279 return c; 280 } 281 282 #define HOSTLIST_FILE "mach" 283 284 #define RUN_TESTS(tc, method) \ 285 do { \ 286 char *_hostlist_file; \ 287 ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ 288 atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ 289 ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \ 290 } while(0) 291 292 ATF_TC(getaddrinfo_test); 293 ATF_TC_HEAD(getaddrinfo_test, tc) { 294 atf_tc_set_md_var(tc, "timeout", "1200"); 295 } 296 ATF_TC_BODY(getaddrinfo_test, tc) 297 { 298 299 RUN_TESTS(tc, METHOD_GETADDRINFO); 300 } 301 302 ATF_TC(gethostby_test); 303 ATF_TC_HEAD(gethostby_test, tc) { 304 atf_tc_set_md_var(tc, "timeout", "1200"); 305 } 306 ATF_TC_BODY(gethostby_test, tc) 307 { 308 309 RUN_TESTS(tc, METHOD_GETHOSTBY); 310 } 311 312 ATF_TC(getipnodeby_test); 313 ATF_TC_HEAD(getipnodeby_test, tc) { 314 315 atf_tc_set_md_var(tc, "timeout", "1200"); 316 } 317 ATF_TC_BODY(getipnodeby_test, tc) 318 { 319 320 RUN_TESTS(tc, METHOD_GETIPNODEBY); 321 } 322 323 ATF_TP_ADD_TCS(tp) 324 { 325 326 ATF_TP_ADD_TC(tp, getaddrinfo_test); 327 ATF_TP_ADD_TC(tp, gethostby_test); 328 ATF_TP_ADD_TC(tp, getipnodeby_test); 329 330 return (atf_no_error()); 331 } 332