If we have pcap_open, call it instead of pcap_open_live, otherwise we might
[obnox/wireshark/wip.git] / capture.c
index d18b1d81cb843a1ff7429dc56bc1c29155e48c5e..b93fcc1a22df8e85791d274d5579578e13778917 100644 (file)
--- a/capture.c
+++ b/capture.c
 #include <sys/types.h>
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>         /* needed to define AF_ values on UNIX */
 #endif
@@ -71,7 +75,6 @@
 
 #include <epan/packet.h>
 #include <epan/dfilter/dfilter.h>
-#include <epan/ws_strsplit.h>
 #include "file.h"
 #include "capture.h"
 #include "capture_sync.h"
@@ -82,8 +85,6 @@
 #include "alert_box.h"
 #include "simple_dialog.h"
 #include <epan/prefs.h>
-#include "conditions.h"
-#include "ringbuffer.h"
 
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #include "file_util.h"
 #include "log.h"
 
+typedef struct if_stat_cache_item_s {
+    char *name;
+    struct pcap_stat ps;
+} if_stat_cache_item_t;
 
+struct if_stat_cache_s {
+    int stat_fd;
+    int fork_child;
+    GList *cache_list;  /* List of if_stat_chache_entry_t */
+};
 
 /**
  * Start a capture.
@@ -313,7 +323,6 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file)
       g_free(capture_opts->save_file);
       capture_opts->save_file = NULL;
       return FALSE;
-      break;
     }
   }
 
@@ -675,12 +684,183 @@ capture_interface_list(int *err, char **err_str)
 
     /* Check to see if we built a list */
     if (if_list == NULL) {
-        if (*err_str)
+        if (err_str && *err_str)
             *err_str = g_strdup("No interfaces found");
         *err = NO_INTERFACES_FOUND;
     }
     return if_list;
 }
 
+/* XXX - We parse simple text output to get our interface list.  Should
+ * we use "real" data serialization instead, e.g. via XML? */
+GList *
+capture_pcap_linktype_list(const gchar *ifname, char **err_str)
+{
+    GList     *linktype_list = NULL;
+    int        err, i;
+    gchar     *msg;
+    gchar    **raw_list, **lt_parts;
+    data_link_info_t *data_link_info;
+
+    g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
+
+    /* Try to get our interface list */
+    err = sync_linktype_list_open(ifname, &msg);
+    if (err != 0) {
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
+        if (err_str) {
+            *err_str = msg;
+        } else {
+            g_free(msg);
+        }
+        return NULL;
+    }
+
+    /* Split our lines */
+    raw_list = g_strsplit(msg, "\n", 0);
+    g_free(msg);
+
+    for (i = 0; raw_list[i] != NULL; i++) {
+        /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
+        lt_parts = g_strsplit(raw_list[i], "\t", 3);
+        if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
+            g_strfreev(lt_parts);
+            continue;
+        }
+
+        data_link_info = g_malloc(sizeof (data_link_info_t));
+        data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
+        data_link_info->name = g_strdup(lt_parts[1]);
+        if (strcmp(lt_parts[2], "(not supported)") != 0)
+            data_link_info->description = g_strdup(lt_parts[2]);
+        else
+            data_link_info->description = NULL;
+
+        linktype_list = g_list_append(linktype_list, data_link_info);
+    }
+    g_strfreev(raw_list);
+
+    /* Check to see if we built a list */
+    if (linktype_list == NULL) {
+        if (err_str)
+            *err_str = NULL;
+    }
+    return linktype_list;
+}
+
+if_stat_cache_t *
+capture_stat_start(GList *if_list) {
+    int stat_fd, fork_child;
+    gchar *msg;
+    if_stat_cache_t *sc = NULL;
+    GList *if_entry;
+    if_info_t *if_info;
+    if_stat_cache_item_t *sc_item;
+
+    /* Fire up dumpcap. */
+    /*
+     * XXX - on systems with BPF, the number of BPF devices limits the
+     * number of devices on which you can capture simultaneously.
+     *
+     * This means that
+     *
+     * 1) this might fail if you run out of BPF devices
+     *
+     * and
+     *
+     * 2) opening every interface could leave too few BPF devices
+     *    for *other* programs.
+     *
+     * It also means the system could end up getting a lot of traffic
+     * that it has to pass through the networking stack and capture
+     * mechanism, so opening all the devices and presenting packet
+     * counts might not always be a good idea.
+     */
+     if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
+        sc = g_malloc(sizeof(if_stat_cache_t));
+        sc->stat_fd = stat_fd;
+        sc->fork_child = fork_child;
+        sc->cache_list = NULL;
+
+        /* Initialize the cache */
+        for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
+            if_info = if_entry->data;
+            sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
+            sc_item->name = g_strdup(if_info->name);
+            sc->cache_list = g_list_append(sc->cache_list, sc_item);
+        }
+    }
+    return sc;
+}
+
+#define MAX_STAT_LINE_LEN 500
+
+static void
+capture_stat_cache_update(if_stat_cache_t *sc) {
+    gchar stat_line[MAX_STAT_LINE_LEN];
+    gchar **stat_parts;
+    GList *sc_entry;
+    if_stat_cache_item_t *sc_item;
+
+    if (!sc)
+        return;
+
+    while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
+        g_strstrip(stat_line);
+        stat_parts = g_strsplit(stat_line, "\t", 3);
+        if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
+            stat_parts[2] == NULL) {
+            g_strfreev(stat_parts);
+            continue;
+        }
+        for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
+            sc_item = sc_entry->data;
+            if (strcmp(sc_item->name, stat_parts[0]) == 0) {
+                sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
+                sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
+            }
+        }
+        g_strfreev(stat_parts);
+    }
+}
+
+gboolean
+capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
+    GList *sc_entry;
+    if_stat_cache_item_t *sc_item;
+
+    if (!sc || !ifname || !ps) {
+        return FALSE;
+    }
+
+    capture_stat_cache_update(sc);
+    for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
+        sc_item = sc_entry->data;
+        if (strcmp(sc_item->name, ifname) == 0) {
+            memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+void
+capture_stat_stop(if_stat_cache_t *sc) {
+    GList *sc_entry;
+    if_stat_cache_item_t *sc_item;
+    gchar *msg;
+
+    if (!sc)
+        return;
+
+    sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
+
+    for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
+        sc_item = sc_entry->data;
+        g_free(sc_item->name);
+        g_free(sc_item);
+    }
+    g_free(sc);
+}
 
 #endif /* HAVE_LIBPCAP */