Ethereal-dev: [ethereal-dev] John's almost-real-time capture

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Gilbert Ramirez <gram@xxxxxxxxxx>
Date: Thu, 6 May 1999 14:45:08 -0500
Can someone else test this patch to ethereal? It works fine on John's
red hat box, but I cannot get it to work on my Debian Linux box or on my
Solaris 2.6 box.

To invoke, use "ethereal -F" or "ethereal -F -S".

When I try to capture after doing this, I get Xlib errors! This is with
both gtk+-1.0 and gtk+-1.2.

--gilbert
diff -urN ethereal/capture.c ethereal-rtcap/capture.c
--- ethereal/capture.c	Mon May  3 16:14:24 1999
+++ ethereal-rtcap/capture.c	Mon May  3 13:27:13 1999
@@ -43,6 +43,7 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <signal.h>
 
 #ifdef NEED_SNPRINTF_H
 # ifdef HAVE_STDARG_H
@@ -70,6 +71,10 @@
 extern GtkWidget    *info_bar;
 extern guint         file_ctx;
 
+extern int fork_mode;
+int fork_child;
+extern int quit_after_cap;
+
 /* File selection data keys */
 #define E_CAP_PREP_FS_KEY "cap_prep_fs"
 #define E_CAP_PREP_TE_KEY "cap_prep_te"
@@ -84,6 +89,10 @@
 /* Capture filter key */
 #define E_CAP_FILT_TE_KEY "cap_filt_te"
 
+/* how often to force an fflush */
+#define DUMP_FREQ 4
+FILE *dump_file_handle;
+
 GList *
 get_interface_list() {
   GList  *il = NULL;
@@ -337,7 +346,7 @@
 	  cf.cfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); 
   }
   cf.count =
-    atoi(g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry))));
+    atoi( g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry))));
   cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
   if (cf.snap < 1)
     cf.snap = MAX_PACKET_SIZE;
@@ -354,7 +363,31 @@
   cf.save_file = tempnam(NULL, "ether");
   cf.user_saved = 0;
   
-  capture();
+  if( fork_mode ){	/*  use fork() for capture */
+    char ssnap[24];
+    char scount[24];	/* need a constant for len of numbers */
+
+    sprintf(ssnap,"%d",cf.snap); /* in liu of itoa */
+    sprintf(scount,"%d",cf.count);
+    signal(SIGCHLD, SIG_IGN);
+    if((fork_child = fork()) == 0){
+      /* args: -k -- capture
+       * -i interface specification
+       * -w file to write
+       * -c count to capture
+       * -Q quit after capture (forces -k)
+       * -s snaplen
+       * should add  -b -m -t from this invocation: TODO
+       */
+	  execlp("ethereal","ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
+	    "-c",scount,"-s", ssnap,0);
+    }
+    else {
+       cf.filename = cf.save_file;
+    }
+  }
+  else
+    capture();
 }
 
 void
@@ -401,6 +434,9 @@
       pcap_close(pch);
       return;
     }
+    /* save the file handle for flushing when a SIGUSR1 arrives */
+    dump_file_handle = (FILE *)ld.pdh; 
+
     ld.linktype = pcap_datalink(pch);
 
     if (cf.cfilter) {
@@ -504,6 +540,11 @@
       "that you have the proper interface specified.");
   }
 
+  if( quit_after_cap ){
+    /* DON'T unlink the save file.  Presumably someone wants it. */
+    gtk_exit(0);
+  }
+
   if (cf.save_file) load_cap_file(cf.save_file, &cf);
 #ifdef USE_ITEM
     set_menu_sensitivity("/File/Save", TRUE);
@@ -534,6 +575,7 @@
 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd) {
   
+  static int dump_count = 0;
   loop_data *ld = (loop_data *) user;
   
   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
@@ -543,6 +585,13 @@
   /* 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);
   
+  /* flush every DUMP_FREQ times */
+  
+  if ( !dump_count  ){
+	fflush((FILE *)ld->pdh);
+  }
+  dump_count = (dump_count + 1) % DUMP_FREQ;
+
   switch (ld->linktype) {
     case DLT_EN10MB :
       capture_eth(pd, phdr->caplen, &ld->counts);
diff -urN ethereal/ethereal.c ethereal-rtcap/ethereal.c
--- ethereal/ethereal.c	Mon May  3 16:15:04 1999
+++ ethereal-rtcap/ethereal.c	Mon May  3 13:33:24 1999
@@ -55,6 +55,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <netinet/in.h>
+#include <signal.h>
 
 #ifdef NEED_SNPRINTF_H
 # ifdef HAVE_STDARG_H
@@ -97,6 +98,13 @@
 
 GtkStyle *item_style;
 
+int sync_mode;	/* allow sync */
+
+int fork_mode;	/* fork a child to do the capture */
+extern int fork_child;
+int quit_after_cap; /* Makes a "capture only mode". Implies -k */
+extern FILE *dump_file_handle;
+
 #define E_DFILTER_TE_KEY "display_filter_te"
 
 /* About Ethereal window */
@@ -281,7 +289,10 @@
     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
     gtk_widget_destroy, GTK_OBJECT (file_sel));
 
-  gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
+  if( fork_mode && (cf.save_file != NULL) )
+    gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
+  else
+    gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
 
   gtk_widget_show(file_sel);
 }
@@ -394,6 +405,28 @@
 
   if (cf.dfilter) g_free(cf.dfilter);
   cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
+  /* JJM */
+
+  /* MUST check fork_mode to see 1) if we have a "fork_child" value, and 2) if
+   * the process will catch the signal
+   */
+  if( sync_mode && fork_mode){
+    /* first, see if the child is still there */
+    if( !kill(fork_child, 0)){
+      /* we can talk to our child */
+      kill(fork_child, SIGUSR1);
+      /* wait for the file to be written.  Probably should pass my pid to child so it
+       * can signal us back when it is done.  Then our handler could emit a gtk signal
+       * to force reloading.  As it stands I am hoping that we can make this threaded
+       * (using gtk or pthreads) and hence not need this ugliness.
+       */
+
+      /* might cause trouble: both sleep and the itimer use SIGALRM.  We use
+       * SIGALRM for dns timeouts.
+       */
+      sleep(2); /* not long enough under heavy load */
+    }
+  }
   load_cap_file(cf.filename, &cf);
 }
 
@@ -491,10 +524,7 @@
 #endif
   }
   if (start_capture) {
-    if (cf.save_file)
-      capture();
-    else
-      capture();
+    capture();
     start_capture = 0;
   }
 }
@@ -518,6 +548,16 @@
   fprintf(stderr, "         [-T tree view height] [-w savefile] \n");
 }
 
+/* if we get SIGUSR1 flush the buffer.  Allows sync by someone watching our dump */
+void
+flushit (int sig)
+{
+    if(dump_file_handle)
+        fflush(dump_file_handle);
+    signal(SIGUSR1, flushit);
+}
+
+
 /* And now our feature presentation... [ fade to music ] */
 int
 main(int argc, char *argv[])
@@ -545,8 +585,10 @@
   gint                *col_fmt;
   gchar              **col_title;
 
+
   /* Let GTK get its args */
   gtk_init (&argc, &argv);
+  
 
   prefs = read_prefs();
     
@@ -584,7 +626,7 @@
 #endif
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "b:B:c:hi:m:nP:r:s:t:T:w:v")) != EOF) {
+  while ((opt = getopt(argc, argv, "b:B:c:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
     switch (opt) {
       case 'b':	       /* Bold font */
 	bold_font = g_strdup(optarg);
@@ -595,6 +637,9 @@
       case 'c':        /* Capture xxx packets */
         cf.count = atoi(optarg);
         break;
+      case 'F':	       /* Fork to capture */
+        fork_mode = 1;
+        break;
       case 'h':        /* Print help and exit */
 	print_usage();
 	exit(0);
@@ -614,12 +659,19 @@
       case 'P':        /* Packet list pane height */
         pl_size = atoi(optarg);
         break;
+      case 'Q':        /* Quit after capture (just capture to file) */
+        quit_after_cap = 1;
+        start_capture = 1;  /*** -Q implies -k !! ***/
+        break;
       case 'r':        /* Read capture file xxx */
         cf_name = g_strdup(optarg);
         break;
       case 's':        /* Set the snapshot (capture) length */
         cf.snap = atoi(optarg);
         break;
+      case 'S':        /* "Sync" mode: used for following file ala tail -f */
+        sync_mode = 1;
+        break;
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
           timestamp_type = RELATIVE;
@@ -647,6 +699,9 @@
 	break;
     }
   }
+
+  if( start_capture)
+    signal(SIGUSR1, flushit); /* catch the flush signal */
 
   /* Build the column format array */  
   col_fmt   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);