diff options
-rw-r--r-- | pcap-int.h | 2 | ||||
-rw-r--r-- | pcap-linux.c | 417 | ||||
-rw-r--r-- | pcap.3pcap.in | 9 | ||||
-rw-r--r-- | pcap.c | 2 | ||||
-rw-r--r-- | pcap/pcap.h | 2 | ||||
-rw-r--r-- | pcap_get_required_select_timeout.3pcap | 108 | ||||
-rw-r--r-- | pcap_get_selectable_fd.3pcap | 8 | ||||
-rw-r--r-- | testprogs/selpolltest.c | 58 |
8 files changed, 478 insertions, 128 deletions
@@ -251,7 +251,7 @@ struct pcap { * pcap_t's with a required timeout, and the code must be * prepared not to see any packets from the attempt. */ - struct timeval *required_select_timeout; + const struct timeval *required_select_timeout; #endif /* diff --git a/pcap-linux.c b/pcap-linux.c index 0003af1a..f9fe8ac6 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -204,6 +204,7 @@ struct pcap_linux { int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ int ifindex; /* interface index of device we're bound to */ int lo_ifindex; /* interface index of the loopback device */ + int netdown; /* we got an ENETDOWN and haven't resolved it */ bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ char *mondevice; /* mac80211 monitor device we created */ u_char *mmapbuf; /* memory-mapped region pointer */ @@ -353,6 +354,14 @@ static void pcap_oneshot_mmap(u_char *user, const struct pcap_pkthdr *h, #endif /* + * Required select timeout if we're polling for an "interface disappeared" + * indication - 1 millisecond. + */ +static const struct timeval netdown_timeout = { + 0, 1000 /* 1000 microseconds = 1 millisecond */ +}; + +/* * Wrap some ioctl calls */ static int iface_get_id(int fd, const char *device, char *ebuf); @@ -1570,6 +1579,53 @@ linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll) } /* + * Check whether the device to which the pcap_t is bound still exists. + * We do so by asking what address the socket is bound to, and checking + * whether the ifindex in the address is -1, meaning "that device is gone", + * or some other value, meaning "that device still exists". + */ +static int +device_still_exists(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + struct sockaddr_ll addr; + socklen_t addr_len; + + /* + * If handlep->ifindex is -1, the socket isn't bound, meaning + * we're capturing on the "any" device; that device never + * disappears. (It should also never be configured down, so + * we shouldn't even get here, but let's make sure.) + */ + if (handlep->ifindex == -1) + return (1); /* it's still here */ + + /* + * OK, now try to get the address for the socket. + */ + addr_len = sizeof (addr); + if (getsockname(handle->fd, (struct sockaddr *) &addr, &addr_len) == -1) { + /* + * Error - report an error and return -1. + */ + pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "getsockname failed"); + return (-1); + } + if (addr.sll_ifindex == -1) { + /* + * This means the device went away. + */ + return (0); + } + + /* + * The device presumably just went down. + */ + return (1); +} + +/* * Read a packet from the socket calling the handler provided by * the user. Returns the number of packets received or -1 if an * error occured. @@ -1616,13 +1672,6 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) * loop, the signal handler should call pcap_breakloop() * to set handle->break_loop (we ignore it on other * platforms as well). - * We also ignore ENETDOWN, so that we can continue to - * capture traffic if the interface goes down and comes - * back up again; comments in the kernel indicate that - * we'll just block waiting for packets if we try to - * receive from a socket that delivered ENETDOWN, and, - * if we're using a memory-mapped buffer, we won't even - * get notified of "network down" events. */ bp = (u_char *)handle->buffer + handle->offset; @@ -1674,14 +1723,40 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) case ENETDOWN: /* - * The device on which we're capturing went away. + * The device on which we're capturing went away + * or the interface was taken down. + * + * Check whether the device still exists. + */ + if (device_still_exists(handle)) { + /* + * It does. Just ignore this; on the + * *BSDs and Darwin, we don't even + * get told whether the interface + * went down, and both there and on + * Linux, if it comes back up again, + * and new packes arrive or are sent, + * they'll be delivered. + * + * XXX - ideally, we'd return an + * "interface went down" warning, + * so the user can be told, but + * pcap_dispatch() etc. aren't + * defined to return warnings. + */ + return 0; + } + + /* + * It doesn't; report that. * - * XXX - we should really return - * PCAP_ERROR_IFACE_NOT_UP, but pcap_dispatch() - * etc. aren't defined to return that. + * XXX - we should really return an appropriate + * error for that, but pcap_dispatch() etc. aren't + * documented as having error returns other than + * PCAP_ERROR or PCAP_ERROR_BREAK. */ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, - "The interface went down"); + "The interface disappeared"); return PCAP_ERROR; default: @@ -4488,7 +4563,8 @@ pcap_get_ring_frame_status(pcap_t *handle, int offset) static int pcap_wait_for_frames_mmap(pcap_t *handle) { struct pcap_linux *handlep = handle->priv; - char c; + int timeout; + struct ifreq ifr; int ret; #ifdef HAVE_SYS_EVENTFD_H struct pollfd pollinfo[2]; @@ -4500,8 +4576,47 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) pollinfo[0].fd = handle->fd; pollinfo[0].events = POLLIN; - do { - /* + /* + * Keep polling until we either get some packets to read, see + * that we got told to break out of the loop, get a fatal error, + * or discover that the device went away. + * + * In non-blocking mode, we must still do one poll() to catch + * any pending error indications, but the poll() has a timeout + * of 0, so that it doesn't block, and we quit after that one + * poll(). + * + * If we've seen an ENETDOWN, it might be the first indication + * that the device went away, or it might just be that it was + * configured down. Unfortunately, there's no guarantee that + * the device has actually been removed as an interface, because: + * + * 1) if, as appears to be the case at least some of the time, + * the PF_PACKET socket code first gets a NETDEV_DOWN indication + * for the device and then gets a NETDEV_UNREGISTER indication + * for it, the first indication will cause a wakeup with ENETDOWN + * but won't set the packet socket's field for the interface index + * to -1, and the second indication won't cause a wakeup (because + * the first indication also caused the protocol hook to be + * unregistered) but will set the packet socket's field for the + * interface index to -1; + * + * 2) even if just a NETDEV_UNREGISTER indication is registered, + * the packet socket's field for the interface index only gets + * set to -1 after the wakeup, so there's a small but non-zero + * risk that a thread blocked waiting for the wakeup will get + * to the "fetch the socket name" code before the interface index + * gets set to -1, so it'll get the old interface index. + * + * Therefore, if we got an ENETDOWN and haven't seen a packet + * since then, we assume that we might be waiting for the interface + * to disappear, and poll with a timeout to try again in a short + * period of time. If we *do* see a packet, the interface has + * come back up again, and is *definitely* still there, so we + * don't need to poll. + */ + for (;;) { + /* * Yes, we do this even in non-blocking mode, as it's * the only way to get error indications from a * tpacket socket. @@ -4509,80 +4624,250 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) * The timeout is 0 in non-blocking mode, so poll() * returns immediately. */ + timeout = handlep->poll_timeout; + /* + * If we got an ENETDOWN and haven't gotten an indication + * that the device has gone away or that the device is up, + * we don't yet know for certain whether the device has + * gone away or not, do a poll() with a 1-millisecond timeout, + * as we have to poll indefinitely for "device went away" + * indications until we either get one or see that the + * device is up. + */ + if (handlep->netdown) { + if (timeout != 0) + timeout = 1; + } #ifdef HAVE_SYS_EVENTFD_H - ret = poll(pollinfo, 2, handlep->poll_timeout); + ret = poll(pollinfo, 2, timeout); #else - ret = poll(pollinfo, 1, handlep->poll_timeout); + ret = poll(pollinfo, 1, timeout); #endif - if (ret < 0 && errno != EINTR) { - pcap_fmt_errmsg_for_errno(handle->errbuf, - PCAP_ERRBUF_SIZE, errno, - "can't poll on packet socket"); - return PCAP_ERROR; - } else if (ret > 0 && pollinfo[0].revents && - (pollinfo[0].revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + if (ret < 0) { /* - * There's some indication other than - * "you can read on this descriptor" on - * the descriptor. + * Error. If it's not EINTR, report it. */ - if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) { - snprintf(handle->errbuf, - PCAP_ERRBUF_SIZE, - "Hangup on packet socket"); + if (errno != EINTR) { + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't poll on packet socket"); return PCAP_ERROR; } - if (pollinfo[0].revents & POLLERR) { + + /* + * It's EINTR; if we were told to break out of + * the loop, do so. + */ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } else if (ret > 0) { + /* + * OK, some descriptor is ready. + * Check the socket descriptor first. + * + * As I read the Linux man page, pollinfo[0].revents + * will either be POLLIN, POLLERR, POLLHUP, or POLLNVAL. + */ + if (pollinfo[0].revents == POLLIN) { + /* + * OK, we may have packets to + * read. + */ + break; + } + if (pollinfo[0].revents != 0) { + /* + * There's some indication other than + * "you can read on this descriptor" on + * the descriptor. + */ + if (pollinfo[0].revents & POLLNVAL) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Invalid polling request on packet socket"); + return PCAP_ERROR; + } + if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Hangup on packet socket"); + return PCAP_ERROR; + } + if (pollinfo[0].revents & POLLERR) { + /* + * Get the error. + */ + int err; + socklen_t errlen; + + errlen = sizeof(err); + if (getsockopt(handle->fd, SOL_SOCKET, + SO_ERROR, &err, &errlen) == -1) { + /* + * The call *itself* returned + * an error; make *that* + * the error. + */ + err = errno; + } + + /* + * OK, we have the error. + */ + if (err == ENETDOWN) { + /* + * The device on which we're + * capturing went away or the + * interface was taken down. + * + * We don't know for certain + * which happened, and the + * next poll() may indicate + * that there are packets + * to be read, so just set + * a flag to get us to do + * checks later, and set + * the required select + * timeout to 1 millisecond + * so that event loops that + * check our socket descriptor + * also time out so that + * they can call us and we + * can do the checks. + */ + handlep->netdown = 1; + handle->required_select_timeout = &netdown_timeout; + } else if (err == 0) { + /* + * This shouldn't happen, so + * report a special indication + * that it did. + */ + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Error condition on packet socket: Reported error was 0"); + return PCAP_ERROR; + } else { + pcap_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, + err, + "Error condition on packet socket"); + return PCAP_ERROR; + } + } + } +#ifdef HAVE_SYS_EVENTFD_H + /* + * Now check the event device. + */ + if (pollinfo[1].revents & POLLIN) { + uint64_t value; + (void)read(handlep->poll_breakloop_fd, &value, + sizeof(value)); + + /* + * This event gets signaled by a + * pcap_breakloop() call; if we were told + * to break out of the loop, do so. + */ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } +#endif + } + + /* + * Either: + * + * 1) we got neither an error from poll() nor any + * readable descriptors, in which case there + * are no packets waiting to read + * + * or + * + * 2) We got readable descriptors but the PF_PACKET + * socket wasn't one of them, in which case there + * are no packets waiting to read + * + * so, if we got an ENETDOWN, we've drained whatever + * packets were available to read at the point of the + * ENETDOWN. + * + * So, if we got an ENETDOWN and haven't gotten an indication + * that the device has gone away or that the device is up, + * we don't yet know for certain whether the device has + * gone away or not, check whether the device exists and is + * up. + */ + if (handlep->netdown) { + if (!device_still_exists(handle)) { /* - * A recv() will give us the actual error code. + * The device doesn't exist any more; + * report that. * - * XXX - make the socket non-blocking? + * XXX - we should really return an + * appropriate error for that, but + * pcap_dispatch() etc. aren't documented + * as having error returns other than + * PCAP_ERROR or PCAP_ERROR_BREAK. */ - if (recv(handle->fd, &c, sizeof c, - MSG_PEEK) != -1) - continue; /* what, no error? */ - if (errno == ENETDOWN) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "The interface disappeared"); + return PCAP_ERROR; + } + + /* + * The device still exists; try to see if it's up. + */ + memset(&ifr, 0, sizeof(ifr)); + pcap_strlcpy(ifr.ifr_name, handlep->device, + sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { + if (errno == ENXIO || errno == ENODEV) { /* - * The device on which we're - * capturing went away. + * OK, *now* it's gone. * - * XXX - we should really return - * PCAP_ERROR_IFACE_NOT_UP, but - * pcap_dispatch() etc. aren't - * defined to return that. + * XXX - see above comment. */ snprintf(handle->errbuf, - PCAP_ERRBUF_SIZE, - "The interface went down"); + PCAP_ERRBUF_SIZE, + "The interface disappeared"); + return PCAP_ERROR; } else { pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, - "Error condition on packet socket"); + "%s: Can't get flags", + handlep->device); + return PCAP_ERROR; } - return PCAP_ERROR; } - if (pollinfo[0].revents & POLLNVAL) { - snprintf(handle->errbuf, - PCAP_ERRBUF_SIZE, - "Invalid polling request on packet socket"); - return PCAP_ERROR; + if (ifr.ifr_flags & IFF_UP) { + /* + * It's up, so it definitely still exists. + * Cancel the ENETDOWN indication - we + * presumably got it due to the interface + * going down rather than the device going + * away - and revert to "no required select + * timeout. + */ + handlep->netdown = 0; + handle->required_select_timeout = NULL; } } -#ifdef HAVE_SYS_EVENTFD_H - if (pollinfo[1].revents & POLLIN) { - uint64_t value; - (void)read(handlep->poll_breakloop_fd, &value, sizeof(value)); - } -#endif - - /* check for break loop condition on interrupted syscall*/ - if (handle->break_loop) { - handle->break_loop = 0; - return PCAP_ERROR_BREAK; - } - } while (ret < 0); + /* + * If we're in non-blocking mode, just quit now, rather + * than spinning in a loop doing poll()s that immediately + * time out if there's no indication on any descriptor. + */ + if (handlep->poll_timeout == 0) + break; + } return 0; } diff --git a/pcap.3pcap.in b/pcap.3pcap.in index 7a69f0ac..62c65eeb 100644 --- a/pcap.3pcap.in +++ b/pcap.3pcap.in @@ -652,7 +652,7 @@ from the device. Not all handles have such a descriptor available; .BR pcap_get_selectable_fd () will return -.B PCAP_ERROR +.B \-1 if no such descriptor is available. If no such descriptor is available, this may be because the device must be polled periodically for packets; in that case, @@ -727,13 +727,12 @@ and .BR poll (2) .TP .BR pcap_get_required_select_timeout (3PCAP) -if no descriptor usable with +attempt to get a timeout required for using a +.B pcap_t +in calls such as .BR select (2) and .BR poll (2) -is available for the -.BR pcap_t , -attempt to get a timeout usable with those routines .RE .SS Filters In order to cause only certain packets to be returned when reading @@ -3312,7 +3312,7 @@ pcap_get_selectable_fd(pcap_t *p) return (p->selectable_fd); } -struct timeval * +const struct timeval * pcap_get_required_select_timeout(pcap_t *p) { return (p->required_select_timeout); diff --git a/pcap/pcap.h b/pcap/pcap.h index e738c762..60f3dbef 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -662,7 +662,7 @@ PCAP_API const char *pcap_lib_version(void); */ PCAP_API int pcap_get_selectable_fd(pcap_t *); - PCAP_API struct timeval *pcap_get_required_select_timeout(pcap_t *); + PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *); #endif /* _WIN32/MSDOS/UN*X */ diff --git a/pcap_get_required_select_timeout.3pcap b/pcap_get_required_select_timeout.3pcap index b722a896..aa5d86f4 100644 --- a/pcap_get_required_select_timeout.3pcap +++ b/pcap_get_required_select_timeout.3pcap @@ -19,8 +19,8 @@ .\" .TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "25 July 2018" .SH NAME -pcap_get_required_select_timeout \- get a file descriptor on which a -select() can be done for a live capture +pcap_get_required_select_timeout \- get a timeout to be used when doing +select() for a live capture .SH SYNOPSIS .nf .ft B @@ -28,7 +28,7 @@ select() can be done for a live capture .ft .LP .ft B -struct timeval *pcap_get_required_select_timeout(pcap_t *p); +const struct timeval *pcap_get_required_select_timeout(pcap_t *p); .ft .fi .SH DESCRIPTION @@ -41,35 +41,78 @@ containing a value that must be used as the minimum timeout in .BR epoll_wait (2), and .BR kevent (2) -calls if +calls, or +.B NULL +if there is no such timeout. +If a +.RB non- NULL +value is returned, it must be used regardless of whether .BR pcap_get_selectable_fd (3PCAP) returns -.BR PCAP_ERROR . -.PP -The timeout that should be used in those calls must be no larger than -the smallest of all timeouts returned by -.BR \%pcap_get_required_select_timeout () -for devices from which packets will be captured. -.PP -The device for which -.BR pcap_get_selectable_fd () -returned -.B PCAP_ERROR -must be put in non-blocking mode with -.BR pcap_setnonblock (3PCAP), -and an attempt must always be made to read packets from the device -when the +.B \-1 +for any descriptor on which those calls are being done. +.BR pcap_get_required_select_timeout () +should be called for all +.BR pcap_t s +before a call to .BR select (), .BR poll (), .BR epoll_wait (), or -.BR kevent () -call returns. +.BR kevent (), +and any timeouts used for those calls should be updated as appropriate +given the new value of the timeout. +.PP +For +.BR kevent (), +one +.B EVFILT_TIMER +filter per selectable descriptor can be used, rather than using the +timeout argument to +.BR kevent (); +if the +.B EVFILT_TIMER +event for a particular selectable descriptor signals an event, +.BR pcap_dispatch (2) +should be called for the corresponding +.BR pcap_t . +.PP +On Linux systems with +.BR timerfd_create (2), +one timer object created by +.BR timerfd_create () +per selectable descriptor can be used, rather than using the timeout +argument to +.BR epoll_wait (); +if the +timer object for a particular selectable descriptor signals an event, +.BR pcap_dispatch (2) +should be called for the corresponding +.BR pcap_t . +.PP +Otherwise, a timeout value no larger than +the smallest of all timeouts returned by +.BR \%pcap_get_required_select_timeout () +for devices from which packets will be captured and any other timeouts +to be used in the call should be used as the timeout for the call, and, +when the call returns, +.BR pcap_dispatch (2) +should be called for all +.BR pcap_t s +for which a +.RB non- NULL +timeout was returned, regardless of whether it's indicated as having +anything to read from it or not. +.PP +All devices with a +.RB non-NULL +timeout must be put in non-blocking mode with +.BR pcap_setnonblock (3PCAP). .PP Note that a device on which a read can be done without blocking may, on some platforms, not have any packets to read if the packet buffer timeout has expired. A call to -.BR pcap_dispatch (3PCAP) +.BR pcap_dispatch () or .BR pcap_next_ex (3PCAP) will return 0 in this case, but will not block. @@ -93,6 +136,27 @@ and cannot be used on any capture source for which .BR pcap_get_selectable_fd () returns \-1. +.PP +In libpcap release 1.10.0 and later, the timeout value can change from +call to call, so +.BR pcap_get_required_select_timeout () +must be called before each call to +.BR select (), +.BR poll (), +.BR epoll_wait (), +or +.BR kevent (), +and the new value must be used to calculate timeouts for the call. Code +that does that will also work with libpcap 1.9.x releases, so code +using +.BR pcap_get_required_select_timeout () +should be changed to call it for each call to +.BR select (), +.BR poll (), +.BR epoll_wait (), +or +.BR kevent () +even if the code must also work with libpcap 1.9.x. .SH SEE ALSO .BR pcap (3PCAP), .BR pcap_get_selectable_fd (3PCAP), diff --git a/pcap_get_selectable_fd.3pcap b/pcap_get_selectable_fd.3pcap index 883aae8c..5e200dd7 100644 --- a/pcap_get_selectable_fd.3pcap +++ b/pcap_get_selectable_fd.3pcap @@ -43,7 +43,7 @@ do a or other such call to wait for it to be possible to read packets without blocking, if such a descriptor exists, or -.BR PCAP_ERROR , +.BR \-1 , if no such descriptor exists. .PP Some network devices opened with @@ -54,7 +54,7 @@ or with .BR pcap_open_live (3PCAP), do not support those calls (for example, regular network devices on FreeBSD 4.3 and 4.4, and Endace DAG devices), so -.B PCAP_ERROR +.B \-1 is returned for those devices. In that case, those calls must be given a timeout less than or equal to the timeout returned by @@ -62,7 +62,7 @@ than or equal to the timeout returned by for the device for which .BR pcap_get_selectable_fd () returned -.BR PCAP_ERROR , +.BR \-1 , the device must be put in non-blocking mode with a call to .BR \%pcap_setnonblock (3PCAP), and an attempt must always be made to read packets from the device @@ -145,7 +145,7 @@ work on that descriptor in Mac OS X 10.6 and later. is not available on Windows. .SH RETURN VALUE A selectable file descriptor is returned if one exists; otherwise, -.B PCAP_ERROR +.B \-1 is returned. .SH SEE ALSO .BR pcap (3PCAP), diff --git a/testprogs/selpolltest.c b/testprogs/selpolltest.c index 9ee01dda..569c8294 100644 --- a/testprogs/selpolltest.c +++ b/testprogs/selpolltest.c @@ -69,13 +69,13 @@ main(int argc, char **argv) register int op; bpf_u_int32 localnet, netmask; register char *cp, *cmdbuf, *device; - int doselect, dopoll, dotimeout, dononblock; + int doselect, dopoll, dotimeout, dononblock, quiet; const char *mechanism; struct bpf_program fcode; char ebuf[PCAP_ERRBUF_SIZE]; pcap_if_t *devlist; int selectable_fd; - struct timeval *required_timeout; + const struct timeval *required_timeout; int status; int packet_count; @@ -85,13 +85,14 @@ main(int argc, char **argv) mechanism = NULL; dotimeout = 0; dononblock = 0; + quiet = 0; if ((cp = strrchr(argv[0], '/')) != NULL) program_name = cp + 1; else program_name = argv[0]; opterr = 0; - while ((op = getopt(argc, argv, "i:sptn")) != -1) { + while ((op = getopt(argc, argv, "i:sptnq")) != -1) { switch (op) { case 'i': @@ -116,6 +117,10 @@ main(int argc, char **argv) dononblock = 1; break; + case 'q': + quiet = 1; + break; + default: usage(); /* NOTREACHED */ @@ -196,6 +201,7 @@ main(int argc, char **argv) for (;;) { fd_set setread, setexcept; struct timeval seltimeout; + struct timeval *timeoutp; FD_ZERO(&setread); if (selectable_fd != -1) { @@ -203,6 +209,7 @@ main(int argc, char **argv) FD_ZERO(&setexcept); FD_SET(selectable_fd, &setexcept); } + required_timeout = pcap_get_required_select_timeout(pd); if (dotimeout) { seltimeout.tv_sec = 0; if (required_timeout != NULL && @@ -210,37 +217,34 @@ main(int argc, char **argv) seltimeout.tv_usec = required_timeout->tv_usec; else seltimeout.tv_usec = 1000; - status = select(selectable_fd + 1, &setread, - NULL, &setexcept, &seltimeout); + timeoutp = &seltimeout; } else if (required_timeout != NULL) { seltimeout = *required_timeout; - status = select(selectable_fd + 1, &setread, - NULL, &setexcept, &seltimeout); + timeoutp = &seltimeout; } else { - status = select((selectable_fd == -1) ? - 0 : selectable_fd + 1, &setread, - NULL, &setexcept, NULL); + timeoutp = NULL; } + status = select((selectable_fd == -1) ? + 0 : selectable_fd + 1, &setread, NULL, &setexcept, + timeoutp); if (status == -1) { printf("Select returns error (%s)\n", strerror(errno)); } else { - if (selectable_fd == -1) { - if (status != 0) - printf("Select returned a descriptor\n"); - } else { + if (!quiet) { if (status == 0) printf("Select timed out: "); - else + else{ printf("Select returned a descriptor: "); - if (FD_ISSET(selectable_fd, &setread)) - printf("readable, "); - else - printf("not readable, "); - if (FD_ISSET(selectable_fd, &setexcept)) - printf("exceptional condition\n"); - else - printf("no exceptional condition\n"); + if (FD_ISSET(selectable_fd, &setread)) + printf("readable, "); + else + printf("not readable, "); + if (FD_ISSET(selectable_fd, &setexcept)) + printf("exceptional condition\n"); + else + printf("no exceptional condition\n"); + } } packet_count = 0; status = pcap_dispatch(pd, -1, countme, @@ -268,6 +272,7 @@ main(int argc, char **argv) fd.fd = selectable_fd; fd.events = POLLIN; + required_timeout = pcap_get_required_select_timeout(pd); if (dotimeout) polltimeout = 1; else if (required_timeout != NULL && @@ -280,10 +285,7 @@ main(int argc, char **argv) printf("Poll returns error (%s)\n", strerror(errno)); } else { - if (selectable_fd == -1) { - if (status != 0) - printf("Poll returned a descriptor\n"); - } else { + if (!quiet) { if (status == 0) printf("Poll timed out\n"); else { @@ -367,7 +369,7 @@ countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) static void usage(void) { - (void)fprintf(stderr, "Usage: %s [ -sptn ] [ -i interface ] [expression]\n", + (void)fprintf(stderr, "Usage: %s [ -sptnq ] [ -i interface ] [expression]\n", program_name); exit(1); } |