Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 #ifndef lint
     23 static const char copyright[] _U_ =
     24     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
     25 The Regents of the University of California.  All rights reserved.\n";
     26 #endif
     27 
     28 /*
     29  * Tests how select() and poll() behave on the selectable file descriptor
     30  * for a pcap_t.
     31  *
     32  * This would be significantly different on Windows, as it'd test
     33  * how WaitForMultipleObjects() would work on the event handle for a
     34  * pcap_t.
     35  */
     36 #include <pcap.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <stdarg.h>
     41 #include <unistd.h>
     42 #include <errno.h>
     43 #include <sys/types.h>
     44 #ifdef HAVE_SYS_SELECT_H
     45 #include <sys/select.h>
     46 #else
     47 #include <sys/time.h>	/* older UN*Xes */
     48 #endif
     49 #include <poll.h>
     50 
     51 char *program_name;
     52 
     53 /*
     54  * This was introduced by Clang:
     55  *
     56  *     http://clang.llvm.org/docs/LanguageExtensions.html#has-attribute
     57  *
     58  * in some version (which version?); it has been picked up by GCC 5.0.
     59  */
     60 #ifndef __has_attribute
     61   /*
     62    * It's a macro, so you can check whether it's defined to check
     63    * whether it's supported.
     64    *
     65    * If it's not, define it to always return 0, so that we move on to
     66    * the fallback checks.
     67    */
     68   #define __has_attribute(x) 0
     69 #endif
     70 
     71 #if __has_attribute(noreturn) \
     72     || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \
     73     || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) \
     74     || (defined(__xlC__) && __xlC__ >= 0x0A01) \
     75     || (defined(__HP_aCC) && __HP_aCC >= 61000)
     76   /*
     77    * Compiler with support for it, or GCC 2.5 and later, or Solaris Studio 12
     78    * (Sun C 5.9) and later, or IBM XL C 10.1 and later (do any earlier
     79    * versions of XL C support this?), or HP aCC A.06.10 and later.
     80    */
     81   #define PCAP_NORETURN __attribute((noreturn))
     82 #elif defined( _MSC_VER )
     83   #define PCAP_NORETURN __declspec(noreturn)
     84 #else
     85   #define PCAP_NORETURN
     86 #endif
     87 
     88 #if __has_attribute(__format__) \
     89     || (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)) \
     90     || (defined(__xlC__) && __xlC__ >= 0x0A01) \
     91     || (defined(__HP_aCC) && __HP_aCC >= 61000)
     92   /*
     93    * Compiler with support for it, or GCC 2.3 and later, or IBM XL C 10.1
     94    * and later (do any earlier versions of XL C support this?),
     95    * or HP aCC A.06.10 and later.
     96    */
     97   #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y)))
     98 #else
     99   #define PCAP_PRINTFLIKE(x,y)
    100 #endif
    101 
    102 /* Forwards */
    103 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
    104 static void PCAP_NORETURN usage(void);
    105 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
    106 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
    107 static char *copy_argv(char **);
    108 
    109 static pcap_t *pd;
    110 
    111 int
    112 main(int argc, char **argv)
    113 {
    114 	register int op;
    115 	bpf_u_int32 localnet, netmask;
    116 	register char *cp, *cmdbuf, *device;
    117 	int doselect, dopoll, dotimeout, dononblock;
    118 	struct bpf_program fcode;
    119 	char ebuf[PCAP_ERRBUF_SIZE];
    120 	int selectable_fd;
    121 	int status;
    122 	int packet_count;
    123 
    124 	device = NULL;
    125 	doselect = 0;
    126 	dopoll = 0;
    127 	dotimeout = 0;
    128 	dononblock = 0;
    129 	if ((cp = strrchr(argv[0], '/')) != NULL)
    130 		program_name = cp + 1;
    131 	else
    132 		program_name = argv[0];
    133 
    134 	opterr = 0;
    135 	while ((op = getopt(argc, argv, "i:sptn")) != -1) {
    136 		switch (op) {
    137 
    138 		case 'i':
    139 			device = optarg;
    140 			break;
    141 
    142 		case 's':
    143 			doselect = 1;
    144 			break;
    145 
    146 		case 'p':
    147 			dopoll = 1;
    148 			break;
    149 
    150 		case 't':
    151 			dotimeout = 1;
    152 			break;
    153 
    154 		case 'n':
    155 			dononblock = 1;
    156 			break;
    157 
    158 		default:
    159 			usage();
    160 			/* NOTREACHED */
    161 		}
    162 	}
    163 
    164 	if (doselect && dopoll) {
    165 		fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n");
    166 		return 1;
    167 	}
    168 	if (dotimeout && !doselect && !dopoll) {
    169 		fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n");
    170 		return 1;
    171 	}
    172 	if (device == NULL) {
    173 		device = pcap_lookupdev(ebuf);
    174 		if (device == NULL)
    175 			error("%s", ebuf);
    176 	}
    177 	*ebuf = '\0';
    178 	pd = pcap_open_live(device, 65535, 0, 1000, ebuf);
    179 	if (pd == NULL)
    180 		error("%s", ebuf);
    181 	else if (*ebuf)
    182 		warning("%s", ebuf);
    183 	if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
    184 		localnet = 0;
    185 		netmask = 0;
    186 		warning("%s", ebuf);
    187 	}
    188 	cmdbuf = copy_argv(&argv[optind]);
    189 
    190 	if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
    191 		error("%s", pcap_geterr(pd));
    192 
    193 	if (pcap_setfilter(pd, &fcode) < 0)
    194 		error("%s", pcap_geterr(pd));
    195 	if (pcap_get_selectable_fd(pd) == -1)
    196 		error("pcap_get_selectable_fd() fails");
    197 	if (dononblock) {
    198 		if (pcap_setnonblock(pd, 1, ebuf) == -1)
    199 			error("pcap_setnonblock failed: %s", ebuf);
    200 	}
    201 	selectable_fd = pcap_get_selectable_fd(pd);
    202 	printf("Listening on %s\n", device);
    203 	if (doselect) {
    204 		for (;;) {
    205 			fd_set setread, setexcept;
    206 			struct timeval seltimeout;
    207 
    208 			FD_ZERO(&setread);
    209 			FD_SET(selectable_fd, &setread);
    210 			FD_ZERO(&setexcept);
    211 			FD_SET(selectable_fd, &setexcept);
    212 			if (dotimeout) {
    213 				seltimeout.tv_sec = 0;
    214 				seltimeout.tv_usec = 1000;
    215 				status = select(selectable_fd + 1, &setread,
    216 				    NULL, &setexcept, &seltimeout);
    217 			} else {
    218 				status = select(selectable_fd + 1, &setread,
    219 				    NULL, &setexcept, NULL);
    220 			}
    221 			if (status == -1) {
    222 				printf("Select returns error (%s)\n",
    223 				    strerror(errno));
    224 			} else {
    225 				if (status == 0)
    226 					printf("Select timed out: ");
    227 				else
    228 					printf("Select returned a descriptor: ");
    229 				if (FD_ISSET(selectable_fd, &setread))
    230 					printf("readable, ");
    231 				else
    232 					printf("not readable, ");
    233 				if (FD_ISSET(selectable_fd, &setexcept))
    234 					printf("exceptional condition\n");
    235 				else
    236 					printf("no exceptional condition\n");
    237 				packet_count = 0;
    238 				status = pcap_dispatch(pd, -1, countme,
    239 				    (u_char *)&packet_count);
    240 				if (status < 0)
    241 					break;
    242 				printf("%d packets seen, %d packets counted after select returns\n",
    243 				    status, packet_count);
    244 			}
    245 		}
    246 	} else if (dopoll) {
    247 		for (;;) {
    248 			struct pollfd fd;
    249 			int polltimeout;
    250 
    251 			fd.fd = selectable_fd;
    252 			fd.events = POLLIN;
    253 			if (dotimeout)
    254 				polltimeout = 1;
    255 			else
    256 				polltimeout = -1;
    257 			status = poll(&fd, 1, polltimeout);
    258 			if (status == -1) {
    259 				printf("Poll returns error (%s)\n",
    260 				    strerror(errno));
    261 			} else {
    262 				if (status == 0)
    263 					printf("Poll timed out\n");
    264 				else {
    265 					printf("Poll returned a descriptor: ");
    266 					if (fd.revents & POLLIN)
    267 						printf("readable, ");
    268 					else
    269 						printf("not readable, ");
    270 					if (fd.revents & POLLERR)
    271 						printf("exceptional condition, ");
    272 					else
    273 						printf("no exceptional condition, ");
    274 					if (fd.revents & POLLHUP)
    275 						printf("disconnect, ");
    276 					else
    277 						printf("no disconnect, ");
    278 					if (fd.revents & POLLNVAL)
    279 						printf("invalid\n");
    280 					else
    281 						printf("not invalid\n");
    282 				}
    283 				packet_count = 0;
    284 				status = pcap_dispatch(pd, -1, countme,
    285 				    (u_char *)&packet_count);
    286 				if (status < 0)
    287 					break;
    288 				printf("%d packets seen, %d packets counted after poll returns\n",
    289 				    status, packet_count);
    290 			}
    291 		}
    292 	} else {
    293 		for (;;) {
    294 			packet_count = 0;
    295 			status = pcap_dispatch(pd, -1, countme,
    296 			    (u_char *)&packet_count);
    297 			if (status < 0)
    298 				break;
    299 			printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
    300 			    status, packet_count);
    301 		}
    302 	}
    303 	if (status == -2) {
    304 		/*
    305 		 * We got interrupted, so perhaps we didn't
    306 		 * manage to finish a line we were printing.
    307 		 * Print an extra newline, just in case.
    308 		 */
    309 		putchar('\n');
    310 	}
    311 	(void)fflush(stdout);
    312 	if (status == -1) {
    313 		/*
    314 		 * Error.  Report it.
    315 		 */
    316 		(void)fprintf(stderr, "%s: pcap_loop: %s\n",
    317 		    program_name, pcap_geterr(pd));
    318 	}
    319 	pcap_close(pd);
    320 	exit(status == -1 ? 1 : 0);
    321 }
    322 
    323 static void
    324 countme(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
    325 {
    326 	int *counterp = (int *)user;
    327 
    328 	(*counterp)++;
    329 }
    330 
    331 static void
    332 usage(void)
    333 {
    334 	(void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
    335 	    program_name);
    336 	exit(1);
    337 }
    338 
    339 /* VARARGS */
    340 static void
    341 error(const char *fmt, ...)
    342 {
    343 	va_list ap;
    344 
    345 	(void)fprintf(stderr, "%s: ", program_name);
    346 	va_start(ap, fmt);
    347 	(void)vfprintf(stderr, fmt, ap);
    348 	va_end(ap);
    349 	if (*fmt) {
    350 		fmt += strlen(fmt);
    351 		if (fmt[-1] != '\n')
    352 			(void)fputc('\n', stderr);
    353 	}
    354 	exit(1);
    355 	/* NOTREACHED */
    356 }
    357 
    358 /* VARARGS */
    359 static void
    360 warning(const char *fmt, ...)
    361 {
    362 	va_list ap;
    363 
    364 	(void)fprintf(stderr, "%s: WARNING: ", program_name);
    365 	va_start(ap, fmt);
    366 	(void)vfprintf(stderr, fmt, ap);
    367 	va_end(ap);
    368 	if (*fmt) {
    369 		fmt += strlen(fmt);
    370 		if (fmt[-1] != '\n')
    371 			(void)fputc('\n', stderr);
    372 	}
    373 }
    374 
    375 /*
    376  * Copy arg vector into a new buffer, concatenating arguments with spaces.
    377  */
    378 static char *
    379 copy_argv(register char **argv)
    380 {
    381 	register char **p;
    382 	register u_int len = 0;
    383 	char *buf;
    384 	char *src, *dst;
    385 
    386 	p = argv;
    387 	if (*p == 0)
    388 		return 0;
    389 
    390 	while (*p)
    391 		len += strlen(*p++) + 1;
    392 
    393 	buf = (char *)malloc(len);
    394 	if (buf == NULL)
    395 		error("copy_argv: malloc");
    396 
    397 	p = argv;
    398 	dst = buf;
    399 	while ((src = *p++) != NULL) {
    400 		while ((*dst++ = *src++) != '\0')
    401 			;
    402 		dst[-1] = ' ';
    403 	}
    404 	dst[-1] = '\0';
    405 
    406 	return buf;
    407 }
    408