]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/testprogs/selpolltest.c
Update apr to 1.7.0. See contrib/apr/CHANGES for a summary of changes.
[FreeBSD/FreeBSD.git] / contrib / libpcap / testprogs / 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 #include "varattrs.h"
23
24 #ifndef lint
25 static const char copyright[] _U_ =
26     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
27 The Regents of the University of California.  All rights reserved.\n";
28 #endif
29
30 /*
31  * Tests how select() and poll() behave on the selectable file descriptor
32  * for a pcap_t.
33  *
34  * This would be significantly different on Windows, as it'd test
35  * how WaitForMultipleObjects() would work on the event handle for a
36  * pcap_t.
37  */
38 #include <pcap.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdarg.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <sys/types.h>
46 #ifdef HAVE_SYS_SELECT_H
47 #include <sys/select.h>
48 #else
49 #include <sys/time.h>   /* older UN*Xes */
50 #endif
51 #include <poll.h>
52
53 #include "pcap/funcattrs.h"
54
55 static char *program_name;
56
57 /* Forwards */
58 static void countme(u_char *, const struct pcap_pkthdr *, const u_char *);
59 static void PCAP_NORETURN usage(void);
60 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
61 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
62 static char *copy_argv(char **);
63
64 static pcap_t *pd;
65
66 int
67 main(int argc, char **argv)
68 {
69         register int op;
70         bpf_u_int32 localnet, netmask;
71         register char *cp, *cmdbuf, *device;
72         int doselect, dopoll, dotimeout, dononblock;
73         const char *mechanism;
74         struct bpf_program fcode;
75         char ebuf[PCAP_ERRBUF_SIZE];
76         pcap_if_t *devlist;
77         int selectable_fd;
78         struct timeval *required_timeout;
79         int status;
80         int packet_count;
81
82         device = NULL;
83         doselect = 0;
84         dopoll = 0;
85         mechanism = NULL;
86         dotimeout = 0;
87         dononblock = 0;
88         if ((cp = strrchr(argv[0], '/')) != NULL)
89                 program_name = cp + 1;
90         else
91                 program_name = argv[0];
92
93         opterr = 0;
94         while ((op = getopt(argc, argv, "i:sptn")) != -1) {
95                 switch (op) {
96
97                 case 'i':
98                         device = optarg;
99                         break;
100
101                 case 's':
102                         doselect = 1;
103                         mechanism = "select() and pcap_dispatch()";
104                         break;
105
106                 case 'p':
107                         dopoll = 1;
108                         mechanism = "poll() and pcap_dispatch()";
109                         break;
110
111                 case 't':
112                         dotimeout = 1;
113                         break;
114
115                 case 'n':
116                         dononblock = 1;
117                         break;
118
119                 default:
120                         usage();
121                         /* NOTREACHED */
122                 }
123         }
124
125         if (doselect && dopoll) {
126                 fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n");
127                 return 1;
128         }
129         if (dotimeout && !doselect && !dopoll) {
130                 fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n");
131                 return 1;
132         }
133         if (device == NULL) {
134                 if (pcap_findalldevs(&devlist, ebuf) == -1)
135                         error("%s", ebuf);
136                 if (devlist == NULL)
137                         error("no interfaces available for capture");
138                 device = strdup(devlist->name);
139                 pcap_freealldevs(devlist);
140         }
141         *ebuf = '\0';
142         pd = pcap_open_live(device, 65535, 0, 1000, ebuf);
143         if (pd == NULL)
144                 error("%s", ebuf);
145         else if (*ebuf)
146                 warning("%s", ebuf);
147         if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
148                 localnet = 0;
149                 netmask = 0;
150                 warning("%s", ebuf);
151         }
152         cmdbuf = copy_argv(&argv[optind]);
153
154         if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
155                 error("%s", pcap_geterr(pd));
156         if (pcap_setfilter(pd, &fcode) < 0)
157                 error("%s", pcap_geterr(pd));
158
159         if (doselect || dopoll) {
160                 /*
161                  * We need either an FD on which to do select()/poll()
162                  * or, if there isn't one, a timeout to use in select()/
163                  * poll().
164                  */
165                 selectable_fd = pcap_get_selectable_fd(pd);
166                 if (selectable_fd == -1) {
167                         printf("Listening on %s, using %s, with a timeout\n",
168                             device, mechanism);
169                         required_timeout = pcap_get_required_select_timeout(pd);
170                         if (required_timeout == NULL)
171                                 error("select()/poll() isn't supported on %s, even with a timeout",
172                                     device);
173
174                         /*
175                          * As we won't be notified by select() or poll()
176                          * that a read can be done, we'll have to periodically
177                          * try reading from the device every time the required
178                          * timeout expires, and we don't want those attempts
179                          * to block if nothing has arrived in that interval,
180                          * so we want to force non-blocking mode.
181                          */
182                         dononblock = 1;
183                 } else {
184                         printf("Listening on %s, using %s\n", device,
185                             mechanism);
186                         required_timeout = NULL;
187                 }
188         } else
189                 printf("Listening on %s, using pcap_dispatch()\n", device);
190
191         if (dononblock) {
192                 if (pcap_setnonblock(pd, 1, ebuf) == -1)
193                         error("pcap_setnonblock failed: %s", ebuf);
194         }
195         if (doselect) {
196                 for (;;) {
197                         fd_set setread, setexcept;
198                         struct timeval seltimeout;
199
200                         FD_ZERO(&setread);
201                         if (selectable_fd != -1) {
202                                 FD_SET(selectable_fd, &setread);
203                                 FD_ZERO(&setexcept);
204                                 FD_SET(selectable_fd, &setexcept);
205                         }
206                         if (dotimeout) {
207                                 seltimeout.tv_sec = 0;
208                                 if (required_timeout != NULL &&
209                                     required_timeout->tv_usec < 1000)
210                                         seltimeout.tv_usec = required_timeout->tv_usec;
211                                 else
212                                         seltimeout.tv_usec = 1000;
213                                 status = select(selectable_fd + 1, &setread,
214                                     NULL, &setexcept, &seltimeout);
215                         } else if (required_timeout != NULL) {
216                                 seltimeout = *required_timeout;
217                                 status = select(selectable_fd + 1, &setread,
218                                     NULL, &setexcept, &seltimeout);
219                         } else {
220                                 status = select((selectable_fd == -1) ?
221                                     0 : selectable_fd + 1, &setread,
222                                     NULL, &setexcept, NULL);
223                         }
224                         if (status == -1) {
225                                 printf("Select returns error (%s)\n",
226                                     strerror(errno));
227                         } else {
228                                 if (selectable_fd == -1) {
229                                         if (status != 0)
230                                                 printf("Select returned a descriptor\n");
231                                 } else {
232                                         if (status == 0)
233                                                 printf("Select timed out: ");
234                                         else
235                                                 printf("Select returned a descriptor: ");
236                                         if (FD_ISSET(selectable_fd, &setread))
237                                                 printf("readable, ");
238                                         else
239                                                 printf("not readable, ");
240                                         if (FD_ISSET(selectable_fd, &setexcept))
241                                                 printf("exceptional condition\n");
242                                         else
243                                                 printf("no exceptional condition\n");
244                                 }
245                                 packet_count = 0;
246                                 status = pcap_dispatch(pd, -1, countme,
247                                     (u_char *)&packet_count);
248                                 if (status < 0)
249                                         break;
250                                 /*
251                                  * Don't report this if we're using a
252                                  * required timeout and we got no packets,
253                                  * because that could be a very short timeout,
254                                  * and we don't want to spam the user with
255                                  * a ton of "no packets" reports.
256                                  */
257                                 if (status != 0 || packet_count != 0 ||
258                                     required_timeout != NULL) {
259                                         printf("%d packets seen, %d packets counted after select returns\n",
260                                             status, packet_count);
261                                 }
262                         }
263                 }
264         } else if (dopoll) {
265                 for (;;) {
266                         struct pollfd fd;
267                         int polltimeout;
268
269                         fd.fd = selectable_fd;
270                         fd.events = POLLIN;
271                         if (dotimeout)
272                                 polltimeout = 1;
273                         else if (required_timeout != NULL &&
274                             required_timeout->tv_usec >= 1000)
275                                 polltimeout = required_timeout->tv_usec/1000;
276                         else
277                                 polltimeout = -1;
278                         status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout);
279                         if (status == -1) {
280                                 printf("Poll returns error (%s)\n",
281                                     strerror(errno));
282                         } else {
283                                 if (selectable_fd == -1) {
284                                         if (status != 0)
285                                                 printf("Poll returned a descriptor\n");
286                                 } else {
287                                         if (status == 0)
288                                                 printf("Poll timed out\n");
289                                         else {
290                                                 printf("Poll returned a descriptor: ");
291                                                 if (fd.revents & POLLIN)
292                                                         printf("readable, ");
293                                                 else
294                                                         printf("not readable, ");
295                                                 if (fd.revents & POLLERR)
296                                                         printf("exceptional condition, ");
297                                                 else
298                                                         printf("no exceptional condition, ");
299                                                 if (fd.revents & POLLHUP)
300                                                         printf("disconnect, ");
301                                                 else
302                                                         printf("no disconnect, ");
303                                                 if (fd.revents & POLLNVAL)
304                                                         printf("invalid\n");
305                                                 else
306                                                         printf("not invalid\n");
307                                         }
308                                 }
309                                 packet_count = 0;
310                                 status = pcap_dispatch(pd, -1, countme,
311                                     (u_char *)&packet_count);
312                                 if (status < 0)
313                                         break;
314                                 /*
315                                  * Don't report this if we're using a
316                                  * required timeout and we got no packets,
317                                  * because that could be a very short timeout,
318                                  * and we don't want to spam the user with
319                                  * a ton of "no packets" reports.
320                                  */
321                                 if (status != 0 || packet_count != 0 ||
322                                     required_timeout != NULL) {
323                                         printf("%d packets seen, %d packets counted after poll returns\n",
324                                             status, packet_count);
325                                 }
326                         }
327                 }
328         } else {
329                 for (;;) {
330                         packet_count = 0;
331                         status = pcap_dispatch(pd, -1, countme,
332                             (u_char *)&packet_count);
333                         if (status < 0)
334                                 break;
335                         printf("%d packets seen, %d packets counted after pcap_dispatch returns\n",
336                             status, packet_count);
337                 }
338         }
339         if (status == -2) {
340                 /*
341                  * We got interrupted, so perhaps we didn't
342                  * manage to finish a line we were printing.
343                  * Print an extra newline, just in case.
344                  */
345                 putchar('\n');
346         }
347         (void)fflush(stdout);
348         if (status == -1) {
349                 /*
350                  * Error.  Report it.
351                  */
352                 (void)fprintf(stderr, "%s: pcap_loop: %s\n",
353                     program_name, pcap_geterr(pd));
354         }
355         pcap_close(pd);
356         exit(status == -1 ? 1 : 0);
357 }
358
359 static void
360 countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
361 {
362         int *counterp = (int *)user;
363
364         (*counterp)++;
365 }
366
367 static void
368 usage(void)
369 {
370         (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n",
371             program_name);
372         exit(1);
373 }
374
375 /* VARARGS */
376 static void
377 error(const char *fmt, ...)
378 {
379         va_list ap;
380
381         (void)fprintf(stderr, "%s: ", program_name);
382         va_start(ap, fmt);
383         (void)vfprintf(stderr, fmt, ap);
384         va_end(ap);
385         if (*fmt) {
386                 fmt += strlen(fmt);
387                 if (fmt[-1] != '\n')
388                         (void)fputc('\n', stderr);
389         }
390         exit(1);
391         /* NOTREACHED */
392 }
393
394 /* VARARGS */
395 static void
396 warning(const char *fmt, ...)
397 {
398         va_list ap;
399
400         (void)fprintf(stderr, "%s: WARNING: ", program_name);
401         va_start(ap, fmt);
402         (void)vfprintf(stderr, fmt, ap);
403         va_end(ap);
404         if (*fmt) {
405                 fmt += strlen(fmt);
406                 if (fmt[-1] != '\n')
407                         (void)fputc('\n', stderr);
408         }
409 }
410
411 /*
412  * Copy arg vector into a new buffer, concatenating arguments with spaces.
413  */
414 static char *
415 copy_argv(register char **argv)
416 {
417         register char **p;
418         register u_int len = 0;
419         char *buf;
420         char *src, *dst;
421
422         p = argv;
423         if (*p == 0)
424                 return 0;
425
426         while (*p)
427                 len += strlen(*p++) + 1;
428
429         buf = (char *)malloc(len);
430         if (buf == NULL)
431                 error("copy_argv: malloc");
432
433         p = argv;
434         dst = buf;
435         while ((src = *p++) != NULL) {
436                 while ((*dst++ = *src++) != '\0')
437                         ;
438                 dst[-1] = ' ';
439         }
440         dst[-1] = '\0';
441
442         return buf;
443 }