diff options
author | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2006-05-20 23:18:44 +0000 |
---|---|---|
committer | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2006-05-20 23:18:44 +0000 |
commit | 93d38cd7b4d3ca5ae16f36150a0999fab4349d13 (patch) | |
tree | 2fe596603e8f0e72050cb1a141aba73cfec7b0f4 | |
parent | 8a8cc789d7881571bcc31d27f493b6645d729bc4 (diff) |
The timeout is needed if you don't have pcap_breakloop(), so we'll put
it back for now; I'll fix it later not to do the timeout if we have
pcap_breakloop().
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@18195 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r-- | capture_loop.c | 138 | ||||
-rw-r--r-- | capture_loop.h | 26 |
2 files changed, 138 insertions, 26 deletions
diff --git a/capture_loop.c b/capture_loop.c index d87854f534..16d32bb350 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -628,6 +628,17 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, #endif } +/* XXX - will this work for tethereal? */ +#ifdef MUST_DO_SELECT + if (!ld->from_cap_pipe) { +#ifdef HAVE_PCAP_GET_SELECTABLE_FD + ld->pcap_fd = pcap_get_selectable_fd(ld->pcap_h); +#else + ld->pcap_fd = pcap_fileno(ld->pcap_h); +#endif + } +#endif + /* Does "open_err_str" contain a non-empty string? If so, "pcap_open_live()" returned a warning; print it, but keep capturing. */ if (open_err_str[0] != '\0') { @@ -832,43 +843,115 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld, #endif /* _WIN32 */ { /* dispatch from pcap */ -#if 1 +#ifdef MUST_DO_SELECT + /* + * Sigh. The semantics of the read timeout argument to + * "pcap_open_live()" aren't particularly well specified by + * the "pcap" man page - at least with the BSD BPF code, the + * intent appears to be, at least in part, a way of cutting + * down the number of reads done on a capture, by blocking + * until the buffer fills or a timer expires - and the Linux + * libpcap doesn't actually support it, so we can't use it + * to break out of the "pcap_dispatch()" every 1/4 of a second + * or so. Linux's libpcap is not the only libpcap that doesn't + * support the read timeout. + * + * Furthermore, at least on Solaris, the bufmod STREAMS module's + * read timeout won't go off if no data has arrived, i.e. it cannot + * be used to guarantee that a read from a DLPI stream will return + * within a specified amount of time regardless of whether any + * data arrives or not. + * + * Thus, on all platforms other than BSD, we do a "select()" on the + * file descriptor for the capture, with a timeout of CAP_READ_TIMEOUT + * milliseconds, or CAP_READ_TIMEOUT*1000 microseconds. + * + * "select()", on BPF devices, doesn't work as you might expect; + * at least on some versions of some flavors of BSD, the timer + * doesn't start until a read is done, so it won't expire if + * only a "select()" or "poll()" is posted. + * + * If we have "pcap_get_selectable_fd()", we use it to get the + * descriptor on which to select; if that's -1, it means there + * is no descriptor on which you can do a "select()" (perhaps + * because you're capturing on a special device, and that device's + * driver unfortunately doesn't support "select()", in which case + * we don't do the select - which means Ethereal might block, + * unable to accept user input, until a packet arrives. If + * that's unacceptable, plead with whoever supplies the software + * for that device to add "select()" support. + */ #ifdef LOG_CAPTURE_VERBOSE - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch"); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select"); #endif - inpkts = pcap_dispatch(ld->pcap_h, -1, ld->packet_cb, (u_char *) ld); - if (inpkts < 0) { - ld->pcap_err = TRUE; - ld->go = FALSE; + if (ld->pcap_fd != -1) { + FD_ZERO(&set1); + FD_SET(ld->pcap_fd, &set1); + timeout.tv_sec = 0; + timeout.tv_usec = CAP_READ_TIMEOUT*1000; + sel_ret = select(ld->pcap_fd+1, &set1, NULL, NULL, &timeout); + if (sel_ret > 0) { + /* + * "select()" says we can read from it without blocking; go for + * it. + */ + inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld); + if (inpkts < 0) { + ld->pcap_err = TRUE; + ld->go = FALSE; + } + } else { + inpkts = 0; + if (sel_ret < 0 && errno != EINTR) { + g_snprintf(errmsg, errmsg_len, + "Unexpected error from select: %s", strerror(errno)); + report_capture_error(errmsg, please_report); + ld->go = FALSE; + } + } } + else +#endif /* MUST_DO_SELECT */ + { + /* dispatch from pcap without select */ +#if 1 +#ifdef LOG_CAPTURE_VERBOSE + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch"); +#endif + inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld); + if (inpkts < 0) { + ld->pcap_err = TRUE; + ld->go = FALSE; + } #else + { #ifdef LOG_CAPTURE_VERBOSE - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_next_ex"); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_next_ex"); #endif - /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */ + /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */ - /* WinPcap's remote capturing feature doesn't work, see http://wiki.ethereal.com/CaptureSetup_2fWinPcapRemote */ - /* for reference, an example remote interface: rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C} */ + /* WinPcap's remote capturing feature doesn't work, see http://wiki.ethereal.com/CaptureSetup_2fWinPcapRemote */ + /* for reference, an example remote interface: rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C} */ - /* emulate dispatch from pcap */ - { - int in; - struct pcap_pkthdr *pkt_header; - u_char *pkt_data; - - inpkts = 0; - while( (in = pcap_next_ex(ld->pcap_h, &pkt_header, &pkt_data)) == 1) { - ld->packet_cb( (u_char *) ld, pkt_header, pkt_data); - inpkts++; - } + /* emulate dispatch from pcap */ + int in; + struct pcap_pkthdr *pkt_header; + u_char *pkt_data; - if(in < 0) { - ld->pcap_err = TRUE; - ld->go = FALSE; - inpkts = in; + inpkts = 0; + while( (in = pcap_next_ex(ld->pcap_h, &pkt_header, &pkt_data)) == 1) { + ld->packet_cb( (u_char *) ld, pkt_header, pkt_data); + inpkts++; + } + + if(in < 0) { + ld->pcap_err = TRUE; + ld->go = FALSE; + inpkts = in; + } } - } #endif + } } #ifdef LOG_CAPTURE_VERBOSE @@ -1019,6 +1102,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct #ifndef _WIN32 ld.cap_pipe_fd = -1; #endif +#ifdef MUST_DO_SELECT + ld.pcap_fd = 0; +#endif ld.packet_cb = capture_loop_packet_cb; diff --git a/capture_loop.h b/capture_loop.h index 4d2778793b..c0a91e2e24 100644 --- a/capture_loop.h +++ b/capture_loop.h @@ -51,6 +51,29 @@ extern void capture_loop_stop(void); /*** the following is internal only (should be moved to capture_loop_int.h) ***/ +/* + * We don't want to do a "select()" on the pcap_t's file descriptor on + * BSD (because "select()" doesn't work correctly on BPF devices on at + * least some releases of some flavors of BSD), and we don't want to do + * it on Windows (because "select()" is something for sockets, not for + * arbitrary handles). (Note that "Windows" here includes Cygwin; + * even in its pretend-it's-UNIX environment, we're using WinPcap, not + * a UNIX libpcap.) + * + * We *do* want to do it on other platforms, as, on other platforms (with + * the possible exception of Ultrix and Digital UNIX), the read timeout + * doesn't expire if no packets have arrived, so a "pcap_dispatch()" call + * will block until packets arrive, causing the UI to hang. + * + * XXX - the various BSDs appear to define BSD in <sys/param.h>; we don't + * want to include it if it's not present on this platform, however. + */ +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \ + !defined(__bsdi__) && !defined(__APPLE__) && !defined(_WIN32) && \ + !defined(__CYGWIN__) +# define MUST_DO_SELECT +#endif + typedef void (*capture_packet_cb_fct)(u_char *, const struct pcap_pkthdr *, const u_char *); @@ -72,6 +95,9 @@ typedef struct _loop_data { /* pcap "input file" */ pcap_t *pcap_h; /* pcap handle */ gboolean pcap_err; /* E: TRUE if error from pcap */ +#ifdef MUST_DO_SELECT + int pcap_fd; /* pcap file descriptor */ +#endif /* capture pipe (unix only "input file") */ gboolean from_cap_pipe; /* TRUE if we are capturing data from a capture pipe */ |