*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* Standard secondary message for unexpected errors.
*/
static const char please_report[] =
- "Please report this to the Ethereal developers";
+ "Please report this to the Wireshark developers";
/*
* This needs to be static, so that the SIGUSR1 handler can clear the "go"
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
/*
- * XXX (T)Ethereal blocks until we return
+ * XXX (T)Wireshark blocks until we return
*/
if (strcmp(pipename, "-") == 0)
fd = 0; /* read from stdin */
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface);
-/* XXX - opening Winsock on tethereal? */
+/* XXX - opening Winsock on twireshark? */
/* Initialize Windows Socket if we are in a WIN32 OS
This needs to be done before querying the interface for network/netmask */
"\n"
"Help can be found at:\n"
"\n"
-" http://wiki.ethereal.com/CaptureSetup\n"
+" http://wiki.wireshark.org/CaptureSetup\n"
"\n"
"64-bit Windows:\n"
"WinPcap does not support 64-bit Windows; you will have to use some other\n"
/* Pipe doesn't exist, so output message for interface */
/* If we got a "can't find PPA for X" message, warn the user (who
- is running (T)Ethereal on HP-UX) that they don't have a version
+ is running (T)Wireshark on HP-UX) that they don't have a version
of libpcap that properly handles HP-UX (libpcap 0.6.x and later
versions, which properly handle HP-UX, say "can't find /dev/dlpi
PPA for X" rather than "can't find PPA for X"). */
if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
libpcap_warn =
"\n\n"
- "You are running (T)Ethereal with a version of the libpcap library\n"
+ "You are running (T)Wireshark with a version of the libpcap library\n"
"that doesn't handle HP-UX network devices well; this means that\n"
- "(T)Ethereal may not be able to capture packets.\n"
+ "(T)Wireshark may not be able to capture packets.\n"
"\n"
"To fix this, you should install libpcap 0.6.2, or a later version\n"
"of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
#endif
}
-/* XXX - will this work for tethereal? */
+/* XXX - will this work for twireshark? */
#ifdef MUST_DO_SELECT
if (!ld->from_cap_pipe) {
#ifdef HAVE_PCAP_GET_SELECTABLE_FD
if (ld->pdh == NULL) {
/* We couldn't set up to write to the capture file. */
- /* XXX - use cf_open_error_message from tethereal instead? */
+ /* XXX - use cf_open_error_message from twireshark instead? */
switch (err) {
case WTAP_ERR_CANT_OPEN:
#endif
#ifndef _WIN32
- if (ld->from_cap_pipe) {
- /* dispatch from capture pipe */
+ if (ld->from_cap_pipe) {
+ /* dispatch from capture pipe */
#ifdef LOG_CAPTURE_VERBOSE
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
#endif
+ FD_ZERO(&set1);
+ FD_SET(ld->cap_pipe_fd, &set1);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = CAP_READ_TIMEOUT*1000;
+ sel_ret = select(ld->cap_pipe_fd+1, &set1, NULL, NULL, &timeout);
+ if (sel_ret <= 0) {
+ 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 {
+ /*
+ * "select()" says we can read from the pipe without blocking
+ */
+ inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
+ if (inpkts < 0) {
+ ld->go = FALSE;
+ }
+ }
+ }
+ else
+#endif /* _WIN32 */
+ {
+ /* dispatch from pcap */
+#ifdef MUST_DO_SELECT
+ /*
+ * 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 it might not be possible
+ * to stop a capture until a packet arrives. If that's unacceptable,
+ * plead with whoever supplies the software for that device to add
+ * "select()" support, or upgrade to libpcap 0.8.1 or later, and
+ * rebuild Wireshark or get a version built with libpcap 0.8.1 or
+ * later, so it can use pcap_breakloop().
+ */
+#ifdef LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select");
+#endif
+ if (ld->pcap_fd != -1) {
FD_ZERO(&set1);
- FD_SET(ld->cap_pipe_fd, &set1);
- timeout.tv_sec = 0;
- timeout.tv_usec = CAP_READ_TIMEOUT*1000;
- sel_ret = select(ld->cap_pipe_fd+1, &set1, NULL, NULL, &timeout);
- if (sel_ret <= 0) {
- inpkts = 0;
+ FD_SET(ld->pcap_fd, &set1);
+ sel_ret = select(ld->pcap_fd+1, &set1, NULL, NULL, NULL);
+ if (sel_ret > 0) {
+ /*
+ * "select()" says we can read from it without blocking; go for
+ * it.
+ *
+ * We don't have pcap_breakloop(), so we only process one packet
+ * per pcap_dispatch() call, to allow a signal to stop the
+ * processing immediately, rather than processing all packets
+ * in a batch before quitting.
+ */
+ inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld);
+ if (inpkts < 0) {
+ ld->pcap_err = TRUE;
+ ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
+ }
+ } 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 {
- /*
- * "select()" says we can read from the pipe without blocking
- */
- inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
- if (inpkts < 0) {
- ld->go = FALSE;
- }
}
}
else
-#endif /* _WIN32 */
- {
- /* dispatch from pcap */
-#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 with select");
-#endif
- 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 */
+ {
+ /* 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");
+ 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) {
+#ifdef _WIN32
+ /*
+ * On Windows, we don't support asynchronously telling a process to
+ * stop capturing; instead, we check for an indication on a pipe
+ * after processing packets. We therefore process only one packet
+ * at a time, so that we can check the pipe after every packet.
+ */
+ inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld);
+#else
+ inpkts = pcap_dispatch(ld->pcap_h, -1, ld->packet_cb, (u_char *) ld);
+#endif
+ if (inpkts < 0) {
+ if (inpkts == -1) {
+ /* Error, rather than pcap_breakloop(). */
ld->pcap_err = TRUE;
- ld->go = FALSE;
}
-#else
- {
+ ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
+ }
+#else /* pcap_next_ex */
#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() */
-
- /* 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} */
+ /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */
- /* emulate dispatch from pcap */
- int in;
- struct pcap_pkthdr *pkt_header;
- u_char *pkt_data;
+ /*
+ * WinPcap's remote capturing feature doesn't work with pcap_dispatch(),
+ * see http://wiki.wireshark.org/CaptureSetup_2fWinPcapRemote
+ * This should be fixed in the WinPcap 4.0 alpha release.
+ *
+ * For reference, an example remote interface:
+ * rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C}
+ */
- 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;
+
+ inpkts = 0;
+ in = 0;
+ while(ld->go &&
+ (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;
- }
+ if(in < 0) {
+ ld->pcap_err = TRUE;
+ ld->go = FALSE;
+ inpkts = in;
}
-#endif
}
+#endif /* pcap_next_ex */
}
+ }
#ifdef LOG_CAPTURE_VERBOSE
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
#endif
- return inpkts;
+ return inpkts;
}
int
capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
{
+#ifndef _WIN32
+ struct sigaction act;
+#endif
time_t upd_time, cur_time;
time_t start_time;
int err_close;
* Catch SIGUSR1, so that we exit cleanly if the parent process
* kills us with it due to the user selecting "Capture->Stop".
*/
- signal(SIGUSR1, capture_loop_stop_signal_handler);
-#endif
+ act.sa_handler = capture_loop_stop_signal_handler;
+ /*
+ * Arrange that system calls not get restarted, because when
+ * our signal handler returns we don't want to restart
+ * a call that was waiting for packets to arrive.
+ */
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGUSR1, &act, NULL);
+#endif /* _WIN32 */
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop starting ...");
capture_opts_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, capture_opts);
void capture_loop_stop(void)
{
- ld.go = FALSE;
+#ifdef HAVE_PCAP_BREAKLOOP
+ pcap_breakloop(ld.pcap_h);
+#else
+ ld.go = FALSE;
+#endif
}
}
#endif /* HAVE_LIBPCAP */
-