diff options
-rw-r--r-- | acinclude.m4 | 1 | ||||
-rw-r--r-- | capture_loop.c | 84 |
2 files changed, 53 insertions, 32 deletions
diff --git a/acinclude.m4 b/acinclude.m4 index 334c13d7c9..f60a387d49 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -469,6 +469,7 @@ and did you also install that package?]])) [Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that declares pcap_if_t.]) AC_CHECK_FUNCS(pcap_datalink_val_to_name pcap_datalink_name_to_val) AC_CHECK_FUNCS(pcap_list_datalinks pcap_set_datalink pcap_lib_version) + AC_CHECK_FUNCS(pcap_get_selectable_fd) fi LIBS="$ac_save_LIBS" ]) diff --git a/capture_loop.c b/capture_loop.c index 906bdf0656..fd1a6c53b1 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -671,7 +671,13 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, } #ifdef MUST_DO_SELECT - if (!ld->from_cap_pipe) ld->pcap_fd = pcap_fileno(ld->pcap_h); + 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()" @@ -864,8 +870,8 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, #endif #ifndef _WIN32 - /* dispatch from capture pipe */ if (ld->from_cap_pipe) { + /* dispatch from capture pipe */ FD_ZERO(&set1); FD_SET(ld->cap_pipe_fd, &set1); timeout.tv_sec = 0; @@ -893,7 +899,7 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, else #endif /* _WIN32 */ { - /* dispatch from pcap using select */ + /* dispatch from pcap */ #ifdef MUST_DO_SELECT /* * Sigh. The semantics of the read timeout argument to @@ -921,39 +927,53 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, * 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. */ - 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, capture_loop_packet_cb, (gchar *)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)); - capture_loop_popup_errmsg(capture_opts, errmsg); - 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, capture_loop_packet_cb, (gchar *)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)); + capture_loop_popup_errmsg(capture_opts, errmsg); + ld->go = FALSE; + } } } -#else - /* dispatch from pcap without select */ - inpkts = pcap_dispatch(ld->pcap_h, 1, capture_loop_packet_cb, (gchar *) ld); - if (inpkts < 0) { - ld->pcap_err = TRUE; - ld->go = FALSE; - } + else #endif /* MUST_DO_SELECT */ + { + /* dispatch from pcap without select */ + inpkts = pcap_dispatch(ld->pcap_h, 1, capture_loop_packet_cb, (gchar *) ld); + if (inpkts < 0) { + ld->pcap_err = TRUE; + ld->go = FALSE; + } + } } return inpkts; |