from Frederic Peters: bring debian package generation .deb up to date
[obnox/wireshark/wip.git] / capture.c
index 8a6036d922304b1dfd3e1a383ff1c040ae0b679c..dfee5f82b7078840236bfb5780ffe1dbee9878c1 100644 (file)
--- a/capture.c
+++ b/capture.c
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-/* With MSVC and a libethereal.dll this file needs to import some variables 
-   in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
-#define _NEED_VAR_IMPORT_
-
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
@@ -34,6 +30,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
@@ -79,55 +76,20 @@ static gboolean normal_do_capture(capture_options *capture_opts, gboolean is_tem
 static void stop_capture_signal_handler(int signo);
 
 
-void
-capture_opts_init(capture_options *capture_opts, void *cfile)
-{
-  capture_opts->cf                      = cfile;
-#ifdef _WIN32
-  capture_opts->buffer_size             = 1;                /* 1 MB */
-#endif
-  capture_opts->has_snaplen             = FALSE;
-  capture_opts->snaplen                 = MIN_PACKET_SIZE;
-  capture_opts->promisc_mode            = TRUE;
-  capture_opts->linktype                = -1;               /* the default linktype */
-/*  capture_opts->capture_child           = FALSE;*/
-  capture_opts->save_file               = NULL;
-  capture_opts->save_file_fd            = -1;
-  capture_opts->sync_mode               = TRUE;
-  capture_opts->show_info               = TRUE;
-  capture_opts->quit_after_cap          = FALSE;
-
-  capture_opts->multi_files_on          = FALSE;
-  capture_opts->has_file_duration       = FALSE;
-  capture_opts->file_duration           = 60;               /* 1 min */
-  capture_opts->has_ring_num_files      = TRUE;
-  capture_opts->ring_num_files          = 2;
-
-  capture_opts->has_autostop_files      = FALSE;
-  capture_opts->autostop_files          = 1;
-  capture_opts->has_autostop_packets    = FALSE;
-  capture_opts->autostop_packets        = 1;
-  capture_opts->has_autostop_filesize   = FALSE;
-  capture_opts->autostop_filesize       = 1024 * 1024;      /* 1 MB */
-  capture_opts->has_autostop_duration   = FALSE;
-  capture_opts->autostop_duration       = 60;               /* 1 min */
-}
-
-
-/* open the output file (temporary/specified name/ringbuffer) and close the old one */
+/* open the output file (temporary/specified name/ringbuffer) */
 /* Returns TRUE if the file opened successfully, FALSE otherwise. */
 static gboolean
-capture_open_output(capture_options *capture_opts, const char *save_file, gboolean *is_tempfile) {
+capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
   char tmpname[128+1];
   gchar *capfile_name;
 
 
-  if (save_file != NULL) {
+  if (capture_opts->save_file != NULL) {
     /* If the Sync option is set, we return to the caller while the capture
      * is in progress.  Therefore we need to take a copy of save_file in
      * case the caller destroys it after we return.
      */
-    capfile_name = g_strdup(save_file);
+    capfile_name = g_strdup(capture_opts->save_file);
     if (capture_opts->multi_files_on) {
       /* ringbuffer is enabled */
       capture_opts->save_file_fd = ringbuf_init(capfile_name,
@@ -147,9 +109,9 @@ capture_open_output(capture_options *capture_opts, const char *save_file, gboole
 
   /* did we fail to open the output file? */
   if (capture_opts->save_file_fd == -1) {
-    if (is_tempfile) {
+    if (*is_tempfile) {
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-       "The temporary file to which the capture would be saved (\"%s\")"
+       "The temporary file to which the capture would be saved (\"%s\") "
        "could not be opened: %s.", capfile_name, strerror(errno));
     } else {
       if (capture_opts->multi_files_on) {
@@ -161,9 +123,9 @@ capture_open_output(capture_options *capture_opts, const char *save_file, gboole
     return FALSE;
   }
 
-  /* close the old file */
-  cf_close(capture_opts->cf);
-  g_assert(capture_opts->save_file == NULL);
+  if(capture_opts->save_file != NULL) {
+    g_free(capture_opts->save_file);
+  }
   capture_opts->save_file = capfile_name;
   /* capture_opts.save_file is "g_free"ed later, which is equivalent to
      "g_free(capfile_name)". */
@@ -172,80 +134,78 @@ capture_open_output(capture_options *capture_opts, const char *save_file, gboole
 }
 
 
+/* close the output file (NOT the capture file) */
+static void
+capture_close_output(capture_options *capture_opts)
+{
+    if (capture_opts->multi_files_on) {
+        ringbuf_free();
+    } else {
+        g_free(capture_opts->save_file);
+    }
+    capture_opts->save_file = NULL;
+}
+
+
 /* Open a specified file, or create a temporary file, and start a capture
    to the file in question.  */
 /* Returns TRUE if the capture starts successfully, FALSE otherwise. */
 gboolean
-do_capture(capture_options *capture_opts, const char *save_file)
+do_capture(capture_options *capture_opts)
 {
   gboolean is_tempfile;
   gboolean ret;
-  gchar *title;
 
-  /* open the output file (temporary/specified name/ringbuffer) and close the old one */
-  if(!capture_open_output(capture_opts, save_file, &is_tempfile)) {
+
+  /* open the new output file (temporary/specified name/ringbuffer) */
+  if(!capture_open_output(capture_opts, &is_tempfile)) {
     return FALSE;
   }
 
-  title = g_strdup_printf("%s: Capturing - Ethereal",
-                          get_interface_descriptive_name(cf_get_iface(capture_opts->cf)));
-  if (capture_opts->sync_mode) {       
+  /* close the currently loaded capture file */
+  cf_close(capture_opts->cf);
+
+  /* We could simply use TRUE for this expression now, this will work for all 
+   * captures except for some of the multiple files options, as these capture 
+   * options currently cannot be passed through the command line to the 
+   * capture child.
+   *
+   * If this is fixed, we could always use the sync mode, throwing away the 
+   * normal mode completely and doing some more cleanup. */
+/*  if (TRUE) {*/
+  if (capture_opts->sync_mode) {
     /* sync mode: do the capture in a child process */
     ret = sync_pipe_do_capture(capture_opts, is_tempfile);
     /* capture is still running */
-    set_main_window_name(title);
+    cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
   } else {
     /* normal mode: do the capture synchronously */
-    set_main_window_name(title);
+    cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
     ret = normal_do_capture(capture_opts, is_tempfile);
     /* capture is finished here */
   }
-  g_free(title);
 
   return ret;
 }
 
 
-/* start a normal capture session */
-static gboolean
-normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
+/* we've succeeded a capture, try to read it into a new capture file */
+gboolean
+capture_read(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
+guint32 drops)
 {
-    int capture_succeeded;
-    gboolean stats_known;
-    struct pcap_stat stats;
     int err;
 
-    /* Not sync mode. */
-    capture_succeeded = capture_start(capture_opts, &stats_known, &stats);
-    if (capture_opts->quit_after_cap) {
-      /* DON'T unlink the save file.  Presumably someone wants it. */
-        main_window_exit();
-    }
-    if (!capture_succeeded) {
-      /* We didn't succeed in doing the capture, so we don't have a save
-        file. */
-      if (capture_opts->multi_files_on) {
-       ringbuf_free();
-      } else {
-       g_free(capture_opts->save_file);
-      }
-      capture_opts->save_file = NULL;
-      return FALSE;
-    }
+
     /* Capture succeeded; attempt to read in the capture file. */
     if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
       /* We're not doing a capture any more, so we don't have a save
         file. */
-      if (capture_opts->multi_files_on) {
-       ringbuf_free();
-      } else {
-       g_free(capture_opts->save_file);
-      }
-      capture_opts->save_file = NULL;
       return FALSE;
     }
 
     /* Set the read filter to NULL. */
+    /* XXX - this is odd here, try to put it somewhere, where it fits better */
     cf_set_rfcode(capture_opts->cf, NULL);
 
     /* Get the packet-drop statistics.
@@ -266,7 +226,7 @@ normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
        we'll put them into the capture file that we write, and will
        thus not have to set them here - "cf_read()" will get them from
        the file and use them. */
-    if (stats_known) {
+    if (drops_known) {
       cf_set_drops_known(capture_opts->cf, TRUE);
 
       /* XXX - on some systems, libpcap doesn't bother filling in
@@ -277,7 +237,7 @@ normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
          several statistics - perhaps including various interface
          error statistics - and would tell us which of them it
          supplies, allowing us to display only the ones it does. */
-      cf_set_drops(capture_opts->cf, stats.ps_drop);
+      cf_set_drops(capture_opts->cf, drops);
     }
     switch (cf_read(capture_opts->cf)) {
 
@@ -295,15 +255,6 @@ normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
       return FALSE;
     }
 
-    /* We're not doing a capture any more, so we don't have a save
-       file. */
-    if (capture_opts->multi_files_on) {
-      ringbuf_free();
-    } else {
-      g_free(capture_opts->save_file);
-    }
-    capture_opts->save_file = NULL;
-
     /* if we didn't captured even a single packet, close the file again */
     if(cf_packet_count(capture_opts->cf) == 0) {
       simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
@@ -317,6 +268,32 @@ normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
 }
 
 
+/* start a normal capture session */
+static gboolean
+normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
+{
+    gboolean succeeded;
+    gboolean stats_known;
+    struct pcap_stat stats;
+
+
+    /* Not sync mode. */
+    succeeded = capture_loop_start(capture_opts, &stats_known, &stats);
+    if (capture_opts->quit_after_cap) {
+      /* DON'T unlink the save file.  Presumably someone wants it. */
+        main_window_exit();
+    }
+    if (succeeded) {
+        /* We succeed in doing the capture, try to read it in. */
+        succeeded = capture_read(capture_opts, is_tempfile, stats_known, stats.ps_drop);
+    }
+
+    /* wether the capture suceeded or not, we have to close the output file here */
+    capture_close_output(capture_opts);
+    return succeeded;
+}
+
+
 static void
 stop_capture_signal_handler(int signo _U_)
 {
@@ -325,35 +302,50 @@ stop_capture_signal_handler(int signo _U_)
 
 
 int  
-capture_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
+capture_child_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
 {
+  gchar *err_msg;
+
+  g_assert(capture_opts->capture_child);
+
 #ifndef _WIN32
   /*
    * Catch SIGUSR1, so that we exit cleanly if the parent process
    * kills us with it due to the user selecting "Capture->Stop".
    */
-  if (capture_opts->capture_child)
     signal(SIGUSR1, stop_capture_signal_handler);
 #endif
 
+    /* parent must have send us a file descriptor for the opened output file */
+    if (capture_opts->save_file_fd == -1) {
+      /* send this to the standard output as something our parent
+            should put in an error message box */
+      err_msg = g_strdup_printf("%s: \"-W\" flag not specified (internal error)\n", CHILD_NAME);
+      sync_pipe_errmsg_to_parent(err_msg);
+      g_free(err_msg);
+      return FALSE;
+    }
+
   return capture_loop_start(capture_opts, stats_known, stats);
 }
 
 void
 capture_stop(capture_options *capture_opts)
 {
-
-  if (capture_opts->sync_mode) {       
+  /* stop the capture child, if we have one */
+  if (!capture_opts->capture_child) {  
     sync_pipe_stop(capture_opts);
   }
-    
+
+  /* stop the capture loop */
   capture_loop_stop();
 }
 
 void
 capture_kill_child(capture_options *capture_opts)
 {
-  if (capture_opts->sync_mode) {       
+  /* kill the capture child, if we have one */
+  if (!capture_opts->capture_child) {  
     sync_pipe_kill(capture_opts);
   }
 }