PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/test/test48.c

http://www.minix3.org/
C | 573 lines | 460 code | 71 blank | 42 comment | 119 complexity | 2a8d16761a32b4e11d236dfe729048e3 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  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>
  8. #define MAX_ERROR 3
  9. #define err() e(__LINE__)
  10. #include "common.c"
  11. static void printstr(const char *s)
  12. {
  13. if (s)
  14. printf("\"%s\"", s);
  15. else
  16. printf("NULL");
  17. }
  18. static void test_getaddrinfo_err(
  19. int n,
  20. const char *nodename,
  21. const char *servname,
  22. int passhints,
  23. int flags,
  24. int family,
  25. int socktype,
  26. const char *exp_result,
  27. const char *result)
  28. {
  29. printf("error %d: getaddrinfo(", n);
  30. printstr(nodename);
  31. printf(", ");
  32. printstr(servname);
  33. printf(", ");
  34. if (passhints)
  35. printf("{ 0x%x, %d, %d }", flags, family, socktype);
  36. else
  37. printf("NULL");
  38. printf("); result: ");
  39. printstr(result);
  40. printf("; expected: ");
  41. printstr(exp_result);
  42. printf("\n");
  43. err();
  44. }
  45. /* yes, this is ugly, but not as ugly as repeating it all every time */
  46. #define TEST_GETADDRINFO_ERR_PARAMS \
  47. nodename, servname, passhints, flags, family, socktype
  48. static void test_getaddrinfo_err_nr(
  49. int n,
  50. const char *nodename,
  51. const char *servname,
  52. int passhints,
  53. int flags,
  54. int family,
  55. int socktype,
  56. int exp_result,
  57. int result)
  58. {
  59. char exp_result_s[23], result_s[23];
  60. /* convert result to string */
  61. snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
  62. exp_result, exp_result);
  63. snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
  64. test_getaddrinfo_err(n, TEST_GETADDRINFO_ERR_PARAMS,
  65. exp_result_s, result_s);
  66. }
  67. static void test_getnameinfo_err(
  68. int n,
  69. unsigned long ipaddr,
  70. unsigned short port,
  71. socklen_t nodelen,
  72. socklen_t servicelen,
  73. int flags,
  74. const char *exp_result,
  75. const char *result)
  76. {
  77. printf("error %d: getnameinfo(0x%.8x, %d, %d, %d, 0x%x); result: ",
  78. n, ntohl(ipaddr), ntohs(port), nodelen, servicelen, flags);
  79. printstr(result);
  80. printf("; expected: ");
  81. printstr(exp_result);
  82. printf("\n");
  83. err();
  84. }
  85. /* yes, this is ugly, but not as ugly as repeating it all every time */
  86. #define TEST_GETNAMEINFO_ERR_PARAMS ipaddr, port, nodelen, servicelen, flags
  87. static void test_getnameinfo_err_nr(
  88. int n,
  89. unsigned long ipaddr,
  90. unsigned short port,
  91. socklen_t nodelen,
  92. socklen_t servicelen,
  93. int flags,
  94. int exp_result,
  95. int result)
  96. {
  97. char exp_result_s[23], result_s[23];
  98. /* convert result to string */
  99. snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
  100. exp_result, exp_result);
  101. snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
  102. test_getnameinfo_err(n, TEST_GETNAMEINFO_ERR_PARAMS,
  103. exp_result_s, result_s);
  104. }
  105. static void test_getaddrinfo(
  106. const char *nodename,
  107. int nodename_numerical,
  108. const char *servname,
  109. int servname_numerical,
  110. int passhints,
  111. int flags,
  112. int family,
  113. int socktype,
  114. int exp_results,
  115. unsigned long exp_ip,
  116. int exp_canonname,
  117. unsigned short exp_port)
  118. {
  119. struct addrinfo *ai, *ai_cur;
  120. struct addrinfo hints;
  121. struct sockaddr_in *sockaddr_in;
  122. int ai_count_dgram, ai_count_stream, r;
  123. /* some parameters are only meaningful with hints */
  124. assert(passhints || !flags);
  125. assert(passhints || family == AF_UNSPEC);
  126. assert(passhints || !socktype);
  127. /* a combination of parameters don't make sense to test */
  128. if (nodename == NULL && servname == NULL) return;
  129. if (nodename == NULL && (flags & AI_NUMERICHOST)) return;
  130. if (servname == NULL && (flags & AI_NUMERICSERV)) return;
  131. /* initialize hints */
  132. memset(&hints, 0, sizeof(hints));
  133. hints.ai_flags = flags;
  134. hints.ai_family = family;
  135. hints.ai_socktype = socktype;
  136. /* perform query and test result */
  137. ai = (struct addrinfo *) 0xDEADBEEF;
  138. r = getaddrinfo(nodename, servname, passhints ? &hints : NULL, &ai);
  139. if (r < 0 || r >= 32 || !((1 << r) & exp_results))
  140. test_getaddrinfo_err_nr(1, TEST_GETADDRINFO_ERR_PARAMS, exp_results, r);
  141. if (r)
  142. return;
  143. /* the function succeeded; do the results make sense? */
  144. ai_cur = ai;
  145. ai_count_dgram = 0;
  146. ai_count_stream = 0;
  147. while (ai_cur)
  148. {
  149. /* test result fields */
  150. if (ai_cur->ai_family != AF_INET)
  151. test_getaddrinfo_err_nr(2, TEST_GETADDRINFO_ERR_PARAMS,
  152. AF_INET, ai_cur->ai_family);
  153. if (socktype && ai_cur->ai_socktype != socktype)
  154. test_getaddrinfo_err_nr(3, TEST_GETADDRINFO_ERR_PARAMS,
  155. socktype, ai_cur->ai_socktype);
  156. switch (ai_cur->ai_socktype)
  157. {
  158. case SOCK_DGRAM: ai_count_dgram++; break;
  159. case SOCK_STREAM: ai_count_stream++; break;
  160. }
  161. /* do address and port match? */
  162. if (ai_cur->ai_addrlen != sizeof(struct sockaddr_in))
  163. test_getaddrinfo_err_nr(4, TEST_GETADDRINFO_ERR_PARAMS,
  164. sizeof(struct sockaddr_in),
  165. ai_cur->ai_addrlen);
  166. else
  167. {
  168. sockaddr_in = (struct sockaddr_in *) ai_cur->ai_addr;
  169. if (sockaddr_in->sin_addr.s_addr != exp_ip)
  170. test_getaddrinfo_err_nr(5,
  171. TEST_GETADDRINFO_ERR_PARAMS,
  172. ntohl(exp_ip),
  173. ntohl(sockaddr_in->sin_addr.s_addr));
  174. if (sockaddr_in->sin_port != exp_port)
  175. test_getaddrinfo_err_nr(6,
  176. TEST_GETADDRINFO_ERR_PARAMS,
  177. ntohs(exp_port),
  178. ntohs(sockaddr_in->sin_port));
  179. }
  180. /* If a hostname is numeric, there can't be a canonical name.
  181. * Instead, the returned canonname (if requested) will be
  182. * identical to the supplied hostname */
  183. if (nodename != NULL && nodename_numerical &&
  184. (flags & AI_CANONNAME)) {
  185. if (strncmp(ai_cur->ai_canonname, nodename,
  186. strlen(nodename)))
  187. test_getaddrinfo_err(11,
  188. TEST_GETADDRINFO_ERR_PARAMS,
  189. nodename, ai_cur->ai_canonname);
  190. } else {
  191. /* is canonical supplied? */
  192. if (exp_canonname && nodename &&
  193. (!ai_cur->ai_canonname || !*ai_cur->ai_canonname))
  194. test_getaddrinfo_err(7,
  195. TEST_GETADDRINFO_ERR_PARAMS,
  196. "(anything)", ai_cur->ai_canonname);
  197. if (!exp_canonname && ai_cur->ai_canonname)
  198. test_getaddrinfo_err(8,
  199. TEST_GETADDRINFO_ERR_PARAMS,
  200. NULL, ai_cur->ai_canonname);
  201. }
  202. /* move to next result */
  203. ai_cur = ai_cur->ai_next;
  204. }
  205. /* If socket type is non-zero, make sure we got what we wanted. Else
  206. * any result is okay. */
  207. if (socktype) {
  208. if (ai_count_dgram != ((socktype == SOCK_STREAM) ? 0 : 1))
  209. test_getaddrinfo_err_nr(9, TEST_GETADDRINFO_ERR_PARAMS,
  210. (socktype == SOCK_STREAM) ? 0 : 1, ai_count_dgram);
  211. if (ai_count_stream != ((socktype == SOCK_DGRAM) ? 0 : 1))
  212. test_getaddrinfo_err_nr(10, TEST_GETADDRINFO_ERR_PARAMS,
  213. (socktype == SOCK_DGRAM) ? 0 : 1, ai_count_stream);
  214. }
  215. /* clean up */
  216. freeaddrinfo(ai);
  217. }
  218. static void memsetl(void *s, unsigned long c, size_t n)
  219. {
  220. unsigned char *p = (unsigned char *) s;
  221. size_t i;
  222. for (i = 0; i < n; i++)
  223. p[i] = c >> (8 * (i % sizeof(c)));
  224. }
  225. void test_getnameinfo(
  226. unsigned long ipaddr,
  227. unsigned short port,
  228. const char *exp_node,
  229. socklen_t nodelen,
  230. const char *exp_service,
  231. socklen_t servicelen,
  232. int flags,
  233. int exp_results)
  234. {
  235. struct sockaddr_in sockaddr;
  236. char node[256], service[256];
  237. int r;
  238. /* avoid buffer overflows */
  239. assert(nodelen <= sizeof(node));
  240. assert(servicelen <= sizeof(service));
  241. /* perform query and test result */
  242. sockaddr.sin_family = AF_INET;
  243. sockaddr.sin_addr.s_addr = ipaddr;
  244. sockaddr.sin_port = port;
  245. memsetl(node, 0xDEADBEEF, nodelen);
  246. memsetl(service, 0xDEADBEEF, servicelen);
  247. r = getnameinfo((struct sockaddr *) &sockaddr, sizeof(sockaddr),
  248. node, nodelen, service, servicelen, flags);
  249. if (r < 0 || r >= 32 || !((1 << r) & exp_results))
  250. test_getnameinfo_err_nr(1, TEST_GETNAMEINFO_ERR_PARAMS,
  251. exp_results, r);
  252. if (r)
  253. return;
  254. /* check results */
  255. if (nodelen && strcmp(exp_node, node) != 0)
  256. test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
  257. exp_node, node);
  258. if (servicelen && strcmp(exp_service, service) != 0)
  259. test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
  260. exp_service, service);
  261. }
  262. static struct
  263. {
  264. const char *nodename;
  265. unsigned long ipaddr;
  266. int numeric;
  267. int canonname;
  268. int need_network;
  269. int exp_result;
  270. } hosts[] = {
  271. { NULL, 0x7f000001, 1, 1, 0, 0 },
  272. { "0.0.0.0", 0x00000000, 1, 0, 0, 0 },
  273. { "0.0.0.255", 0x000000ff, 1, 0, 0, 0 },
  274. { "0.0.255.0", 0x0000ff00, 1, 0, 0, 0 },
  275. { "0.255.0.0", 0x00ff0000, 1, 0, 0, 0 },
  276. { "255.0.0.0", 0xff000000, 1, 0, 0, 0 },
  277. { "127.0.0.1", 0x7f000001, 1, 0, 0, 0 },
  278. { "localhost", 0x7f000001, 0, 1, 0, 0, },
  279. { "static.minix3.org", 0xC023C00A, 0, 1, 1, 0, },
  280. { "", 0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)},
  281. { "256.256.256.256",0x00000000, 1, 0, 0, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)},
  282. { "minix3.xyz", 0x00000000, 0, 0, 1, (1<<EAI_NONAME)|(1<<EAI_FAIL)|(1<<EAI_NODATA)}};
  283. static struct
  284. {
  285. const char *servname;
  286. unsigned short port;
  287. int numeric;
  288. int socktype;
  289. int exp_result;
  290. } services[] = {
  291. { NULL, 0, 1, 0, 0 },
  292. { "0", 0, 1, 0, 0 },
  293. { "1", 1, 1, 0, 0 },
  294. { "32767", 32767, 1, 0, 0 },
  295. { "32768", 32768, 1, 0, 0 },
  296. { "65535", 65535, 1, 0, 0 },
  297. { "echo", 7, 0, 0, 0 },
  298. { "ftp", 21, 0, SOCK_STREAM, 0 },
  299. { "tftp", 69, 0, SOCK_DGRAM , 0 },
  300. { "-1", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) },
  301. { "", 0, 1, 0, (1<<EAI_NONAME) | (1<<EAI_SERVICE) },
  302. { "65537", 0, 1, 0, (1 << EAI_SERVICE) },
  303. { "XXX", 0, 0, 0, (1 << EAI_SERVICE) }};
  304. static struct
  305. {
  306. int value;
  307. int exp_result;
  308. } families[] = {
  309. { AF_UNSPEC, 0 },
  310. { AF_INET, 0 },
  311. { AF_UNSPEC + AF_INET + 1, (1 << EAI_FAMILY) }};
  312. static struct
  313. {
  314. int value;
  315. int exp_result;
  316. } socktypes[] = {
  317. { 0, 0 },
  318. { SOCK_STREAM, 0 },
  319. { SOCK_DGRAM, 0 },
  320. { SOCK_STREAM + SOCK_DGRAM + 1,
  321. (1 << EAI_SOCKTYPE) | (1 << EAI_FAIL) | (1 << EAI_NONAME) }};
  322. #define LENGTH(a) (sizeof((a)) / sizeof((a)[0]))
  323. static void test_getaddrinfo_all(int use_network)
  324. {
  325. int flag_PASSIVE, flag_CANONNAME, flag_NUMERICHOST, flag_NUMERICSERV;
  326. int exp_results, flags, i, j, k, l, passhints;
  327. unsigned long ipaddr;
  328. /* loop through various parameter values */
  329. for (i = 0; i < LENGTH(hosts); i++)
  330. for (j = 0; j < LENGTH(services); j++)
  331. for (k = 0; k < LENGTH(families); k++)
  332. for (l = 0; l < LENGTH(socktypes); l++)
  333. for (flag_PASSIVE = 0; flag_PASSIVE < 2; flag_PASSIVE++)
  334. for (flag_CANONNAME = 0; flag_CANONNAME < 2; flag_CANONNAME++)
  335. for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
  336. for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
  337. for (passhints = 0; passhints < 2; passhints++)
  338. {
  339. /* skip tests that need but cannot use network */
  340. if (!use_network && hosts[i].need_network)
  341. continue;
  342. /* determine flags */
  343. flags = (flag_PASSIVE ? AI_PASSIVE : 0) |
  344. (flag_CANONNAME ? AI_CANONNAME : 0) |
  345. (flag_NUMERICHOST ? AI_NUMERICHOST : 0) |
  346. (flag_NUMERICSERV ? AI_NUMERICSERV : 0);
  347. /* some options require hints */
  348. if (families[k].value != AF_UNSPEC ||
  349. socktypes[l].value != 0 || flags) {
  350. passhints = 1;
  351. }
  352. /* flags may influence IP address */
  353. ipaddr = hosts[i].ipaddr;
  354. if (!hosts[i].nodename && flag_PASSIVE)
  355. ipaddr = INADDR_ANY;
  356. /* determine expected result */
  357. exp_results =
  358. hosts[i].exp_result |
  359. services[j].exp_result |
  360. families[k].exp_result |
  361. socktypes[l].exp_result;
  362. if (!hosts[i].nodename && !services[j].servname)
  363. exp_results |= (1 << EAI_NONAME);
  364. if (flag_NUMERICHOST && !hosts[i].numeric)
  365. exp_results |= (1 << EAI_NONAME);
  366. if (flag_NUMERICSERV && !services[j].numeric)
  367. exp_results |= (1 << EAI_NONAME);
  368. /* When we don't pass hints, getaddrinfo will find suitable
  369. * settings for us. If we do pass hints, there might be
  370. * conflicts.
  371. */
  372. if (passhints) {
  373. /* Can't have conflicting socket types */
  374. if (services[j].socktype &&
  375. socktypes[l].value &&
  376. socktypes[l].value != services[j].socktype) {
  377. exp_results |= (1 << EAI_SERVICE);
  378. }
  379. }
  380. /* with no reason for failure, we demand success */
  381. if (!exp_results)
  382. exp_results |= (1 << 0);
  383. /* test getaddrinfo function */
  384. test_getaddrinfo(
  385. hosts[i].nodename,
  386. hosts[i].numeric,
  387. services[j].servname,
  388. services[j].numeric,
  389. passhints,
  390. flags,
  391. families[k].value,
  392. socktypes[l].value,
  393. exp_results,
  394. htonl(ipaddr),
  395. flag_CANONNAME && hosts[i].canonname,
  396. htons(services[j].port));
  397. }
  398. }
  399. static struct
  400. {
  401. const char *nodename;
  402. const char *nodenum;
  403. unsigned long ipaddr;
  404. int havename;
  405. } ipaddrs[] = {
  406. { "0.0.0.0", "0.0.0.0", 0x00000000, 0 },
  407. { "0.0.0.255", "0.0.0.255", 0x000000ff, 0 },
  408. { "0.0.255.0", "0.0.255.0", 0x0000ff00, 0 },
  409. { "0.255.0.0", "0.255.0.0", 0x00ff0000, 0 },
  410. { "255.0.0.0", "255.0.0.0", 0xff000000, 0 },
  411. { "localhost", "127.0.0.1", 0x7f000001, 1 },
  412. /* no reverse DNS unfortunately */
  413. /* { "minix3.org", "130.37.20.20", 0x82251414, 1 } */};
  414. static struct
  415. {
  416. const char *servname;
  417. const char *servnum;
  418. unsigned short port;
  419. int socktype;
  420. } ports[] = {
  421. { "0", "0", 0, 0 },
  422. { "tcpmux", "1", 1, SOCK_STREAM },
  423. { "32767", "32767", 32767, 0 },
  424. { "32768", "32768", 32768, 0 },
  425. { "65535", "65535", 65535, 0 },
  426. { "echo", "7", 7, 0 },
  427. { "ftp", "21", 21, SOCK_STREAM },
  428. { "tftp", "69", 69, SOCK_DGRAM }};
  429. static int buflens[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 255 };
  430. static void test_getnameinfo_all(void)
  431. {
  432. int flag_NUMERICHOST, flag_NAMEREQD, flag_NUMERICSERV, flag_DGRAM;
  433. int exp_results, flags, i, j, k, l, socktypemismatch;
  434. const char *nodename, *servname;
  435. /* loop through various parameter values */
  436. for (i = 0; i < LENGTH(ipaddrs); i++)
  437. for (j = 0; j < LENGTH(ports); j++)
  438. for (k = 0; k < LENGTH(buflens); k++)
  439. for (l = 0; l < LENGTH(buflens); l++)
  440. for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
  441. for (flag_NAMEREQD = 0; flag_NAMEREQD < 2; flag_NAMEREQD++)
  442. for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
  443. for (flag_DGRAM = 0; flag_DGRAM < 2; flag_DGRAM++)
  444. {
  445. /* determine flags */
  446. flags = (flag_NUMERICHOST ? NI_NUMERICHOST : 0) |
  447. (flag_NAMEREQD ? NI_NAMEREQD : 0) |
  448. (flag_NUMERICSERV ? NI_NUMERICSERV : 0) |
  449. (flag_DGRAM ? NI_DGRAM : 0);
  450. /* determine expected result */
  451. exp_results = 0;
  452. nodename = flag_NUMERICHOST ? ipaddrs[i].nodenum : ipaddrs[i].nodename;
  453. if (buflens[k] > 0 && buflens[k] <= strlen(nodename))
  454. exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY);
  455. socktypemismatch =
  456. (flag_DGRAM && ports[j].socktype == SOCK_STREAM) ||
  457. (!flag_DGRAM && ports[j].socktype == SOCK_DGRAM);
  458. servname = (flag_NUMERICSERV || socktypemismatch) ?
  459. ports[j].servnum : ports[j].servname;
  460. if (buflens[l] > 0 && buflens[l] <= strlen(servname))
  461. exp_results |= (1 << EAI_OVERFLOW) | (1 << EAI_MEMORY);
  462. if (flag_NAMEREQD && (!ipaddrs[i].havename || flag_NUMERICHOST) && buflens[k])
  463. exp_results |= (1 << EAI_NONAME);
  464. /* with no reason for failure, we demand success */
  465. if (!exp_results)
  466. exp_results |= (1 << 0);
  467. /* perform the test */
  468. test_getnameinfo(
  469. htonl(ipaddrs[i].ipaddr),
  470. htons(ports[j].port),
  471. nodename,
  472. buflens[k],
  473. servname,
  474. buflens[l],
  475. flags,
  476. exp_results);
  477. }
  478. }
  479. static int can_use_network(void)
  480. {
  481. int status;
  482. /* try to ping minix3.org */
  483. status = system("ping www.minix3.org > /dev/null 2>&1");
  484. if (status == 127)
  485. {
  486. printf("cannot execute ping\n");
  487. err();
  488. }
  489. return status == 0;
  490. }
  491. int main(void)
  492. {
  493. int use_network;
  494. start(48);
  495. use_network = can_use_network();
  496. if (!use_network)
  497. printf("Warning: no network\n");
  498. test_getaddrinfo_all(use_network);
  499. test_getnameinfo_all();
  500. quit();
  501. return 0;
  502. }