worldstone: add -s for statistical profiling
[minix.git] / test / test48.c
bloba1af20b786a8bb4aeb1328cb6451d46e53466c8f
1 #include <arpa/inet.h>
2 #include <assert.h>
3 #include <netdb.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
9 #define MAX_ERROR 3
10 #define err() e(__LINE__)
11 #include "common.c"
13 static void printstr(const char *s)
15 if (s)
16 printf("\"%s\"", s);
17 else
18 printf("NULL");
21 static void test_getaddrinfo_err(
22 int n,
23 const char *nodename,
24 const char *servname,
25 int passhints,
26 int flags,
27 int family,
28 int socktype,
29 const char *exp_result,
30 const char *result)
32 printf("error %d: getaddrinfo(", n);
33 printstr(nodename);
34 printf(", ");
35 printstr(servname);
36 printf(", ");
37 if (passhints)
38 printf("{ 0x%x, %d, %d }", flags, family, socktype);
39 else
40 printf("NULL");
42 printf("); result: ");
43 printstr(result);
44 printf("; expected: ");
45 printstr(exp_result);
46 printf("\n");
47 err();
50 /* yes, this is ugly, but not as ugly as repeating it all every time */
51 #define TEST_GETADDRINFO_ERR_PARAMS \
52 nodename, servname, passhints, flags, family, socktype
54 static void test_getaddrinfo_err_nr(
55 int n,
56 const char *nodename,
57 const char *servname,
58 int passhints,
59 int flags,
60 int family,
61 int socktype,
62 int exp_result,
63 int result)
65 char exp_result_s[23], result_s[23];
67 /* convert result to string */
68 snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
69 exp_result, exp_result);
70 snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
71 test_getaddrinfo_err(n, TEST_GETADDRINFO_ERR_PARAMS,
72 exp_result_s, result_s);
75 static void test_getnameinfo_err(
76 int n,
77 unsigned long ipaddr,
78 unsigned short port,
79 socklen_t nodelen,
80 socklen_t servicelen,
81 int flags,
82 const char *exp_result,
83 const char *result)
85 printf("error %d: getnameinfo(0x%.8x, %d, %d, %d, 0x%x); result: ",
86 n, ntohl(ipaddr), ntohs(port), nodelen, servicelen, flags);
87 printstr(result);
88 printf("; expected: ");
89 printstr(exp_result);
90 printf("\n");
91 err();
94 /* yes, this is ugly, but not as ugly as repeating it all every time */
95 #define TEST_GETNAMEINFO_ERR_PARAMS ipaddr, port, nodelen, servicelen, flags
97 static void test_getnameinfo_err_nr(
98 int n,
99 unsigned long ipaddr,
100 unsigned short port,
101 socklen_t nodelen,
102 socklen_t servicelen,
103 int flags,
104 int exp_result,
105 int result)
107 char exp_result_s[23], result_s[23];
109 /* convert result to string */
110 snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
111 exp_result, exp_result);
112 snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
113 test_getnameinfo_err(n, TEST_GETNAMEINFO_ERR_PARAMS,
114 exp_result_s, result_s);
117 static void test_getaddrinfo(
118 const char *nodename,
119 int nodename_numerical,
120 const char *servname,
121 int servname_numerical,
122 int passhints,
123 int flags,
124 int family,
125 int socktype,
126 int exp_results,
127 unsigned long exp_ip,
128 int exp_canonname,
129 unsigned short exp_port)
131 struct addrinfo *ai, *ai_cur;
132 struct addrinfo hints;
133 struct sockaddr_in *sockaddr_in;
134 int ai_count_dgram, ai_count_stream, r;
136 /* some parameters are only meaningful with hints */
137 assert(passhints || !flags);
138 assert(passhints || family == AF_UNSPEC);
139 assert(passhints || !socktype);
141 /* a combination of parameters don't make sense to test */
142 if (nodename == NULL && servname == NULL) return;
143 if (nodename == NULL && (flags & AI_NUMERICHOST)) return;
144 if (servname == NULL && (flags & AI_NUMERICSERV)) return;
146 /* initialize hints */
147 memset(&hints, 0, sizeof(hints));
148 hints.ai_flags = flags;
149 hints.ai_family = family;
150 hints.ai_socktype = socktype;
152 /* perform query and test result */
153 ai = (struct addrinfo *) 0xDEADBEEF;
154 r = getaddrinfo(nodename, servname, passhints ? &hints : NULL, &ai);
155 if (r < 0 || r >= 32 || !((1 << r) & exp_results))
156 test_getaddrinfo_err_nr(1, TEST_GETADDRINFO_ERR_PARAMS, exp_results, r);
158 if (r)
159 return;
161 /* the function succeeded; do the results make sense? */
162 ai_cur = ai;
163 ai_count_dgram = 0;
164 ai_count_stream = 0;
165 while (ai_cur)
167 /* test result fields */
168 if (ai_cur->ai_family != AF_INET)
169 test_getaddrinfo_err_nr(2, TEST_GETADDRINFO_ERR_PARAMS,
170 AF_INET, ai_cur->ai_family);
172 if (socktype && ai_cur->ai_socktype != socktype)
173 test_getaddrinfo_err_nr(3, TEST_GETADDRINFO_ERR_PARAMS,
174 socktype, ai_cur->ai_socktype);
176 switch (ai_cur->ai_socktype)
178 case SOCK_DGRAM: ai_count_dgram++; break;
179 case SOCK_STREAM: ai_count_stream++; break;
182 /* do address and port match? */
183 if (ai_cur->ai_addrlen != sizeof(struct sockaddr_in))
184 test_getaddrinfo_err_nr(4, TEST_GETADDRINFO_ERR_PARAMS,
185 sizeof(struct sockaddr_in),
186 ai_cur->ai_addrlen);
187 else
189 sockaddr_in = (struct sockaddr_in *) ai_cur->ai_addr;
190 if (sockaddr_in->sin_addr.s_addr != exp_ip)
191 test_getaddrinfo_err_nr(5,
192 TEST_GETADDRINFO_ERR_PARAMS,
193 ntohl(exp_ip),
194 ntohl(sockaddr_in->sin_addr.s_addr));
196 if (sockaddr_in->sin_port != exp_port)
197 test_getaddrinfo_err_nr(6,
198 TEST_GETADDRINFO_ERR_PARAMS,
199 ntohs(exp_port),
200 ntohs(sockaddr_in->sin_port));
203 /* If a hostname is numeric, there can't be a canonical name.
204 * Instead, the returned canonname (if requested) will be
205 * identical to the supplied hostname */
206 if (nodename != NULL && nodename_numerical &&
207 (flags & AI_CANONNAME)) {
208 if (strncmp(ai_cur->ai_canonname, nodename,
209 strlen(nodename)))
210 test_getaddrinfo_err(11,
211 TEST_GETADDRINFO_ERR_PARAMS,
212 nodename, ai_cur->ai_canonname);
213 } else {
214 /* is canonical supplied? */
215 if (exp_canonname && nodename &&
216 (!ai_cur->ai_canonname || !*ai_cur->ai_canonname))
217 test_getaddrinfo_err(7,
218 TEST_GETADDRINFO_ERR_PARAMS,
219 "(anything)", ai_cur->ai_canonname);
221 if (!exp_canonname && ai_cur->ai_canonname)
222 test_getaddrinfo_err(8,
223 TEST_GETADDRINFO_ERR_PARAMS,
224 NULL, ai_cur->ai_canonname);
227 /* move to next result */
228 ai_cur = ai_cur->ai_next;
231 /* If socket type is non-zero, make sure we got what we wanted. Else
232 * any result is okay. */
233 if (socktype) {
234 if (ai_count_dgram != ((socktype == SOCK_STREAM) ? 0 : 1))
235 test_getaddrinfo_err_nr(9, TEST_GETADDRINFO_ERR_PARAMS,
236 (socktype == SOCK_STREAM) ? 0 : 1, ai_count_dgram);
238 if (ai_count_stream != ((socktype == SOCK_DGRAM) ? 0 : 1))
239 test_getaddrinfo_err_nr(10, TEST_GETADDRINFO_ERR_PARAMS,
240 (socktype == SOCK_DGRAM) ? 0 : 1, ai_count_stream);
243 /* clean up */
244 freeaddrinfo(ai);
247 static void memsetl(void *s, unsigned long c, size_t n)
249 unsigned char *p = (unsigned char *) s;
250 size_t i;
252 for (i = 0; i < n; i++)
253 p[i] = c >> (8 * (i % sizeof(c)));
256 void test_getnameinfo(
257 unsigned long ipaddr,
258 unsigned short port,
259 const char *exp_node,
260 socklen_t nodelen,
261 const char *exp_service,
262 socklen_t servicelen,
263 int flags,
264 int exp_results)
266 struct sockaddr_in sockaddr;
267 char node[256], service[256];
268 int r;
270 /* avoid buffer overflows */
271 assert(nodelen <= sizeof(node));
272 assert(servicelen <= sizeof(service));
274 /* perform query and test result */
275 sockaddr.sin_family = AF_INET;
276 sockaddr.sin_addr.s_addr = ipaddr;
277 sockaddr.sin_port = port;
278 memsetl(node, 0xDEADBEEF, nodelen);
279 memsetl(service, 0xDEADBEEF, servicelen);
280 r = getnameinfo((struct sockaddr *) &sockaddr, sizeof(sockaddr),
281 node, nodelen, service, servicelen, flags);
283 if (r < 0 || r >= 32 || !((1 << r) & exp_results))
284 test_getnameinfo_err_nr(1, TEST_GETNAMEINFO_ERR_PARAMS,
285 exp_results, r);
287 if (r)
288 return;
290 /* check results */
291 if (nodelen && strcmp(exp_node, node) != 0)
292 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
293 exp_node, node);
295 if (servicelen && strcmp(exp_service, service) != 0)
296 test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
297 exp_service, service);
300 static struct
302 const char *nodename;
303 unsigned long ipaddr;
304 int numeric;
305 int canonname;
306 int need_network;
307 int exp_result;
308 } hosts[] = {
309 { NULL, 0x7f000001, 1, 1, 0, 0 },
310 { "0.0.0.0", 0x00000000, 1, 0, 0, 0 },
311 { "0.0.0.255", 0x000000ff, 1, 0, 0, 0 },
312 { "0.0.255.0", 0x0000ff00, 1, 0, 0, 0 },
313 { "0.255.0.0", 0x00ff0000, 1, 0, 0, 0 },
314 { "255.0.0.0", 0xff000000, 1, 0, 0, 0 },
315 { "127.0.0.1", 0x7f000001, 1, 0, 0, 0 },
316 { "localhost", 0x7f000001, 0, 1, 0, 0, },
317 { "static.minix3.org", 0xC023C00A, 0, 1, 1, 0, },
318 { "", 0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)},
319 { "256.256.256.256",0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)},
320 { "minix3.xyz", 0x00000000, 0, 0, 1, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}};
322 static struct
324 const char *servname;
325 unsigned short port;
326 int numeric;
327 int socktype;
328 int exp_result;
329 } services[] = {
330 { NULL, 0, 1, 0, 0 },
331 { "0", 0, 1, 0, 0 },
332 { "1", 1, 1, 0, 0 },
333 { "32767", 32767, 1, 0, 0 },
334 { "32768", 32768, 1, 0, 0 },
335 { "65535", 65535, 1, 0, 0 },
336 { "echo", 7, 0, 0, 0 },
337 { "ftp", 21, 0, SOCK_STREAM, 0 },
338 { "tftp", 69, 0, SOCK_DGRAM , 0 },
339 { "-1", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) },
340 { "", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) },
341 { "65537", 0, 1, 0, (1 << EAI_SERVICE) },
342 { "XXX", 0, 0, 0, (1 << EAI_SERVICE) }};
344 static struct
346 int value;
347 int exp_result;
348 } families[] = {
349 { AF_UNSPEC, 0 },
350 { AF_INET, 0 },
351 { AF_UNSPEC + AF_INET + 1, (1 << EAI_FAMILY) }};
353 static struct
355 int value;
356 int exp_result;
357 } socktypes[] = {
358 { 0, 0 },
359 { SOCK_STREAM, 0 },
360 { SOCK_DGRAM, 0 },
361 { SOCK_STREAM + SOCK_DGRAM + 1,
362 (1 << EAI_SOCKTYPE) | (1 << EAI_FAIL) | (1 << EAI_NONAME) }};
364 #define LENGTH(a) (sizeof((a)) / sizeof((a)[0]))
366 static void test_getaddrinfo_all(int use_network)
368 int flag_PASSIVE, flag_CANONNAME, flag_NUMERICHOST, flag_NUMERICSERV;
369 int exp_results, flags, i, j, k, l, passhints;
370 unsigned long ipaddr;
372 /* loop through various parameter values */
373 for (i = 0; i < LENGTH(hosts); i++)
374 for (j = 0; j < LENGTH(services); j++)
375 for (k = 0; k < LENGTH(families); k++)
376 for (l = 0; l < LENGTH(socktypes); l++)
377 for (flag_PASSIVE = 0; flag_PASSIVE < 2; flag_PASSIVE++)
378 for (flag_CANONNAME = 0; flag_CANONNAME < 2; flag_CANONNAME++)
379 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
380 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
381 for (passhints = 0; passhints < 2; passhints++)
383 /* skip tests that need but cannot use network */
384 if (!use_network && hosts[i].need_network)
385 continue;
387 /* determine flags */
388 flags = (flag_PASSIVE ? AI_PASSIVE : 0) |
389 (flag_CANONNAME ? AI_CANONNAME : 0) |
390 (flag_NUMERICHOST ? AI_NUMERICHOST : 0) |
391 (flag_NUMERICSERV ? AI_NUMERICSERV : 0);
393 /* some options require hints */
394 if (families[k].value != AF_UNSPEC ||
395 socktypes[l].value != 0 || flags) {
396 passhints = 1;
399 /* flags may influence IP address */
400 ipaddr = hosts[i].ipaddr;
401 if (!hosts[i].nodename && flag_PASSIVE)
402 ipaddr = INADDR_ANY;
404 /* determine expected result */
405 exp_results =
406 hosts[i].exp_result |
407 services[j].exp_result |
408 families[k].exp_result |
409 socktypes[l].exp_result;
410 if (!hosts[i].nodename && !services[j].servname)
411 exp_results |= (1 << EAI_NONAME);
413 if (flag_NUMERICHOST && !hosts[i].numeric)
414 exp_results |= (1 << EAI_NONAME);
416 if (flag_NUMERICSERV && !services[j].numeric)
417 exp_results |= (1 << EAI_NONAME);
419 /* When we don't pass hints, getaddrinfo will find suitable
420 * settings for us. If we do pass hints, there might be
421 * conflicts.
423 if (passhints) {
424 /* Can't have conflicting socket types */
425 if (services[j].socktype &&
426 socktypes[l].value &&
427 socktypes[l].value != services[j].socktype) {
428 exp_results |= (1 << EAI_SERVICE);
432 /* with no reason for failure, we demand success */
433 if (!exp_results)
434 exp_results |= (1 << 0);
436 /* test getaddrinfo function */
437 test_getaddrinfo(
438 hosts[i].nodename,
439 hosts[i].numeric,
440 services[j].servname,
441 services[j].numeric,
442 passhints,
443 flags,
444 families[k].value,
445 socktypes[l].value,
446 exp_results,
447 htonl(ipaddr),
448 flag_CANONNAME && hosts[i].canonname,
449 htons(services[j].port));
453 static struct
455 const char *nodename;
456 const char *nodenum;
457 unsigned long ipaddr;
458 int havename;
459 } ipaddrs[] = {
460 { "0.0.0.0", "0.0.0.0", 0x00000000, 0 },
461 { "0.0.0.255", "0.0.0.255", 0x000000ff, 0 },
462 { "0.0.255.0", "0.0.255.0", 0x0000ff00, 0 },
463 { "0.255.0.0", "0.255.0.0", 0x00ff0000, 0 },
464 { "255.0.0.0", "255.0.0.0", 0xff000000, 0 },
465 { "localhost", "127.0.0.1", 0x7f000001, 1 },
466 /* no reverse DNS unfortunately */
467 /* { "minix3.org", "130.37.20.20", 0x82251414, 1 } */};
469 static struct
471 const char *servname;
472 const char *servnum;
473 unsigned short port;
474 int socktype;
475 } ports[] = {
476 { "0", "0", 0, 0 },
477 { "tcpmux", "1", 1, SOCK_STREAM },
478 { "32767", "32767", 32767, 0 },
479 { "32768", "32768", 32768, 0 },
480 { "65535", "65535", 65535, 0 },
481 { "echo", "7", 7, 0 },
482 { "ftp", "21", 21, SOCK_STREAM },
483 { "tftp", "69", 69, SOCK_DGRAM }};
485 static int buflens[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 255 };
487 static void test_getnameinfo_all(void)
489 int flag_NUMERICHOST, flag_NAMEREQD, flag_NUMERICSERV, flag_DGRAM;
490 int exp_results, flags, i, j, k, l, socktypemismatch;
491 const char *nodename, *servname;
493 /* loop through various parameter values */
494 for (i = 0; i < LENGTH(ipaddrs); i++)
495 for (j = 0; j < LENGTH(ports); j++)
496 for (k = 0; k < LENGTH(buflens); k++)
497 for (l = 0; l < LENGTH(buflens); l++)
498 for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
499 for (flag_NAMEREQD = 0; flag_NAMEREQD < 2; flag_NAMEREQD++)
500 for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
501 for (flag_DGRAM = 0; flag_DGRAM < 2; flag_DGRAM++)
503 /* determine flags */
504 flags = (flag_NUMERICHOST ? NI_NUMERICHOST : 0) |
505 (flag_NAMEREQD ? NI_NAMEREQD : 0) |
506 (flag_NUMERICSERV ? NI_NUMERICSERV : 0) |
507 (flag_DGRAM ? NI_DGRAM : 0);
509 /* determine expected result */
510 exp_results = 0;
512 nodename = flag_NUMERICHOST ? ipaddrs[i].nodenum : ipaddrs[i].nodename;
513 if (buflens[k] > 0 && buflens[k] <= strlen(nodename))
514 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY);
516 socktypemismatch =
517 (flag_DGRAM && ports[j].socktype == SOCK_STREAM) ||
518 (!flag_DGRAM && ports[j].socktype == SOCK_DGRAM);
519 servname = (flag_NUMERICSERV || socktypemismatch) ?
520 ports[j].servnum : ports[j].servname;
521 if (buflens[l] > 0 && buflens[l] <= strlen(servname))
522 exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY);
524 if (flag_NAMEREQD && (!ipaddrs[i].havename || flag_NUMERICHOST) && buflens[k])
525 exp_results |= (1 << EAI_NONAME);
527 /* with no reason for failure, we demand success */
528 if (!exp_results)
529 exp_results |= (1 << 0);
531 /* perform the test */
532 test_getnameinfo(
533 htonl(ipaddrs[i].ipaddr),
534 htons(ports[j].port),
535 nodename,
536 buflens[k],
537 servname,
538 buflens[l],
539 flags,
540 exp_results);
544 static int can_use_network(void)
546 int status;
548 /* try to ping minix3.org */
549 status = system("ping www.minix3.org > /dev/null 2>&1");
550 if (status == 127)
552 printf("cannot execute ping\n");
553 err();
556 return status == 0;
559 int main(void)
561 int use_network;
563 start(48);
565 use_network = can_use_network();
566 if (!use_network)
567 printf("Warning: no network\n");
568 test_getaddrinfo_all(use_network);
569 test_getnameinfo_all();
571 quit();
572 return 0;