]> The Tcpdump Group git mirrors - libpcap/blob - tests/selpolltest.c
If parser debugging is enabled, ensure pcap_debug is exported.
[libpcap] / tests / selpolltest.c
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 }