/* capture.c
* Routines for packet capture windows
*
- * $Id: capture.c,v 1.14 1998/12/22 05:52:48 gram Exp $
+ * $Id: capture.c,v 1.95 2000/02/09 19:17:50 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
# include "config.h"
#endif
+#ifdef HAVE_LIBPCAP
+
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
-#include <gtk/gtk.h>
-#include <pcap.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include <gtk/gtk.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
#include <string.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
+
+#include <time.h>
+
+#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
#include <net/if.h>
+#endif
+
+#include <signal.h>
+#include <errno.h>
#ifdef NEED_SNPRINTF_H
# ifdef HAVE_STDARG_H
# include "snprintf.h"
#endif
-#ifdef HAVE_SYS_SOCKIO_H
-# include <sys/sockio.h>
+#ifndef lib_pcap_h
+#include <pcap.h>
#endif
-#include "ethereal.h"
+#include "gtk/main.h"
+#include "gtk/gtkglobals.h"
#include "packet.h"
#include "file.h"
#include "capture.h"
-#include "etypes.h"
#include "util.h"
+#include "simple_dialog.h"
#include "prefs.h"
+#include "globals.h"
+
+int sync_mode; /* fork a child to do the capture, and sync between them */
+static int sync_pipe[2]; /* used to sync father */
+int quit_after_cap; /* Makes a "capture only mode". Implies -k */
+gboolean capture_child; /* if this is the child for "-S" */
+static guint cap_input_id;
+
+static void cap_file_input_cb(gpointer, gint, GdkInputCondition);
+static void capture_delete_cb(GtkWidget *, GdkEvent *, gpointer);
+static void capture_stop_cb(GtkWidget *, gpointer);
+static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+static float pct(gint, gint);
+
+typedef struct _loop_data {
+ gint go;
+ gint max;
+ gint linktype;
+ gint sync_packets;
+ packet_counts counts;
+ wtap_dumper *pdh;
+} loop_data;
+
+/* Win32 needs the O_BINARY flag for open() */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
-extern capture_file cf;
-extern GtkWidget *info_bar;
-extern guint file_ctx;
-
-/* File selection data keys */
-#define E_CAP_PREP_FS_KEY "cap_prep_fs"
-#define E_CAP_PREP_TE_KEY "cap_prep_te"
-
-/* Capture callback data keys */
-#define E_CAP_IFACE_KEY "cap_iface"
-#define E_CAP_FILT_KEY "cap_filter"
-#define E_CAP_FILE_KEY "cap_file"
-#define E_CAP_COUNT_KEY "cap_count"
-#define E_CAP_OPEN_KEY "cap_open"
-#define E_CAP_SNAP_KEY "cap_snap"
-
-/* Capture filter key */
-#define E_CAP_FILT_TE_KEY "cap_filt_te"
-
-GList *
-get_interface_list() {
- GList *il = NULL;
- struct ifreq *ifr, *last;
- struct ifconf ifc;
- int sock = socket(AF_INET, SOCK_DGRAM, 0);
-
- if (sock < 0)
- {
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Can't list interfaces: error opening socket.");
- return NULL;
+/* Open a specified file, or create a temporary file, and start a capture
+ to the file in question. */
+void
+do_capture(char *capfile_name)
+{
+ char tmpname[128+1];
+ gboolean is_tempfile;
+ u_char c;
+ int i;
+ guint byte_count;
+ char *msg;
+ int err;
+ int capture_succeeded;
+
+ if (capfile_name != NULL) {
+ /* Try to open/create the specified file for use as a capture buffer. */
+ cf.save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
+ is_tempfile = FALSE;
+ } else {
+ /* Choose a random name for the capture buffer */
+ cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
+ capfile_name = g_strdup(tmpname);
+ is_tempfile = TRUE;
}
-
- /* Since we have to grab the interface list all at once, we'll make
- plenty of room */
- ifc.ifc_len = 1024 * sizeof(struct ifreq);
- ifc.ifc_buf = malloc(ifc.ifc_len);
-
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
- ifc.ifc_len < sizeof(struct ifreq))
- {
+ if (cf.save_file_fd == -1) {
simple_dialog(ESD_TYPE_WARN, NULL,
- "Can't list interfaces: ioctl error.");
- return NULL;
+ "The file to which the capture would be saved (\"%s\")"
+ "could not be opened: %s.", capfile_name, strerror(errno));
+ return;
}
-
- ifr = (struct ifreq *) ifc.ifc_req;
- last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
- while (ifr < last)
- {
- /*
- * What we want:
- * - Interfaces that are up, and not loopback
- * - IP interfaces (do we really need this?)
- * - Anything that doesn't begin with "lo" (loopback again) or "dummy"
- * - Anything that doesn't include a ":" (Solaris virtuals)
- */
- if (! (ifr->ifr_flags & (IFF_UP | IFF_LOOPBACK)) &&
- (ifr->ifr_addr.sa_family == AF_INET) &&
- strncmp(ifr->ifr_name, "lo", 2) &&
- strncmp(ifr->ifr_name, "dummy", 5) &&
- ! strchr(ifr->ifr_name, ':')) {
- il = g_list_append(il, g_strdup(ifr->ifr_name));
+ close_cap_file(&cf, info_bar);
+ g_assert(cf.save_file == NULL);
+ cf.save_file = capfile_name;
+
+ if (sync_mode) { /* use fork() for capture */
+#ifndef _WIN32
+ int fork_child;
+ char ssnap[24];
+ char scount[24]; /* need a constant for len of numbers */
+ char save_file_fd[24];
+
+ sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
+ sprintf(scount,"%d",cf.count);
+ sprintf(save_file_fd,"%d",cf.save_file_fd);
+ signal(SIGCHLD, SIG_IGN);
+ pipe(sync_pipe);
+ if ((fork_child = fork()) == 0) {
+ /*
+ * Child process - run Ethereal with the right arguments to make
+ * it just pop up the live capture dialog box and capture with
+ * the specified capture parameters, writing to the specified file.
+ *
+ * args: -i interface specification
+ * -w file to write
+ * -W file descriptor to write
+ * -c count to capture
+ * -s snaplen
+ * -m / -b fonts
+ * -f "filter expression"
+ */
+ close(1);
+ dup(sync_pipe[1]);
+ close(sync_pipe[0]);
+ execlp(ethereal_path, CHILD_NAME, "-i", cf.iface,
+ "-w", cf.save_file, "-W", save_file_fd,
+ "-c", scount, "-s", ssnap,
+ "-m", medium_font, "-b", bold_font,
+ (cf.cfilter == NULL)? 0 : "-f",
+ (cf.cfilter == NULL)? 0 : cf.cfilter,
+ (const char *)NULL);
+ } else {
+ /* Parent process - read messages from the child process over the
+ sync pipe. */
+ close(sync_pipe[1]);
+
+ /* Read a byte count from "sync_pipe[0]", terminated with a
+ colon; if the count is 0, the child process created the
+ capture file and we should start reading from it, otherwise
+ the capture couldn't start and the count is a count of bytes
+ of error message, and we should display the message. */
+ byte_count = 0;
+ for (;;) {
+ i = read(sync_pipe[0], &c, 1);
+ if (i == 0) {
+ /* EOF - the child process died.
+ Close the read side of the sync pipe, remove the capture file,
+ and report the failure.
+ XXX - reap the child process and report the status in detail. */
+ close(sync_pipe[0]);
+ unlink(cf.save_file);
+ g_free(cf.save_file);
+ cf.save_file = NULL;
+ simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
+ return;
+ }
+ if (c == ';')
+ break;
+ if (!isdigit(c)) {
+ /* Child process handed us crap.
+ Close the read side of the sync pipe, remove the capture file,
+ and report the failure. */
+ close(sync_pipe[0]);
+ unlink(cf.save_file);
+ g_free(cf.save_file);
+ cf.save_file = NULL;
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Capture child process sent us a bad message");
+ return;
+ }
+ byte_count = byte_count*10 + c - '0';
+ }
+ if (byte_count == 0) {
+ /* Success. Open the capture file, and set up to read it. */
+ err = start_tail_cap_file(cf.save_file, is_tempfile, &cf);
+ if (err == 0) {
+ /* We were able to open and set up to read the capture file;
+ arrange that our callback be called whenever it's possible
+ to read from the sync pipe, so that it's called when
+ the child process wants to tell us something. */
+ cap_input_id = gtk_input_add_full(sync_pipe[0],
+ GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
+ cap_file_input_cb,
+ NULL,
+ (gpointer) &cf,
+ NULL);
+ } else {
+ /* We weren't able to open the capture file; complain, and
+ close the sync pipe. */
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(err, FALSE), cf.save_file);
+
+ /* Close the sync pipe. */
+ close(sync_pipe[0]);
+
+ /* Don't unlink the save file - leave it around, for debugging
+ purposes. */
+ g_free(cf.save_file);
+ cf.save_file = NULL;
+ }
+ } else {
+ /* Failure - the child process sent us a message indicating
+ what the problem was. */
+ msg = g_malloc(byte_count + 1);
+ if (msg == NULL) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Capture child process failed, but its error message was too big.");
+ } else {
+ i = read(sync_pipe[0], msg, byte_count);
+ if (i < 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Capture child process failed: Error %s reading its error message.",
+ strerror(errno));
+ } else if (i == 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Capture child process failed: EOF reading its error message.");
+ } else
+ simple_dialog(ESD_TYPE_WARN, NULL, msg);
+ g_free(msg);
+
+ /* Close the sync pipe. */
+ close(sync_pipe[0]);
+
+ /* Get rid of the save file - the capture never started. */
+ unlink(cf.save_file);
+ g_free(cf.save_file);
+ cf.save_file = NULL;
+ }
+ }
}
-#ifdef HAVE_SA_LEN
- ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
-#else
- ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
#endif
+ } else {
+ /* Not sync mode. */
+ capture_succeeded = capture();
+ if (quit_after_cap) {
+ /* DON'T unlink the save file. Presumably someone wants it. */
+ gtk_exit(0);
+ }
+ if (capture_succeeded) {
+ /* Capture succeeded; read in the capture file. */
+ if ((err = open_cap_file(cf.save_file, is_tempfile, &cf)) == 0) {
+ /* Set the read filter to NULL. */
+ cf.rfcode = NULL;
+ err = read_cap_file(&cf);
+ }
+ }
+ /* We're not doing a capture any more, so we don't have a save
+ file. */
+ g_free(cf.save_file);
+ cf.save_file = NULL;
}
-
- free(ifc.ifc_buf);
- return il;
}
-void
-capture_prep_cb(GtkWidget *w, gpointer d) {
- GtkWidget *cap_open_w, *if_cb, *if_lb, *file_te, *file_bt,
- *count_lb, *count_cb, *main_vb, *if_hb, *count_hb,
- *filter_hb, *filter_bt, *filter_te, *file_hb, *caplen_hb,
- *bbox, *ok_bt, *cancel_bt, *capfile_ck, *snap_lb,
- *snap_sb;
- GtkAdjustment *adj;
- GList *if_list, *count_list = NULL;
- gchar *count_item1 = "0 (Infinite)", count_item2[16];
-
- cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences");
-
- /* Container for each row of widgets */
- main_vb = gtk_vbox_new(FALSE, 3);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* Interface row */
- if_hb = gtk_hbox_new(FALSE, 3);
- gtk_container_add(GTK_CONTAINER(main_vb), if_hb);
- gtk_widget_show(if_hb);
-
- if_lb = gtk_label_new("Interface:");
- gtk_box_pack_start(GTK_BOX(if_hb), if_lb, FALSE, FALSE, 0);
- gtk_widget_show(if_lb);
-
- if_list = get_interface_list();
-
- if_cb = gtk_combo_new();
- gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
- if (cf.iface)
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cf.iface);
- else if (if_list)
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data);
- gtk_box_pack_start(GTK_BOX(if_hb), if_cb, FALSE, FALSE, 0);
- gtk_widget_show(if_cb);
-
- while (if_list) {
- g_free(if_list->data);
- if_list = g_list_remove_link(if_list, if_list);
- }
+#ifndef _WIN32
+/* There's stuff to read from the sync pipe, meaning the child has sent
+ us a message, or the sync pipe has closed, meaning the child has
+ closed it (perhaps because it exited). */
+static void
+cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition)
+{
+ capture_file *cf = (capture_file *)data;
+ char buffer[256+1], *p = buffer, *q = buffer;
+ int nread;
+ int to_read = 0;
+ gboolean exit_loop = FALSE;
+ int err;
+ int wstatus;
+ int wsignal;
+ char *msg;
+ char *sigmsg;
+ char sigmsg_buf[6+1+3+1];
+ char *coredumped;
+
+ /* avoid reentrancy problems and stack overflow */
+ gtk_input_remove(cap_input_id);
+
+ if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
+ /* The child has closed the sync pipe, meaning it's not going to be
+ capturing any more packets. Pick up its exit status, and
+ complain if it died of a signal. */
+ if (wait(&wstatus) != -1) {
+ /* XXX - are there any platforms on which we can run that *don't*
+ support POSIX.1's <sys/wait.h> and macros therein? */
+ wsignal = wstatus & 0177;
+ coredumped = "";
+ if (wstatus == 0177) {
+ /* It stopped, rather than exiting. "Should not happen." */
+ msg = "stopped";
+ wsignal = (wstatus >> 8) & 0xFF;
+ } else {
+ msg = "terminated";
+ if (wstatus & 0200)
+ coredumped = " - core dumped";
+ }
+ if (wsignal != 0) {
+ switch (wsignal) {
- /* Count row */
- count_hb = gtk_hbox_new(FALSE, 3);
- gtk_container_add(GTK_CONTAINER(main_vb), count_hb);
- gtk_widget_show(count_hb);
-
- count_lb = gtk_label_new("Count:");
- gtk_box_pack_start(GTK_BOX(count_hb), count_lb, FALSE, FALSE, 0);
- gtk_widget_show(count_lb);
-
- if (cf.count) {
- snprintf(count_item2, 15, "%d", cf.count);
- count_list = g_list_append(count_list, count_item2);
- }
- count_list = g_list_append(count_list, count_item1);
+ case SIGHUP:
+ sigmsg = "Hangup";
+ break;
- count_cb = gtk_combo_new();
- gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list);
- gtk_box_pack_start(GTK_BOX(count_hb), count_cb, FALSE, FALSE, 0);
- gtk_widget_show(count_cb);
+ case SIGINT:
+ sigmsg = "Interrupted";
+ break;
- while (count_list)
- count_list = g_list_remove_link(count_list, count_list);
+ case SIGQUIT:
+ sigmsg = "Quit";
+ break;
- /* Filter row */
- filter_hb = gtk_hbox_new(FALSE, 3);
- gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
- gtk_widget_show(filter_hb);
-
- filter_bt = gtk_button_new_with_label("Filter:");
- gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
- GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
- gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
- gtk_widget_show(filter_bt);
-#ifdef WITH_WIRETAP
- gtk_widget_set_sensitive(filter_bt, FALSE);
-#endif
-
- filter_te = gtk_entry_new();
- if (cf.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.cfilter);
- gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
- gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
- gtk_widget_show(filter_te);
-#ifdef WITH_WIRETAP
- gtk_widget_set_sensitive(filter_te, FALSE);
- gtk_entry_set_text(GTK_ENTRY(filter_te), "<unavailable>");
-#endif
-
- /* File row: File: button and text entry */
- file_hb = gtk_hbox_new(FALSE, 3);
- gtk_container_add(GTK_CONTAINER(main_vb), file_hb);
- gtk_widget_show(file_hb);
-
- file_bt = gtk_button_new_with_label("File:");
- gtk_box_pack_start(GTK_BOX(file_hb), file_bt, FALSE, FALSE, 0);
- gtk_widget_show(file_bt);
-
- file_te = gtk_entry_new();
- if (cf.save_file)
- gtk_entry_set_text(GTK_ENTRY(file_te), cf.save_file);
- gtk_box_pack_start(GTK_BOX(file_hb), file_te, TRUE, TRUE, 0);
- gtk_widget_show(file_te);
-
- gtk_signal_connect_object(GTK_OBJECT(file_bt), "clicked",
- GTK_SIGNAL_FUNC(capture_prep_file_cb), GTK_OBJECT(file_te));
-
- /* Misc row: Capture file checkbox and snap spinbutton */
- caplen_hb = gtk_hbox_new(FALSE, 3);
- gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
- gtk_widget_show(caplen_hb);
-
- capfile_ck = gtk_check_button_new_with_label("Open file after capture");
- gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(capfile_ck), TRUE);
- gtk_box_pack_start(GTK_BOX(caplen_hb), capfile_ck, FALSE, FALSE, 3);
- gtk_widget_show(capfile_ck);
-
- snap_lb = gtk_label_new("Capture length");
- gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
- gtk_widget_show(snap_lb);
-
- adj = (GtkAdjustment *) gtk_adjustment_new((float) cf.snap, 1.0, 4096.0,
- 1.0, 10.0, 0.0);
- snap_sb = gtk_spin_button_new (adj, 0, 0);
- gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
- gtk_widget_set_usize (snap_sb, 80, 0);
- gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3);
- gtk_widget_show(snap_sb);
-
- /* Button row: OK and cancel buttons */
- bbox = gtk_hbutton_box_new();
- gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
- gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
- gtk_container_add(GTK_CONTAINER(main_vb), bbox);
- gtk_widget_show(bbox);
-
- ok_bt = gtk_button_new_with_label ("OK");
- gtk_signal_connect_object(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w));
- GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
- gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
- gtk_widget_grab_default(ok_bt);
- gtk_widget_show(ok_bt);
-
- cancel_bt = gtk_button_new_with_label ("Cancel");
- gtk_signal_connect_object(GTK_OBJECT(cancel_bt), "clicked",
- GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w));
- GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
- gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
- gtk_widget_show(cancel_bt);
-
- /* Attach pointers to needed widgets to the capture prefs window/object */
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_IFACE_KEY, if_cb);
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILT_KEY, filter_te);
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILE_KEY, file_te);
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_COUNT_KEY, count_cb);
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_OPEN_KEY, capfile_ck);
- gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SNAP_KEY, snap_sb);
-
- gtk_widget_show(cap_open_w);
-}
+ case SIGILL:
+ sigmsg = "Illegal instruction";
+ break;
-void
-capture_prep_file_cb(GtkWidget *w, gpointer te) {
- GtkWidget *fs;
+ case SIGTRAP:
+ sigmsg = "Trace trap";
+ break;
- fs = gtk_file_selection_new ("Ethereal: Open Save File");
+ case SIGABRT:
+ sigmsg = "Abort";
+ break;
- gtk_object_set_data(GTK_OBJECT(w), E_CAP_PREP_FS_KEY, fs);
- gtk_object_set_data(GTK_OBJECT(w), E_CAP_PREP_TE_KEY, (GtkWidget *) te);
-
- gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
- "clicked", (GtkSignalFunc) cap_prep_fs_ok_cb, w);
+ case SIGFPE:
+ sigmsg = "Arithmetic exception";
+ break;
- /* Connect the cancel_button to destroy the widget */
- gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
- "clicked", (GtkSignalFunc) cap_prep_fs_cancel_cb, w);
-
- gtk_widget_show(fs);
-}
+ case SIGKILL:
+ sigmsg = "Killed";
+ break;
-void
-cap_prep_fs_ok_cb(GtkWidget *w, gpointer data) {
- GtkWidget *fs, *te;
-
- fs = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_PREP_FS_KEY);
- te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_PREP_TE_KEY);
+ case SIGBUS:
+ sigmsg = "Bus error";
+ break;
- gtk_entry_set_text(GTK_ENTRY(te),
- gtk_file_selection_get_filename (GTK_FILE_SELECTION(fs)));
- cap_prep_fs_cancel_cb(w, data);
-}
+ case SIGSEGV:
+ sigmsg = "Segmentation violation";
+ break;
-void
-cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data) {
- GtkWidget *fs;
-
- fs = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_PREP_FS_KEY);
+ /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
+ Linux is POSIX compliant. These are not POSIX-defined signals ---
+ ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
+
+ ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
+ were omitted from POSIX.1 because their behavior is
+ implementation dependent and could not be adequately catego-
+ rized. Conforming implementations may deliver these sig-
+ nals, but must document the circumstances under which they
+ are delivered and note any restrictions concerning their
+ delivery.''
+ */
+
+ #ifdef SIGSYS
+ case SIGSYS:
+ sigmsg = "Bad system call";
+ break;
+ #endif
- gtk_widget_destroy(fs);
-}
+ case SIGPIPE:
+ sigmsg = "Broken pipe";
+ break;
-void
-capture_prep_ok_cb(GtkWidget *w, gpointer data) {
- GtkWidget *if_cb, *filter_te, *file_te, *count_cb, *open_ck, *snap_sb;
- gint open;
-
- if_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_IFACE_KEY);
- filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_FILT_KEY);
- file_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_FILE_KEY);
- count_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_COUNT_KEY);
- open_ck = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_OPEN_KEY);
- snap_sb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), E_CAP_SNAP_KEY);
-
- if (cf.iface) g_free(cf.iface);
- cf.iface =
- g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
- if (cf.cfilter) g_free(cf.cfilter);
- cf.cfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
- if (cf.save_file) g_free(cf.save_file);
- cf.save_file = g_strdup(gtk_entry_get_text(GTK_ENTRY(file_te)));
- cf.count =
- atoi(g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry))));
- open = GTK_TOGGLE_BUTTON(open_ck)->active;
- cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
- if (cf.snap < 1)
- cf.snap = 4096;
- else if (cf.snap < 68)
- cf.snap = 68;
-
- gtk_widget_destroy(GTK_WIDGET(data));
-
- capture(open);
-}
+ case SIGALRM:
+ sigmsg = "Alarm clock";
+ break;
-void
-capture_prep_close_cb(GtkWidget *w, gpointer win) {
+ case SIGTERM:
+ sigmsg = "Terminated";
+ break;
+
+ default:
+ sprintf(sigmsg_buf, "Signal %d", wsignal);
+ sigmsg = sigmsg_buf;
+ break;
+ }
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Child capture process %s: %s%s", msg, sigmsg, coredumped);
+ }
+ }
+
+ /* Read what remains of the capture file, and finish the capture.
+ XXX - do something if this fails? */
+ err = finish_tail_cap_file(cf);
+
+ /* We're not doing a capture any more, so we don't have a save
+ file. */
+ g_free(cf->save_file);
+ cf->save_file = NULL;
+
+ return;
+ }
+
+ buffer[nread] = '\0';
+
+ while(!exit_loop) {
+ /* look for (possibly multiple) '*' */
+ switch (*q) {
+ case '*' :
+ to_read += atoi(p);
+ p = q + 1;
+ q++;
+ break;
+ case '\0' :
+ /* XXX should handle the case of a pipe full (i.e. no star found) */
+ exit_loop = TRUE;
+ break;
+ default :
+ q++;
+ break;
+ }
+ }
- gtk_grab_remove(GTK_WIDGET(win));
- gtk_widget_destroy(GTK_WIDGET(win));
+ /* Read from the capture file the number of records the child told us
+ it added.
+ XXX - do something if this fails? */
+ err = continue_tail_cap_file(cf, to_read);
+
+ /* restore pipe handler */
+ cap_input_id = gtk_input_add_full (sync_pipe[0],
+ GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
+ cap_file_input_cb,
+ NULL,
+ (gpointer) cf,
+ NULL);
}
+#endif /* _WIN32 */
-void
-capture(gint open) {
- GtkWidget *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb,
- *ospf_lb, *other_lb, *stop_bt;
+/*
+ * Timeout, in milliseconds, for reads from the stream of captured packets.
+ */
+#define CAP_READ_TIMEOUT 250
+
+/* Do the low-level work of a capture.
+ Returns TRUE if it succeeds, FALSE otherwise. */
+int
+capture(void)
+{
+ GtkWidget *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
+ *ospf_lb, *gre_lb, *netbios_lb, *ipx_lb, *vines_lb, *other_lb, *stop_bt;
pcap_t *pch;
gchar err_str[PCAP_ERRBUF_SIZE], label_str[32];
loop_data ld;
bpf_u_int32 netnum, netmask;
time_t upd_time, cur_time;
-
- ld.go = TRUE;
- ld.count = 0;
- ld.max = cf.count;
- ld.tcp = 0;
- ld.udp = 0;
- ld.ospf = 0;
- ld.other = 0;
- ld.pdh = NULL;
-
- close_cap_file(&cf, info_bar, file_ctx);
-
- pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
-
- if (pch) {
- if (cf.save_file[0]) {
- ld.pdh = pcap_dump_open(pch, cf.save_file);
- if (ld.pdh == NULL) { /* We have an error */
- snprintf(err_str, PCAP_ERRBUF_SIZE, "Error trying to open dump "
- "file:\n%s", pcap_geterr(pch));
- simple_dialog(ESD_TYPE_WARN, NULL, err_str);
- g_free(cf.save_file);
- cf.save_file = NULL;
- pcap_close(pch);
- return;
- }
- }
-
- if (cf.cfilter) {
- if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Can't use filter: Couldn't obtain netmask info.");
- return;
- } else if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string.");
- return;
- } else if (pcap_setfilter(pch, &cf.fcode) < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
- return;
- }
- }
+ int err, inpkts;
+ char errmsg[1024+1];
+#ifdef linux
+ fd_set set1;
+ struct timeval timeout;
+ int pcap_fd;
+#endif
- cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
-
- /* Container for capture display widgets */
- main_vb = gtk_vbox_new(FALSE, 1);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
- gtk_widget_show(main_vb);
-
- count_lb = gtk_label_new("Count: 0");
- gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
- gtk_widget_show(count_lb);
-
- tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
- gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
- gtk_widget_show(tcp_lb);
-
- udp_lb = gtk_label_new("UDP: 0 (0.0%)");
- gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
- gtk_widget_show(udp_lb);
-
- ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
- gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
- gtk_widget_show(ospf_lb);
-
- other_lb = gtk_label_new("Other: 0 (0.0%)");
- gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
- gtk_widget_show(other_lb);
-
- stop_bt = gtk_button_new_with_label ("Stop");
- gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
- GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
- gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
- GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(stop_bt);
- GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(stop_bt);
- gtk_widget_show(stop_bt);
-
- gtk_widget_show(cap_w);
- gtk_grab_add(cap_w);
-
- upd_time = time(NULL);
- while (ld.go) {
+ ld.go = TRUE;
+ ld.counts.total = 0;
+ ld.max = cf.count;
+ ld.linktype = WTAP_ENCAP_UNKNOWN;
+ ld.sync_packets = 0;
+ ld.counts.tcp = 0;
+ ld.counts.udp = 0;
+ ld.counts.icmp = 0;
+ ld.counts.ospf = 0;
+ ld.counts.gre = 0;
+ ld.counts.ipx = 0;
+ ld.counts.netbios = 0;
+ ld.counts.vines = 0;
+ ld.counts.other = 0;
+ ld.pdh = NULL;
+
+ /* Open the network interface to capture from it. */
+ pch = pcap_open_live(cf.iface, cf.snap, 1, CAP_READ_TIMEOUT, err_str);
+
+ if (pch == NULL) {
+ /* Well, we couldn't start the capture.
+ If this is a child process that does the capturing in sync
+ mode or fork mode, it shouldn't do any UI stuff until we pop up the
+ capture-progress window, and, since we couldn't start the
+ capture, we haven't popped it up. */
+ if (!capture_child) {
while (gtk_events_pending()) gtk_main_iteration();
- pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+ }
+ snprintf(errmsg, sizeof errmsg,
+ "The capture session could not be initiated (%s).\n"
+ "Please check to make sure you have sufficient permissions, and that\n"
+ "you have the proper interface specified.", err_str);
+ goto error;
+ }
- /* Only update once a second so as not to overload slow displays */
- cur_time = time(NULL);
- if (cur_time > upd_time) {
+ if (cf.cfilter) {
+ /* A capture filter was specified; set it up. */
+ if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
+ snprintf(errmsg, sizeof errmsg,
+ "Can't use filter: Couldn't obtain netmask info (%s).", err_str);
+ goto error;
+ }
+ if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
+ snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
+ pcap_geterr(pch));
+ goto error;
+ }
+ if (pcap_setfilter(pch, &cf.fcode) < 0) {
+ snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
+ pcap_geterr(pch));
+ goto error;
+ }
+ }
- upd_time = cur_time;
+ /* Set up to write to the capture file. */
+ ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
+ if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
+ strcpy(errmsg, "The network you're capturing from is of a type"
+ " that Ethereal doesn't support.");
+ goto error;
+ }
+ ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
+ ld.linktype, pcap_snapshot(pch), &err);
+
+ if (ld.pdh == NULL) {
+ /* We couldn't set up to write to the capture file. */
+ switch (err) {
+
+ case WTAP_ERR_CANT_OPEN:
+ strcpy(errmsg, "The file to which the capture would be saved"
+ " couldn't be created for some unknown reason.");
+ break;
+
+ case WTAP_ERR_SHORT_WRITE:
+ strcpy(errmsg, "A full header couldn't be written to the file"
+ " to which the capture would be saved.");
+ break;
+
+ default:
+ if (err < 0) {
+ sprintf(errmsg, "The file to which the capture would be"
+ " saved (\"%s\") could not be opened: Error %d.",
+ cf.save_file, err);
+ } else {
+ sprintf(errmsg, "The file to which the capture would be"
+ " saved (\"%s\") could not be opened: %s.",
+ cf.save_file, strerror(err));
+ }
+ break;
+ }
+ goto error;
+ }
- sprintf(label_str, "Count: %d", ld.count);
- gtk_label_set(GTK_LABEL(count_lb), label_str);
+ if (capture_child) {
+ /* Well, we should be able to start capturing.
+
+ This is the child process for a sync mode capture, so sync out
+ the capture file, so the header makes it to the file system,
+ and send a "capture started successfully and capture file created"
+ message to our parent so that they'll open the capture file and
+ update its windows to indicate that we have a live capture in
+ progress. */
+ fflush(wtap_dump_file(ld.pdh));
+ write(1, "0;", 2);
+ }
- sprintf(label_str, "TCP: %d (%.1f%%)", ld.tcp, pct(ld.tcp, ld.count));
- gtk_label_set(GTK_LABEL(tcp_lb), label_str);
+ cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
- sprintf(label_str, "UDP: %d (%.1f%%)", ld.udp, pct(ld.udp, ld.count));
- gtk_label_set(GTK_LABEL(udp_lb), label_str);
+ /* Container for capture display widgets */
+ main_vb = gtk_vbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
+ gtk_widget_show(main_vb);
- sprintf(label_str, "OSPF: %d (%.1f%%)", ld.ospf, pct(ld.ospf, ld.count));
- gtk_label_set(GTK_LABEL(ospf_lb), label_str);
+ count_lb = gtk_label_new("Count: 0");
+ gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
+ gtk_widget_show(count_lb);
- sprintf(label_str, "Other: %d (%.1f%%)", ld.other,
- pct(ld.other, ld.count));
- gtk_label_set(GTK_LABEL(other_lb), label_str);
+ tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
+ gtk_widget_show(tcp_lb);
+
+ udp_lb = gtk_label_new("UDP: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
+ gtk_widget_show(udp_lb);
+
+ icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
+ gtk_widget_show(icmp_lb);
+
+ ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
+ gtk_widget_show(ospf_lb);
+
+ gre_lb = gtk_label_new("GRE: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
+ gtk_widget_show(gre_lb);
+
+ netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
+ gtk_widget_show(netbios_lb);
+
+ ipx_lb = gtk_label_new("IPX: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), ipx_lb, FALSE, FALSE, 3);
+ gtk_widget_show(ipx_lb);
+
+ vines_lb = gtk_label_new("VINES: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), vines_lb, FALSE, FALSE, 3);
+ gtk_widget_show(vines_lb);
+
+ other_lb = gtk_label_new("Other: 0 (0.0%)");
+ gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
+ gtk_widget_show(other_lb);
+
+ /* allow user to either click a stop button, or the close button on
+ the window to stop a capture in progress. */
+ stop_bt = gtk_button_new_with_label ("Stop");
+ gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
+ GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
+ gtk_signal_connect(GTK_OBJECT(cap_w), "delete_event",
+ GTK_SIGNAL_FUNC(capture_delete_cb), (gpointer) &ld);
+ gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
+ GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(stop_bt);
+ GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(stop_bt);
+ gtk_widget_show(stop_bt);
+
+ gtk_widget_show(cap_w);
+ gtk_grab_add(cap_w);
+
+ upd_time = time(NULL);
+#ifdef linux
+ pcap_fd = pcap_fileno(pch);
+#endif
+ while (ld.go) {
+ while (gtk_events_pending()) gtk_main_iteration();
+#ifdef linux
+ /*
+ * 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.
+ *
+ * Thus, on Linux, 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.
+ */
+ FD_ZERO(&set1);
+ FD_SET(pcap_fd, &set1);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = CAP_READ_TIMEOUT*1000;
+ if (select(pcap_fd+1, &set1, NULL, NULL, &timeout) != 0) {
+ /*
+ * "select()" says we can read from it without blocking; go for
+ * it.
+ */
+ inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+ } else
+ inpkts = 0;
+#else
+ inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+#endif
+ if (inpkts > 0)
+ ld.sync_packets += inpkts;
+ /* Only update once a second so as not to overload slow displays */
+ cur_time = time(NULL);
+ if (cur_time > upd_time) {
+ upd_time = cur_time;
+
+ sprintf(label_str, "Count: %d", ld.counts.total);
+ gtk_label_set(GTK_LABEL(count_lb), label_str);
+
+ sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
+ pct(ld.counts.tcp, ld.counts.total));
+ gtk_label_set(GTK_LABEL(tcp_lb), label_str);
+
+ sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
+ pct(ld.counts.udp, ld.counts.total));
+ gtk_label_set(GTK_LABEL(udp_lb), label_str);
+
+ sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
+ pct(ld.counts.icmp, ld.counts.total));
+ gtk_label_set(GTK_LABEL(icmp_lb), label_str);
+
+ sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
+ pct(ld.counts.ospf, ld.counts.total));
+ gtk_label_set(GTK_LABEL(ospf_lb), label_str);
+
+ sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
+ pct(ld.counts.gre, ld.counts.total));
+ gtk_label_set(GTK_LABEL(gre_lb), label_str);
+
+ sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
+ pct(ld.counts.netbios, ld.counts.total));
+ gtk_label_set(GTK_LABEL(netbios_lb), label_str);
+
+ sprintf(label_str, "IPX: %d (%.1f%%)", ld.counts.ipx,
+ pct(ld.counts.ipx, ld.counts.total));
+ gtk_label_set(GTK_LABEL(ipx_lb), label_str);
+
+ sprintf(label_str, "VINES: %d (%.1f%%)", ld.counts.vines,
+ pct(ld.counts.vines, ld.counts.total));
+ gtk_label_set(GTK_LABEL(vines_lb), label_str);
+
+ sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
+ pct(ld.counts.other, ld.counts.total));
+ gtk_label_set(GTK_LABEL(other_lb), label_str);
+
+ /* do sync here, too */
+ fflush(wtap_dump_file(ld.pdh));
+ if (capture_child && ld.sync_packets) {
+ /* This is the child process for a sync mode capture, so send
+ our parent a message saying we've written out "ld.sync_packets"
+ packets to the capture file. */
+ char tmp[20];
+ sprintf(tmp, "%d*", ld.sync_packets);
+ write(1, tmp, strlen(tmp));
+ ld.sync_packets = 0;
}
}
+ }
- if (ld.pdh) pcap_dump_close(ld.pdh);
- pcap_close(pch);
-
- gtk_grab_remove(GTK_WIDGET(cap_w));
- gtk_widget_destroy(GTK_WIDGET(cap_w));
+ if (!wtap_dump_close(ld.pdh, &err)) {
+ /* XXX - in fork mode, this may not pop up, or, if it does,
+ it may disappear as soon as we exit.
+
+ We should have the parent process, while it's reading
+ the packet count update messages, catch error messages
+ and pop up a message box if it sees one. */
+ switch (err) {
+
+ case WTAP_ERR_CANT_CLOSE:
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "The file to which the capture was being saved"
+ " couldn't be closed for some unknown reason.");
+ break;
+
+ case WTAP_ERR_SHORT_WRITE:
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Not all the data could be written to the file"
+ " to which the capture was being saved.");
+ break;
+
+ default:
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "The file to which the capture was being"
+ " saved (\"%s\") could not be closed: %s.",
+ cf.save_file, wtap_strerror(err));
+ break;
+ }
+ }
+ pcap_close(pch);
+
+ gtk_grab_remove(GTK_WIDGET(cap_w));
+ gtk_widget_destroy(GTK_WIDGET(cap_w));
+
+ return TRUE;
+
+error:
+ /* We couldn't even start the capture, so get rid of the capture
+ file. */
+ unlink(cf.save_file); /* silently ignore error */
+ g_free(cf.save_file);
+ cf.save_file = NULL;
+ if (capture_child) {
+ /* This is the child process for a sync mode capture.
+ Send the error message to our parent, so they can display a
+ dialog box containing it. */
+ int msglen = strlen(errmsg);
+ char lenbuf[10+1+1];
+ sprintf(lenbuf, "%u;", msglen);
+ write(1, lenbuf, strlen(lenbuf));
+ write(1, errmsg, msglen);
} else {
- while (gtk_events_pending()) gtk_main_iteration();
- simple_dialog(ESD_TYPE_WARN, NULL,
- "The capture session could not be initiated. Please\n"
- "check to make sure you have sufficient permissions, and\n"
- "that you have the proper interface specified.");
- g_free(cf.save_file);
- cf.save_file = NULL;
+ /* Display the dialog box ourselves; there's no parent. */
+ simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
}
+ if (pch != NULL)
+ pcap_close(pch);
- if (cf.save_file && open) load_cap_file(cf.save_file, &cf);
+ return FALSE;
}
-float
+static float
pct(gint num, gint denom) {
if (denom) {
return (float) num * 100.0 / (float) denom;
}
}
-void
+static void
+capture_delete_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
+ capture_stop_cb(NULL, data);
+}
+
+static void
capture_stop_cb(GtkWidget *w, gpointer data) {
loop_data *ld = (loop_data *) data;
ld->go = FALSE;
}
-void
+static void
capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
const u_char *pd) {
-
- guint16 etype;
- guint8 iptype = 0;
- gint offset = 14;
-
+ struct wtap_pkthdr whdr;
loop_data *ld = (loop_data *) user;
-
- if ((++ld->count >= ld->max) && (ld->max > 0))
+ int err;
+
+ if ((++ld->counts.total >= ld->max) && (ld->max > 0))
{
ld->go = FALSE;
}
- /* Currently, pcap_dumper_t is a FILE *. Let's hope that doesn't change. */
- if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd);
-
- etype = etype = (pd[12] << 8) | pd[13];
- if (etype <= IEEE_802_3_MAX_LEN) {
- etype = (pd[20] << 8) | pd[21];
- offset = 22;
+ if (ld->pdh) {
+ /* "phdr->ts" may not necessarily be a "struct timeval" - it may
+ be a "struct bpf_timeval", with member sizes wired to 32
+ bits - and we may go that way ourselves in the future, so
+ copy the members individually. */
+ whdr.ts.tv_sec = phdr->ts.tv_sec;
+ whdr.ts.tv_usec = phdr->ts.tv_usec;
+ whdr.caplen = phdr->caplen;
+ whdr.len = phdr->len;
+ whdr.pkt_encap = ld->linktype;
+
+ /* XXX - do something if this fails */
+ wtap_dump(ld->pdh, &whdr, pd, &err);
}
-
- switch(etype){
- case ETHERTYPE_IP:
- iptype = pd[offset + 9];
- switch (iptype) {
- case IP_PROTO_TCP:
- ld->tcp++;
- break;
- case IP_PROTO_UDP:
- ld->udp++;
- break;
- case IP_PROTO_OSPF:
- ld->ospf++;
- break;
- default:
- ld->other++;
- }
- break;
- case ETHERTYPE_IPX:
- case ETHERTYPE_IPv6:
- case ETHERTYPE_ATALK:
- case ETHERTYPE_VINES:
- case ETHERTYPE_ARP:
- default:
- ld->other++;
+
+ /* Set the initial payload to the packet length, and the initial
+ captured payload to the capture length (other protocols may
+ reduce them if their headers say they're less). */
+ pi.len = phdr->len;
+ pi.captured_len = phdr->caplen;
+
+ switch (ld->linktype) {
+ case WTAP_ENCAP_ETHERNET:
+ capture_eth(pd, 0, &ld->counts);
+ break;
+ case WTAP_ENCAP_FDDI:
+ case WTAP_ENCAP_FDDI_BITSWAPPED:
+ capture_fddi(pd, &ld->counts);
+ break;
+ case WTAP_ENCAP_TR:
+ capture_tr(pd, 0, &ld->counts);
+ break;
+ case WTAP_ENCAP_NULL:
+ capture_null(pd, &ld->counts);
+ break;
+ case WTAP_ENCAP_PPP:
+ capture_ppp(pd, &ld->counts);
+ break;
+ case WTAP_ENCAP_RAW_IP:
+ capture_raw(pd, &ld->counts);
+ break;
+ /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
+ with LLC header following; we should implement it at some
+ point. */
}
}
+
+#endif /* HAVE_LIBPCAP */