| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- #include "unp.h"
- /*
- * Test program for getaddrinfo() and getnameinfo().
- */
- /* function prototypes for internal functions */
- static void do_errtest(void);
- static void do_funccall(const char *, const char *, int, int, int, int, int);
- static int do_onetest(char *, char *, struct addrinfo *, int);
- static const char *str_fam(int);
- static const char *str_sock(int);
- static void usage(const char *);
- /* globals */
- int vflag;
- int
- main(int argc, char **argv)
- {
- int doerrtest = 0;
- int loopcount = 1;
- int c, i;
- char *host = NULL;
- char hostbuf[NI_MAXHOST];
- char *serv = NULL;
- char servbuf[NI_MAXSERV];
- struct protoent *proto;
- struct addrinfo hints; /* set by command-line options */
- if (argc < 2)
- usage("");
- memset(&hints, 0, sizeof(struct addrinfo));
- opterr = 0; /* don't want getopt() writing to stderr */
- while ( (c = getopt(argc, argv, "cef:h:l:pr:s:t:v")) != -1) {
- switch (c) {
- case 'c':
- hints.ai_flags |= AI_CANONNAME;
- break;
- case 'e':
- doerrtest = 1;
- break;
- case 'f': /* address family */
- #ifdef IPv4
- if (strcmp(optarg, "inet") == 0) {
- hints.ai_family = AF_INET;
- break;
- }
- #endif
- #ifdef IPv6
- if (strcmp(optarg, "inet6") == 0) {
- hints.ai_family = AF_INET6;
- break;
- }
- #endif
- #ifdef UNIXdomain
- if (strcmp(optarg, "unix") == 0) {
- hints.ai_family = AF_LOCAL;
- break;
- }
- #endif
- usage("invalid -f option");
- case 'h': /* host */
- strncpy(hostbuf, optarg, NI_MAXHOST-1);
- host = hostbuf;
- break;
- case 'l': /* loop count */
- loopcount = atoi(optarg);
- break;
- case 'p':
- hints.ai_flags |= AI_PASSIVE;
- break;
- case 'r': /* protocol */
- if ((proto = getprotobyname(optarg)) == NULL) {
- hints.ai_protocol = atoi(optarg);
- } else {
- hints.ai_protocol = proto->p_proto;
- }
- break;
- case 's':
- strncpy(servbuf, optarg, NI_MAXSERV-1);
- serv = servbuf;
- break;
- case 't': /* socket type */
- if (strcmp(optarg, "stream") == 0) {
- hints.ai_socktype = SOCK_STREAM;
- break;
- }
- if (strcmp(optarg, "dgram") == 0) {
- hints.ai_socktype = SOCK_DGRAM;
- break;
- }
- if (strcmp(optarg, "raw") == 0) {
- hints.ai_socktype = SOCK_RAW;
- break;
- }
- #ifdef SOCK_RDM
- if (strcmp(optarg, "rdm") == 0) {
- hints.ai_socktype = SOCK_RDM;
- break;
- }
- #endif
- #ifdef SOCK_SEQPACKET
- if (strcmp(optarg, "seqpacket") == 0) {
- hints.ai_socktype = SOCK_SEQPACKET;
- break;
- }
- #endif
- usage("invalid -t option");
- case 'v':
- vflag = 1;
- break;
- case '?':
- usage("unrecognized option");
- }
- }
- if (optind < argc) {
- usage("extra args");
- }
- if (doerrtest) {
- do_errtest();
- exit(0);
- }
- for (i = 1; i <= loopcount; i++) {
- if (do_onetest(host, serv, &hints, i) > 0)
- exit(1);
- if (i % 1000 == 0) {
- printf(" %d", i);
- fflush(stdout);
- }
- }
- exit(0);
- }
- /*
- * Check that the right error codes are returned for invalid input.
- * Test all the errors that are easy to test for.
- */
- static void
- do_errtest(void)
- {
- /* passive open with no hostname and no address family */
- do_funccall(NULL, "ftp", AI_PASSIVE, 0, 0, 0, 0);
- /* kind of hard to automatically test EAI_AGAIN ??? */
- /* invalid flags */
- do_funccall("localhost", NULL, 999999, 0, 0, 0, EAI_BADFLAGS);
- /* how to test EAI_FAIL ??? */
- /* invalid address family */
- do_funccall("localhost", NULL, 0, AF_SNA, 0, 0, EAI_FAMILY);
- /* hard to test for EAI_MEMORY: would have to malloc() until
- failure, then give some back, then call getaddrinfo and
- hope that its memory requests would not be satisfied. */
- /* to test for EAI_NODATA: would have to know of a host with
- no A record in the DNS */
- #ifdef notdef /* following depends on resolver, sigh */
- /* believe it or not, there is a registered domain "bar.com",
- so the following should generate NO_DATA from the DNS */
- do_funccall("foo.bar.foo.bar.foo.bar.com", NULL, 0, 0, 0, 0, EAI_NODATA);
- #endif
- /* no hostname, no service name */
- do_funccall(NULL, NULL, 0, 0, 0, 0, EAI_NONAME);
- /* invalid hostname (should be interpreted in local default domain) */
- do_funccall("lkjjkhjhghgfgfd", NULL, 0, 0, 0, 0, EAI_NONAME);
- /* invalid service name */
- do_funccall(NULL, "nosuchservice", 0, 0, 0, 0, EAI_NONAME);
- /* service valid but not supported for socket type */
- do_funccall("localhost", "telnet", 0, 0, SOCK_DGRAM, 0, EAI_SERVICE);
- /* service valid but not supported for socket type */
- do_funccall("localhost", "tftp", 0, 0, SOCK_STREAM, 0, EAI_SERVICE);
- /* invalid socket type */
- do_funccall("localhost", NULL, 0, AF_INET, SOCK_SEQPACKET, 0, EAI_SOCKTYPE);
- /* EAI_SYSTEM not generated by my implementation */
- }
- static void
- do_funccall(const char *host, const char *serv,
- int flags, int family, int socktype, int protocol, int exprc)
- {
- int rc;
- struct addrinfo hints, *res;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_flags = flags;
- hints.ai_family = family;
- hints.ai_socktype = socktype;
- hints.ai_protocol = protocol;
- rc = getaddrinfo(host, serv, &hints, &res);
- if (rc != exprc) {
- printf("expected return = %d (%s),\nactual return = %d (%s)\n",
- exprc, gai_strerror(exprc), rc, gai_strerror(rc));
- if (host != NULL)
- printf(" host = %s\n", host);
- if (serv != NULL)
- printf(" serv = %s\n", serv);
- printf(" flags = %d, family = %s, socktype = %s, protocol = %d\n",
- flags, str_fam(family), str_sock(socktype), protocol);
- exit(2);
- }
- }
- static int
- do_onetest(char *host, char *serv, struct addrinfo *hints, int iteration)
- {
- int rc, fd, verbose;
- struct addrinfo *res, *rescopy;
- char rhost[NI_MAXHOST], rserv[NI_MAXSERV];
- verbose = vflag && (iteration == 1); /* only first time */
- if (host != NULL && verbose)
- printf("host = %s\n", host);
- if (serv != NULL && verbose)
- printf("serv = %s\n", serv);
- rc = getaddrinfo(host, serv, hints, &res);
- if (rc != 0) {
- printf("getaddrinfo return code = %d (%s)\n", rc, gai_strerror(rc));
- return(1);
- }
- rescopy = res;
- do {
- if (iteration == 1) { /* always print results first time */
- printf("\nsocket(%s, %s, %d)", str_fam(res->ai_family),
- str_sock(res->ai_socktype), res->ai_protocol);
- /* canonname should be set only in first addrinfo{} */
- if (hints->ai_flags & AI_CANONNAME) {
- if (res->ai_canonname)
- printf(", ai_canonname = %s", res->ai_canonname);
- }
- printf("\n");
- printf("\taddress: %s\n",
- Sock_ntop(res->ai_addr, res->ai_addrlen));
- }
- /* Call socket() to make sure return values are valid */
- fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd < 0)
- printf("call to socket() failed!\n");
- else
- close(fd);
- /*
- * Call getnameinfo() to check the reverse mapping.
- */
- rc = getnameinfo(res->ai_addr, res->ai_addrlen,
- rhost, NI_MAXHOST, rserv, NI_MAXSERV,
- (res->ai_socktype == SOCK_DGRAM) ? NI_DGRAM: 0);
- if (rc == 0) {
- if (verbose)
- printf("\tgetnameinfo: host = %s, serv = %s\n",
- rhost, rserv);
- } else
- printf("getnameinfo returned %d (%s)\n", rc, gai_strerror(rc));
- } while ( (res = res->ai_next) != NULL);
- freeaddrinfo(rescopy);
- return(0);
- }
- static void
- usage(const char *msg)
- {
- printf(
- "usage: testaddrinfo [ options ]\n"
- "options: -h <host> (can be hostname or address string)\n"
- " -s <service> (can be service name or decimal port number)\n"
- " -c AI_CANONICAL flag\n"
- " -p AI_PASSIVE flag\n"
- " -l N loop N times (check for memory leaks with ps)\n"
- " -f X address family, X = inet, inet6, unix\n"
- " -r X protocol, X = tcp, udp, ... or number e.g. 6, 17, ...\n"
- " -t X socket type, X = stream, dgram, raw, rdm, seqpacket\n"
- " -v verbose\n"
- " -e only do test of error returns (no options required)\n"
- " without -e, one or both of <host> and <service> must be specified.\n"
- );
- if (msg[0] != 0)
- printf("%s\n", msg);
- exit(1);
- }
- static const char *
- str_fam(int family)
- {
- #ifdef IPv4
- if (family == AF_INET)
- return("AF_INET");
- #endif
- #ifdef IPv6
- if (family == AF_INET6)
- return("AF_INET6");
- #endif
- #ifdef UNIXdomain
- if (family == AF_LOCAL)
- return("AF_LOCAL");
- #endif
- return("<unknown family>");
- }
- static const char *
- str_sock(int socktype)
- {
- switch(socktype) {
- case SOCK_STREAM: return "SOCK_STREAM";
- case SOCK_DGRAM: return "SOCK_DGRAM";
- case SOCK_RAW: return "SOCK_RAW";
- #ifdef SOCK_RDM
- case SOCK_RDM: return "SOCK_RDM";
- #endif
- #ifdef SOCK_SEQPACKET
- case SOCK_SEQPACKET:return "SOCK_SEQPACKET";
- #endif
- default: return "<unknown socktype>";
- }
- }
|