Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/resolv/resolv_test.c
39530 views
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
#include <sys/cdefs.h>
32
__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
33
34
#include <sys/types.h>
35
#include <sys/socket.h>
36
#include <assert.h>
37
#include <errno.h>
38
#include <pthread.h>
39
#include <stdio.h>
40
#include <stdatomic.h>
41
#include <netdb.h>
42
#include <stdlib.h>
43
#include <unistd.h>
44
#include <string.h>
45
#include <stringlist.h>
46
47
#include <atf-c.h>
48
49
#define NTHREADS 10
50
#define NHOSTS 100
51
#define WS " \t\n\r"
52
53
enum method {
54
METHOD_GETADDRINFO,
55
METHOD_GETHOSTBY,
56
METHOD_GETIPNODEBY
57
};
58
59
static StringList *hosts = NULL;
60
static _Atomic(int) *ask = NULL;
61
static _Atomic(int) *got = NULL;
62
static bool debug_output = 0;
63
64
static void load(const char *);
65
static void resolvone(long, int, enum method);
66
static void *resolvloop(void *);
67
static pthread_t run(int, enum method, long);
68
69
#define DBG(...) do { \
70
if (debug_output) \
71
dprintf(STDOUT_FILENO, __VA_ARGS__); \
72
} while (0)
73
74
static void
75
load(const char *fname)
76
{
77
FILE *fp;
78
size_t linecap;
79
char *line;
80
81
fp = fopen(fname, "r");
82
ATF_REQUIRE(fp != NULL);
83
line = NULL;
84
linecap = 0;
85
while (getline(&line, &linecap, fp) >= 0) {
86
char *ptr;
87
88
for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) {
89
if (ptr[0] == '#')
90
break;
91
sl_add(hosts, strdup(ptr));
92
}
93
}
94
free(line);
95
96
(void)fclose(fp);
97
}
98
99
static int
100
resolv_getaddrinfo(long threadnum, char *host, int port, const char **errstr)
101
{
102
char portstr[6], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
103
struct addrinfo hints, *res;
104
int error;
105
106
snprintf(portstr, sizeof(portstr), "%d", port);
107
memset(&hints, 0, sizeof(hints));
108
hints.ai_family = AF_UNSPEC;
109
hints.ai_flags = AI_PASSIVE;
110
hints.ai_socktype = SOCK_STREAM;
111
error = getaddrinfo(host, portstr, &hints, &res);
112
if (error == 0) {
113
DBG("T%ld: host %s ok\n", threadnum, host);
114
memset(hbuf, 0, sizeof(hbuf));
115
memset(pbuf, 0, sizeof(pbuf));
116
getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
117
pbuf, sizeof(pbuf), 0);
118
DBG("T%ld: reverse %s %s\n", threadnum, hbuf, pbuf);
119
freeaddrinfo(res);
120
} else {
121
*errstr = gai_strerror(error);
122
DBG("T%ld: host %s not found: %s\n", threadnum, host, *errstr);
123
}
124
return error;
125
}
126
127
static int
128
resolv_gethostby(long threadnum, char *host, const char **errstr)
129
{
130
char buf[1024];
131
struct hostent *hp, *hp2;
132
133
hp = gethostbyname(host);
134
if (hp) {
135
DBG("T%ld: host %s ok\n", threadnum, host);
136
memcpy(buf, hp->h_addr, hp->h_length);
137
hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
138
if (hp2) {
139
DBG("T%ld: reverse %s\n", threadnum, hp2->h_name);
140
}
141
} else {
142
*errstr = hstrerror(h_errno);
143
DBG("T%ld: host %s not found: %s\n", threadnum, host, *errstr);
144
}
145
return hp ? 0 : h_errno;
146
}
147
148
static int
149
resolv_getipnodeby(long threadnum, char *host, const char **errstr)
150
{
151
char buf[1024];
152
struct hostent *hp, *hp2;
153
int error = 0;
154
155
hp = getipnodebyname(host, AF_INET, 0, &error);
156
if (hp) {
157
DBG("T%ld: host %s ok\n", threadnum, host);
158
memcpy(buf, hp->h_addr, hp->h_length);
159
hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
160
&error);
161
if (hp2) {
162
DBG("T%ld: reverse %s\n", threadnum, hp2->h_name);
163
freehostent(hp2);
164
}
165
freehostent(hp);
166
} else {
167
*errstr = hstrerror(error);
168
DBG("T%ld: host %s not found: %s\n", threadnum, host, *errstr);
169
}
170
return hp ? 0 : error;
171
}
172
173
static void
174
resolvone(long threadnum, int n, enum method method)
175
{
176
const char* errstr = NULL;
177
size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
178
char *host = hosts->sl_str[i];
179
int error;
180
181
DBG("T%ld: %d resolving %s %zd\n", threadnum, n, host, i);
182
switch (method) {
183
case METHOD_GETADDRINFO:
184
error = resolv_getaddrinfo(threadnum, host, i, &errstr);
185
break;
186
case METHOD_GETHOSTBY:
187
error = resolv_gethostby(threadnum, host, &errstr);
188
break;
189
case METHOD_GETIPNODEBY:
190
error = resolv_getipnodeby(threadnum, host, &errstr);
191
break;
192
default:
193
/* UNREACHABLE */
194
/* XXX Needs an __assert_unreachable() for userland. */
195
assert(0 && "Unreachable segment reached");
196
abort();
197
break;
198
}
199
atomic_fetch_add_explicit(&ask[i], 1, memory_order_relaxed);
200
if (error == 0)
201
atomic_fetch_add_explicit(&got[i], 1, memory_order_relaxed);
202
else if (got[i] != 0)
203
fprintf(stderr,
204
"T%ld ERROR after previous success for %s: %d (%s)\n",
205
threadnum, hosts->sl_str[i], error, errstr);
206
}
207
208
struct resolvloop_args {
209
int nhosts;
210
enum method method;
211
long threadnum;
212
};
213
214
static void *
215
resolvloop(void *p)
216
{
217
struct resolvloop_args *args = p;
218
int nhosts = args->nhosts;
219
220
if (nhosts == 0) {
221
free(args);
222
return NULL;
223
}
224
225
do {
226
resolvone(args->threadnum, nhosts, args->method);
227
} while (--nhosts);
228
free(args);
229
return (void *)(uintptr_t)nhosts;
230
}
231
232
static pthread_t
233
run(int nhosts, enum method method, long i)
234
{
235
pthread_t t;
236
int rc;
237
struct resolvloop_args *args;
238
239
/* Created thread is responsible for free(). */
240
args = malloc(sizeof(*args));
241
ATF_REQUIRE(args != NULL);
242
243
args->nhosts = nhosts;
244
args->method = method;
245
args->threadnum = i + 1;
246
rc = pthread_create(&t, NULL, resolvloop, args);
247
ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc));
248
return t;
249
}
250
251
static int
252
run_tests(const char *hostlist_file, enum method method)
253
{
254
size_t nthreads = NTHREADS;
255
pthread_t *threads;
256
size_t nhosts = NHOSTS;
257
size_t i;
258
int c;
259
hosts = sl_init();
260
261
srandom(1234);
262
debug_output = getenv("DEBUG_OUTPUT") != NULL;
263
264
load(hostlist_file);
265
266
ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file);
267
268
ask = calloc(hosts->sl_cur, sizeof(int));
269
ATF_REQUIRE(ask != NULL);
270
271
got = calloc(hosts->sl_cur, sizeof(int));
272
ATF_REQUIRE(got != NULL);
273
274
threads = calloc(nthreads, sizeof(pthread_t));
275
ATF_REQUIRE(threads != NULL);
276
277
for (i = 0; i < nthreads; i++) {
278
threads[i] = run(nhosts, method, i);
279
}
280
/* Wait for all threads to join and check that they checked all hosts */
281
for (i = 0; i < nthreads; i++) {
282
size_t remaining;
283
284
remaining = (uintptr_t)pthread_join(threads[i], NULL);
285
ATF_CHECK_EQ_MSG(0, remaining,
286
"Thread %zd still had %zd hosts to check!", i, remaining);
287
}
288
289
c = 0;
290
for (i = 0; i < hosts->sl_cur; i++) {
291
if (got[i] != 0) {
292
ATF_CHECK_EQ_MSG(ask[i], got[i],
293
"Error: host %s ask %d got %d", hosts->sl_str[i],
294
ask[i], got[i]);
295
c += ask[i] != got[i];
296
}
297
}
298
free(threads);
299
free(ask);
300
free(got);
301
sl_free(hosts, 1);
302
return c;
303
}
304
305
#define HOSTLIST_FILE "mach"
306
307
#define RUN_TESTS(tc, method) \
308
do { \
309
char *_hostlist_file; \
310
ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
311
atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
312
ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \
313
} while(0)
314
315
ATF_TC(getaddrinfo_test);
316
ATF_TC_HEAD(getaddrinfo_test, tc) {
317
atf_tc_set_md_var(tc, "timeout", "1200");
318
}
319
ATF_TC_BODY(getaddrinfo_test, tc)
320
{
321
322
RUN_TESTS(tc, METHOD_GETADDRINFO);
323
}
324
325
ATF_TC(gethostby_test);
326
ATF_TC_HEAD(gethostby_test, tc) {
327
atf_tc_set_md_var(tc, "timeout", "1200");
328
}
329
ATF_TC_BODY(gethostby_test, tc)
330
{
331
332
RUN_TESTS(tc, METHOD_GETHOSTBY);
333
}
334
335
ATF_TC(getipnodeby_test);
336
ATF_TC_HEAD(getipnodeby_test, tc) {
337
338
atf_tc_set_md_var(tc, "timeout", "1200");
339
}
340
ATF_TC_BODY(getipnodeby_test, tc)
341
{
342
343
RUN_TESTS(tc, METHOD_GETIPNODEBY);
344
}
345
346
ATF_TP_ADD_TCS(tp)
347
{
348
349
ATF_TP_ADD_TC(tp, getaddrinfo_test);
350
ATF_TP_ADD_TC(tp, gethostby_test);
351
ATF_TP_ADD_TC(tp, getipnodeby_test);
352
353
return (atf_no_error());
354
}
355
356