testga.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #include "unp.h"
  2. /*
  3. * Test program for getaddrinfo() and getnameinfo().
  4. */
  5. /* function prototypes for internal functions */
  6. static void do_errtest(void);
  7. static void do_funccall(const char *, const char *, int, int, int, int, int);
  8. static int do_onetest(char *, char *, struct addrinfo *, int);
  9. static const char *str_fam(int);
  10. static const char *str_sock(int);
  11. static void usage(const char *);
  12. /* globals */
  13. int vflag;
  14. int
  15. main(int argc, char **argv)
  16. {
  17. int doerrtest = 0;
  18. int loopcount = 1;
  19. int c, i;
  20. char *host = NULL;
  21. char hostbuf[NI_MAXHOST];
  22. char *serv = NULL;
  23. char servbuf[NI_MAXSERV];
  24. struct protoent *proto;
  25. struct addrinfo hints; /* set by command-line options */
  26. if (argc < 2)
  27. usage("");
  28. memset(&hints, 0, sizeof(struct addrinfo));
  29. opterr = 0; /* don't want getopt() writing to stderr */
  30. while ( (c = getopt(argc, argv, "cef:h:l:pr:s:t:v")) != -1) {
  31. switch (c) {
  32. case 'c':
  33. hints.ai_flags |= AI_CANONNAME;
  34. break;
  35. case 'e':
  36. doerrtest = 1;
  37. break;
  38. case 'f': /* address family */
  39. #ifdef IPv4
  40. if (strcmp(optarg, "inet") == 0) {
  41. hints.ai_family = AF_INET;
  42. break;
  43. }
  44. #endif
  45. #ifdef IPv6
  46. if (strcmp(optarg, "inet6") == 0) {
  47. hints.ai_family = AF_INET6;
  48. break;
  49. }
  50. #endif
  51. #ifdef UNIXdomain
  52. if (strcmp(optarg, "unix") == 0) {
  53. hints.ai_family = AF_LOCAL;
  54. break;
  55. }
  56. #endif
  57. usage("invalid -f option");
  58. case 'h': /* host */
  59. strncpy(hostbuf, optarg, NI_MAXHOST-1);
  60. host = hostbuf;
  61. break;
  62. case 'l': /* loop count */
  63. loopcount = atoi(optarg);
  64. break;
  65. case 'p':
  66. hints.ai_flags |= AI_PASSIVE;
  67. break;
  68. case 'r': /* protocol */
  69. if ((proto = getprotobyname(optarg)) == NULL) {
  70. hints.ai_protocol = atoi(optarg);
  71. } else {
  72. hints.ai_protocol = proto->p_proto;
  73. }
  74. break;
  75. case 's':
  76. strncpy(servbuf, optarg, NI_MAXSERV-1);
  77. serv = servbuf;
  78. break;
  79. case 't': /* socket type */
  80. if (strcmp(optarg, "stream") == 0) {
  81. hints.ai_socktype = SOCK_STREAM;
  82. break;
  83. }
  84. if (strcmp(optarg, "dgram") == 0) {
  85. hints.ai_socktype = SOCK_DGRAM;
  86. break;
  87. }
  88. if (strcmp(optarg, "raw") == 0) {
  89. hints.ai_socktype = SOCK_RAW;
  90. break;
  91. }
  92. #ifdef SOCK_RDM
  93. if (strcmp(optarg, "rdm") == 0) {
  94. hints.ai_socktype = SOCK_RDM;
  95. break;
  96. }
  97. #endif
  98. #ifdef SOCK_SEQPACKET
  99. if (strcmp(optarg, "seqpacket") == 0) {
  100. hints.ai_socktype = SOCK_SEQPACKET;
  101. break;
  102. }
  103. #endif
  104. usage("invalid -t option");
  105. case 'v':
  106. vflag = 1;
  107. break;
  108. case '?':
  109. usage("unrecognized option");
  110. }
  111. }
  112. if (optind < argc) {
  113. usage("extra args");
  114. }
  115. if (doerrtest) {
  116. do_errtest();
  117. exit(0);
  118. }
  119. for (i = 1; i <= loopcount; i++) {
  120. if (do_onetest(host, serv, &hints, i) > 0)
  121. exit(1);
  122. if (i % 1000 == 0) {
  123. printf(" %d", i);
  124. fflush(stdout);
  125. }
  126. }
  127. exit(0);
  128. }
  129. /*
  130. * Check that the right error codes are returned for invalid input.
  131. * Test all the errors that are easy to test for.
  132. */
  133. static void
  134. do_errtest(void)
  135. {
  136. /* passive open with no hostname and no address family */
  137. do_funccall(NULL, "ftp", AI_PASSIVE, 0, 0, 0, 0);
  138. /* kind of hard to automatically test EAI_AGAIN ??? */
  139. /* invalid flags */
  140. do_funccall("localhost", NULL, 999999, 0, 0, 0, EAI_BADFLAGS);
  141. /* how to test EAI_FAIL ??? */
  142. /* invalid address family */
  143. do_funccall("localhost", NULL, 0, AF_SNA, 0, 0, EAI_FAMILY);
  144. /* hard to test for EAI_MEMORY: would have to malloc() until
  145. failure, then give some back, then call getaddrinfo and
  146. hope that its memory requests would not be satisfied. */
  147. /* to test for EAI_NODATA: would have to know of a host with
  148. no A record in the DNS */
  149. #ifdef notdef /* following depends on resolver, sigh */
  150. /* believe it or not, there is a registered domain "bar.com",
  151. so the following should generate NO_DATA from the DNS */
  152. do_funccall("foo.bar.foo.bar.foo.bar.com", NULL, 0, 0, 0, 0, EAI_NODATA);
  153. #endif
  154. /* no hostname, no service name */
  155. do_funccall(NULL, NULL, 0, 0, 0, 0, EAI_NONAME);
  156. /* invalid hostname (should be interpreted in local default domain) */
  157. do_funccall("lkjjkhjhghgfgfd", NULL, 0, 0, 0, 0, EAI_NONAME);
  158. /* invalid service name */
  159. do_funccall(NULL, "nosuchservice", 0, 0, 0, 0, EAI_NONAME);
  160. /* service valid but not supported for socket type */
  161. do_funccall("localhost", "telnet", 0, 0, SOCK_DGRAM, 0, EAI_SERVICE);
  162. /* service valid but not supported for socket type */
  163. do_funccall("localhost", "tftp", 0, 0, SOCK_STREAM, 0, EAI_SERVICE);
  164. /* invalid socket type */
  165. do_funccall("localhost", NULL, 0, AF_INET, SOCK_SEQPACKET, 0, EAI_SOCKTYPE);
  166. /* EAI_SYSTEM not generated by my implementation */
  167. }
  168. static void
  169. do_funccall(const char *host, const char *serv,
  170. int flags, int family, int socktype, int protocol, int exprc)
  171. {
  172. int rc;
  173. struct addrinfo hints, *res;
  174. memset(&hints, 0, sizeof(struct addrinfo));
  175. hints.ai_flags = flags;
  176. hints.ai_family = family;
  177. hints.ai_socktype = socktype;
  178. hints.ai_protocol = protocol;
  179. rc = getaddrinfo(host, serv, &hints, &res);
  180. if (rc != exprc) {
  181. printf("expected return = %d (%s),\nactual return = %d (%s)\n",
  182. exprc, gai_strerror(exprc), rc, gai_strerror(rc));
  183. if (host != NULL)
  184. printf(" host = %s\n", host);
  185. if (serv != NULL)
  186. printf(" serv = %s\n", serv);
  187. printf(" flags = %d, family = %s, socktype = %s, protocol = %d\n",
  188. flags, str_fam(family), str_sock(socktype), protocol);
  189. exit(2);
  190. }
  191. }
  192. static int
  193. do_onetest(char *host, char *serv, struct addrinfo *hints, int iteration)
  194. {
  195. int rc, fd, verbose;
  196. struct addrinfo *res, *rescopy;
  197. char rhost[NI_MAXHOST], rserv[NI_MAXSERV];
  198. verbose = vflag && (iteration == 1); /* only first time */
  199. if (host != NULL && verbose)
  200. printf("host = %s\n", host);
  201. if (serv != NULL && verbose)
  202. printf("serv = %s\n", serv);
  203. rc = getaddrinfo(host, serv, hints, &res);
  204. if (rc != 0) {
  205. printf("getaddrinfo return code = %d (%s)\n", rc, gai_strerror(rc));
  206. return(1);
  207. }
  208. rescopy = res;
  209. do {
  210. if (iteration == 1) { /* always print results first time */
  211. printf("\nsocket(%s, %s, %d)", str_fam(res->ai_family),
  212. str_sock(res->ai_socktype), res->ai_protocol);
  213. /* canonname should be set only in first addrinfo{} */
  214. if (hints->ai_flags & AI_CANONNAME) {
  215. if (res->ai_canonname)
  216. printf(", ai_canonname = %s", res->ai_canonname);
  217. }
  218. printf("\n");
  219. printf("\taddress: %s\n",
  220. Sock_ntop(res->ai_addr, res->ai_addrlen));
  221. }
  222. /* Call socket() to make sure return values are valid */
  223. fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  224. if (fd < 0)
  225. printf("call to socket() failed!\n");
  226. else
  227. close(fd);
  228. /*
  229. * Call getnameinfo() to check the reverse mapping.
  230. */
  231. rc = getnameinfo(res->ai_addr, res->ai_addrlen,
  232. rhost, NI_MAXHOST, rserv, NI_MAXSERV,
  233. (res->ai_socktype == SOCK_DGRAM) ? NI_DGRAM: 0);
  234. if (rc == 0) {
  235. if (verbose)
  236. printf("\tgetnameinfo: host = %s, serv = %s\n",
  237. rhost, rserv);
  238. } else
  239. printf("getnameinfo returned %d (%s)\n", rc, gai_strerror(rc));
  240. } while ( (res = res->ai_next) != NULL);
  241. freeaddrinfo(rescopy);
  242. return(0);
  243. }
  244. static void
  245. usage(const char *msg)
  246. {
  247. printf(
  248. "usage: testaddrinfo [ options ]\n"
  249. "options: -h <host> (can be hostname or address string)\n"
  250. " -s <service> (can be service name or decimal port number)\n"
  251. " -c AI_CANONICAL flag\n"
  252. " -p AI_PASSIVE flag\n"
  253. " -l N loop N times (check for memory leaks with ps)\n"
  254. " -f X address family, X = inet, inet6, unix\n"
  255. " -r X protocol, X = tcp, udp, ... or number e.g. 6, 17, ...\n"
  256. " -t X socket type, X = stream, dgram, raw, rdm, seqpacket\n"
  257. " -v verbose\n"
  258. " -e only do test of error returns (no options required)\n"
  259. " without -e, one or both of <host> and <service> must be specified.\n"
  260. );
  261. if (msg[0] != 0)
  262. printf("%s\n", msg);
  263. exit(1);
  264. }
  265. static const char *
  266. str_fam(int family)
  267. {
  268. #ifdef IPv4
  269. if (family == AF_INET)
  270. return("AF_INET");
  271. #endif
  272. #ifdef IPv6
  273. if (family == AF_INET6)
  274. return("AF_INET6");
  275. #endif
  276. #ifdef UNIXdomain
  277. if (family == AF_LOCAL)
  278. return("AF_LOCAL");
  279. #endif
  280. return("<unknown family>");
  281. }
  282. static const char *
  283. str_sock(int socktype)
  284. {
  285. switch(socktype) {
  286. case SOCK_STREAM: return "SOCK_STREAM";
  287. case SOCK_DGRAM: return "SOCK_DGRAM";
  288. case SOCK_RAW: return "SOCK_RAW";
  289. #ifdef SOCK_RDM
  290. case SOCK_RDM: return "SOCK_RDM";
  291. #endif
  292. #ifdef SOCK_SEQPACKET
  293. case SOCK_SEQPACKET:return "SOCK_SEQPACKET";
  294. #endif
  295. default: return "<unknown socktype>";
  296. }
  297. }