Put into the "Capture Preferences" dialog box a check box to control
[obnox/wireshark/wip.git] / gtk / capture_dlg.c
index 0509c6bd28ef1815fd596d0a6e3f22df181f5432..586946d991f512b2c760c3c2f57ff2484a61d58e 100644 (file)
@@ -1,7 +1,7 @@
 /* capture_dlg.c
  * Routines for packet capture windows
  *
- * $Id: capture_dlg.c,v 1.7 1999/10/02 07:13:20 guy Exp $
+ * $Id: capture_dlg.c,v 1.18 2000/01/18 09:24:57 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -28,6 +28,8 @@
 # include "config.h"
 #endif
 
+#ifdef HAVE_LIBPCAP
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 #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 <stdarg.h>
 # include "snprintf.h"
 #endif
 
-#ifdef HAVE_SYS_SOCKIO_H
-# include <sys/sockio.h>
-#endif
-
-#include <wiretap/wtap.h>
 #include "capture.h"
 #include "globals.h"
 #include "main.h"
 #include "capture_dlg.h"
 #include "prefs_dlg.h"
+#include "simple_dialog.h"
 #include "util.h"
 
 /* Capture callback data keys */
-#define E_CAP_IFACE_KEY    "cap_iface"
-#define E_CAP_FILT_KEY     "cap_filter_te"
-#define E_CAP_FILE_TE_KEY  "cap_file_te"
-#define E_CAP_COUNT_KEY    "cap_count"
-#define E_CAP_SNAP_KEY     "cap_snap"
-#define E_CAP_SYNC_KEY     "cap_sync"
-#define E_CAP_RESOLVE_KEY  "cap_resolve"
-
-/* Capture filter key */
-#define E_CAP_FILT_TE_KEY "cap_filt_te"
-
-static GList*
-get_interface_list();
+#define E_CAP_IFACE_KEY       "cap_iface"
+#define E_CAP_FILT_KEY        "cap_filter_te"
+#define E_CAP_FILE_TE_KEY     "cap_file_te"
+#define E_CAP_COUNT_KEY       "cap_count"
+#define E_CAP_SNAP_KEY        "cap_snap"
+#define E_CAP_SYNC_KEY        "cap_sync"
+#define E_CAP_AUTO_SCROLL_KEY "cap_auto_scroll"
+#define E_CAP_RESOLVE_KEY     "cap_resolve"
 
 static void
 capture_prep_file_cb(GtkWidget *w, gpointer te);
@@ -105,12 +83,6 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
 static void
 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w);
 
-static void
-search_for_if_cb(gpointer data, gpointer user_data);
-
-static void
-free_if_cb(gpointer data, gpointer user_data);
-
 void
 capture_prep_cb(GtkWidget *w, gpointer d)
 {
@@ -120,14 +92,18 @@ capture_prep_cb(GtkWidget *w, gpointer d)
                 *file_hb, *file_bt, *file_te,
                 *caplen_hb,
                 *bbox, *ok_bt, *cancel_bt, *snap_lb,
-                *snap_sb, *sync_cb, *resolv_cb;
+                *snap_sb, *sync_cb, *auto_scroll_cb, *resolv_cb;
   GtkAdjustment *adj;
   GList         *if_list, *count_list = NULL;
   gchar         *count_item1 = "0 (Infinite)", count_item2[16];
+  int           err;
+  char          err_str[PCAP_ERRBUF_SIZE];
 
-  if_list = get_interface_list();
-  if (if_list == NULL)
-    return;
+  if_list = get_interface_list(&err, err_str);
+  if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
+    simple_dialog(ESD_TYPE_WARN, NULL, "Can't get list of interfaces: %s",
+                       err_str);
+  }
   
   cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences");
@@ -148,7 +124,8 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   gtk_widget_show(if_lb);
   
   if_cb = gtk_combo_new();
-  gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
+  if (if_list != NULL)
+    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)
@@ -156,10 +133,7 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   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);
-  }
+  free_interface_list(if_list);
 
   /* Count row */
   count_hb = gtk_hbox_new(FALSE, 3);
@@ -191,7 +165,7 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   
   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_SIGNAL_FUNC(filter_dialog_cb), NULL);
   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
   gtk_widget_show(filter_bt);
   
@@ -240,6 +214,11 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   gtk_container_add(GTK_CONTAINER(main_vb), sync_cb);
   gtk_widget_show(sync_cb);
 
+  auto_scroll_cb = gtk_check_button_new_with_label("Automatic scrolling in live capture");
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(auto_scroll_cb), auto_scroll_live);
+  gtk_container_add(GTK_CONTAINER(main_vb), auto_scroll_cb);
+  gtk_widget_show(auto_scroll_cb);
+
   resolv_cb = gtk_check_button_new_with_label("Enable name resolution");
   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(resolv_cb), g_resolving_actif);
   gtk_container_add(GTK_CONTAINER(main_vb), resolv_cb);
@@ -274,6 +253,7 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   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_SNAP_KEY,  snap_sb);
   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SYNC_KEY,  sync_cb);
+  gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_AUTO_SCROLL_KEY, auto_scroll_cb);
   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_RESOLVE_KEY,  resolv_cb);
 
   gtk_widget_show(cap_open_w);
@@ -316,7 +296,9 @@ cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data)
 static void
 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
   GtkWidget *if_cb, *filter_te, *file_te, *count_cb, *snap_sb, *sync_cb,
-            *resolv_cb;
+            *auto_scroll_cb, *resolv_cb;
+  gchar *if_text;
+  gchar *if_name;
   gchar *filter_text;
   gchar *save_file;
 
@@ -326,20 +308,36 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
   count_cb  = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_COUNT_KEY);
   snap_sb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SNAP_KEY);
   sync_cb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SYNC_KEY);
+  auto_scroll_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_AUTO_SCROLL_KEY);
   resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RESOLVE_KEY);
 
+  if_text =
+    g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
+  if_name = strtok(if_text, " \t");
+  if (if_name == NULL) {
+    simple_dialog(ESD_TYPE_WARN, NULL,
+      "You didn't specify an interface on which to capture packets.");
+    g_free(if_name);
+    return;
+  }
   if (cf.iface)
     g_free(cf.iface);
-  cf.iface =
-    g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
-
+  cf.iface = g_strdup(if_name);
+  g_free(if_text);
+
+  /* XXX - don't try to get clever and set "cf.filter" to NULL if the
+     filter string is empty, as an indication that we don't have a filter
+     and thus don't have to set a filter when capturing - the version of
+     libpcap in Red Hat Linux 6.1, and versions based on later patches
+     in that series, don't bind the AF_PACKET socket to an interface
+     until a filter is set, which means they aren't bound at all if
+     no filter is set, which means no packets arrive as input on that
+     socket, which means Ethereal never sees any packets. */
   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
   if (cf.cfilter)
     g_free(cf.cfilter);
-  cf.cfilter = NULL; /* ead 06/16/99 */
-  if (filter_text && filter_text[0]) {
-    cf.cfilter = g_strdup(filter_text); 
-  }
+  g_assert(filter_text != NULL);
+  cf.cfilter = g_strdup(filter_text); 
 
   save_file = gtk_entry_get_text(GTK_ENTRY(file_te));
   if (save_file && save_file[0]) {
@@ -360,6 +358,8 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
 
   sync_mode = GTK_TOGGLE_BUTTON (sync_cb)->active;
 
+  auto_scroll_live = GTK_TOGGLE_BUTTON (auto_scroll_cb)->active;
+
   g_resolving_actif = GTK_TOGGLE_BUTTON (resolv_cb)->active;
 
   gtk_widget_destroy(GTK_WIDGET(parent_w));
@@ -374,155 +374,4 @@ capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w)
   gtk_widget_destroy(GTK_WIDGET(parent_w));
 }
 
-struct search_user_data {
-       char    *name;
-       int     found;
-};
-
-static GList *
-get_interface_list() {
-  GList  *il = NULL;
-  gint    nonloopback_pos = 0;
-  struct  ifreq *ifr, *last;
-  struct  ifconf ifc;
-  struct  ifreq ifrflags;
-  int     sock = socket(AF_INET, SOCK_DGRAM, 0);
-  struct search_user_data user_data;
-  pcap_t *pch;
-  gchar   err_str[PCAP_ERRBUF_SIZE];
-
-  if (sock < 0)
-  {
-    simple_dialog(ESD_TYPE_WARN, NULL,
-      "Can't list interfaces: error opening socket.");
-    return NULL;
-  }
-
-  /* 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))
-  {
-    simple_dialog(ESD_TYPE_WARN, NULL,
-      "Can't list interfaces: SIOCGIFCONF error: %s", strerror(errno));
-    goto fail;
-  }
-
-  ifr  = (struct ifreq *) ifc.ifc_req;
-  last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
-  while (ifr < last)
-  {
-    /*
-     * Skip addresses that begin with "dummy", or that include a ":"
-     * (the latter are Solaris virtuals).
-     */
-    if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
-       strchr(ifr->ifr_name, ':') != NULL)
-      goto next;
-
-    /*
-     * If we already have this interface name on the list, don't add
-     * it (SIOCGIFCONF returns, at least on BSD-flavored systems, one
-     * entry per interface *address*; if an interface has multiple
-     * addresses, we get multiple entries for it).
-     */
-    user_data.name = ifr->ifr_name;
-    user_data.found = FALSE;
-    g_list_foreach(il, search_for_if_cb, &user_data);
-    if (user_data.found)
-      goto next;
-
-    /*
-     * Get the interface flags.
-     */
-    memset(&ifrflags, 0, sizeof ifrflags);
-    strncpy(ifrflags.ifr_name, ifr->ifr_name, sizeof ifrflags.ifr_name);
-    if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
-      if (errno == ENXIO)
-        goto next;
-      simple_dialog(ESD_TYPE_WARN, NULL,
-        "Can't list interfaces: SIOCGIFFLAGS error on %s: %s",
-        ifr->ifr_name, strerror(errno));
-      goto fail;
-    }
-
-    /*
-     * Skip interfaces that aren't up.
-     */
-    if (!(ifrflags.ifr_flags & IFF_UP))
-      goto next;
-
-    /*
-     * Skip interfaces that we can't open with "libpcap".
-     */
-    pch = pcap_open_live(ifr->ifr_name, WTAP_MAX_PACKET_SIZE, 0, 0, err_str);
-    if (pch == NULL)
-      goto next;
-    pcap_close(pch);
-
-    /*
-     * If it's a loopback interface, add it at the end of the list,
-     * otherwise add it after the last non-loopback interface,
-     * so all loopback interfaces go at the end - we don't want a
-     * loopback interface to be the default capture device unless there
-     * are no non-loopback devices.
-     */
-    if ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
-       strncmp(ifr->ifr_name, "lo", 2) == 0)
-      il = g_list_insert(il, g_strdup(ifr->ifr_name), -1);
-    else {
-      il = g_list_insert(il, g_strdup(ifr->ifr_name), nonloopback_pos);
-      /* Insert the next non-loopback interface after this one. */
-      nonloopback_pos++;
-    }
-
-next:
-#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
-  }
-
-  free(ifc.ifc_buf);
-  close(sock);
-
-  if (il == NULL) {
-    simple_dialog(ESD_TYPE_WARN, NULL,
-      "There are no network interfaces that can be opened.\n"
-      "Please check to make sure you have sufficient permission\n"
-      "to capture packets.");
-    return NULL;
-  }
-
-  return il;
-
-fail:
-  if (il != NULL) {
-    g_list_foreach(il, free_if_cb, NULL);
-    g_list_free(il);
-  }
-  free(ifc.ifc_buf);
-  close(sock);
-  return NULL;
-}
-
-static void
-search_for_if_cb(gpointer data, gpointer user_data)
-{
-       struct search_user_data *search_user_data = user_data;
-
-       if (strcmp((char *)data, search_user_data->name) == 0)
-               search_user_data->found = TRUE;
-}
-
-static void
-free_if_cb(gpointer data, gpointer user_data)
-{
-       g_free(data);
-}
-
-
+#endif /* HAVE_LIBPCAP */