Ethereal-dev: [ethereal-dev] more real-time capture and full display

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

From: Laurent Deniel <deniel@xxxxxxxxxxx>
Date: Sat, 08 May 1999 18:36:08 +0200
 Hi all,

 Here is a diff to current CVS tree that enhances the -S option of 
 John patch :

 - now, capture and full display of decoded packet are possible at the 
   same time !
 - open/reload is no more needed
 - the child uses a pipe to sync the father
 - the father is able to read the cap file at reception of something
   in the pipe (make use of gtk_input_add_full)
 - sync is performed every DUMP_FREQ packets (should be configurable)
 - the father is able to detect that the child has ended or crashed
 - the child ends if the father exits (SIGPIPE)
 - the father automatically opens the cap file when the child starts
   and captures at least one packet
 - SIGUSR1 and sleep are no more needed
 - the problem of execlp is fixed (use execl with correct PATH).

 Sorry Gilbert, I have not yet tested this patch with wiretap.

 Laurent.

--
Laurent DENIEL            | E-mail: deniel@xxxxxxxxxxx
Paris, FRANCE             |         deniel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx
                          | WWW   : http://www.worldnet.fr/~deniel
    All above opinions are personal, unless stated otherwise.
diff -u --recursive --new-file ethereal/capture.c ethereal-new/capture.c
--- ethereal/capture.c	Fri Apr 30 21:52:21 1999
+++ ethereal-new/capture.c	Sat May  8 18:00:47 1999
@@ -43,6 +43,8 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <signal.h>
+#include <errno.h>
 
 #ifdef NEED_SNPRINTF_H
 # ifdef HAVE_STDARG_H
@@ -70,6 +72,13 @@
 extern GtkWidget    *info_bar;
 extern guint         file_ctx;
 
+extern gchar *ethereal_path;
+extern int fork_mode;
+extern int sync_pipe[];
+extern int sync_mode;
+extern int sigusr2_received;
+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 +93,9 @@
 /* Capture filter key */
 #define E_CAP_FILT_TE_KEY "cap_filt_te"
 
+/* how often to force an fflush */
+#define DUMP_FREQ 4
+
 GList *
 get_interface_list() {
   GList  *il = NULL;
@@ -337,7 +349,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 +366,53 @@
   cf.save_file = tempnam(NULL, "ether");
   cf.user_saved = 0;
   
-  capture();
+  if( fork_mode ){	/*  use fork() for capture */
+    int  fork_child;
+    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 (sync_mode) pipe(sync_pipe);
+    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
+       */
+       if (sync_mode) {
+	 close(1);
+	 dup(sync_pipe[1]);
+	 close(sync_pipe[0]);
+	 execl(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
+	       "-c",scount,"-s", ssnap, "-S", 0);	
+       }
+       else 
+	 execl(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
+	       "-c",scount,"-s", ssnap,0);
+    }
+    else {
+       cf.filename = cf.save_file;
+       close(sync_pipe[1]);
+       if (sync_mode) {
+	 while (!sigusr2_received) {
+	   struct timeval timeout = {1,0};
+	   select(0, NULL, NULL, NULL, &timeout);
+	   if (kill(fork_child, 0) == -1 && errno == ESRCH) 
+	     break;
+	 }
+	 if (sigusr2_received) 
+	   load_cap_file(cf.save_file, &cf);
+	 sigusr2_received = FALSE;
+       }
+    }
+  }
+  else
+    capture();
 }
 
 void
@@ -381,6 +439,7 @@
   ld.counts.total = 0;
   ld.max          = cf.count;
   ld.linktype     = DLT_NULL;
+  ld.signal_sent  = 0;
   ld.counts.tcp   = 0;
   ld.counts.udp   = 0;
   ld.counts.ospf  = 0;
@@ -401,6 +460,7 @@
       pcap_close(pch);
       return;
     }
+
     ld.linktype = pcap_datalink(pch);
 
     if (cf.cfilter) {
@@ -504,6 +564,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 +599,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 +609,15 @@
   /* 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);
+    if (sync_mode) 
+      write(1, "D", 1);
+  }
+  dump_count = (dump_count + 1) % DUMP_FREQ;
+
   switch (ld->linktype) {
     case DLT_EN10MB :
       capture_eth(pd, phdr->caplen, &ld->counts);
@@ -563,4 +638,13 @@
       capture_raw(pd, phdr->caplen, &ld->counts);
       break;
   }
+
+  if (sync_mode && !ld->signal_sent) {
+    /* will trigger the father to open the cap file which contains 
+       at least one complete packet */
+    fflush((FILE *)ld->pdh);
+    kill(getppid(), SIGUSR2);
+    ld->signal_sent = 1;
+  }
+  
 }
diff -u --recursive --new-file ethereal/capture.h ethereal-new/capture.h
--- ethereal/capture.h	Fri Apr 30 21:52:21 1999
+++ ethereal-new/capture.h	Sat May  8 17:52:48 1999
@@ -30,6 +30,7 @@
   gint           go;
   gint           max;
   gint           linktype;
+  gint           signal_sent;
   packet_counts  counts;
   pcap_dumper_t *pdh;
 } loop_data;
diff -u --recursive --new-file ethereal/ethereal.c ethereal-new/ethereal.c
--- ethereal/ethereal.c	Fri May  7 19:35:30 1999
+++ ethereal-new/ethereal.c	Sat May  8 18:01:51 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
@@ -92,11 +93,18 @@
 frame_data  *fd;
 gint         start_capture = 0;
 gchar        comp_info_str[256];
+gchar       *ethereal_path = NULL;
 
 ts_type timestamp_type = RELATIVE;
 
 GtkStyle *item_style;
 
+int sync_mode;	/* allow sync */
+int sync_pipe[2]; /* used to sync father */
+int fork_mode;	/* fork a child to do the capture */
+int sigusr2_received = 0;
+int quit_after_cap; /* Makes a "capture only mode". Implies -k */
+
 #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);
 }
@@ -408,17 +419,19 @@
 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
   GList      *l;
 
+  if (!sync_mode) {
 #ifdef WITH_WIRETAP
   if (cf.wth) return; 
 #else
   if (cf.pfh) return;
 #endif
+  }
   blank_packetinfo();
   gtk_text_freeze(GTK_TEXT(byte_view));
   gtk_text_set_point(GTK_TEXT(byte_view), 0);
   gtk_text_forward_delete(GTK_TEXT(byte_view),
     gtk_text_get_length(GTK_TEXT(byte_view)));
-  l = g_list_nth(cf.plist, row);
+  l = g_list_nth(cf.plist_first, row);
   if (l) {
     fd = (frame_data *) l->data;
     fseek(cf.fh, fd->file_off, SEEK_SET);
@@ -491,14 +504,16 @@
 #endif
   }
   if (start_capture) {
-    if (cf.save_file)
-      capture();
-    else
-      capture();
+    capture();
     start_capture = 0;
   }
 }
 
+static void 
+sigusr2_handler(int sig) {
+  sigusr2_received = 1;
+}
+
 static void
 ethereal_proto_init(void) {
 
@@ -545,13 +560,17 @@
   gint                *col_fmt;
   gchar              **col_title;
 
+  ethereal_path = argv[0];
+
   /* Let GTK get its args */
   gtk_init (&argc, &argv);
+  
 
   prefs = read_prefs();
     
   /* Initialize the capture file struct */
   cf.plist		= NULL;
+  cf.plist_first       	= NULL;
 #ifdef WITH_WIRETAP
   cf.wth		= NULL;
 #else
@@ -584,7 +603,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 +614,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 +636,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 +676,9 @@
 	break;
     }
   }
+
+  if (sync_mode)
+    signal(SIGUSR2, sigusr2_handler);
 
   /* Build the column format array */  
   col_fmt   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
diff -u --recursive --new-file ethereal/file.c ethereal-new/file.c
--- ethereal/file.c	Fri Apr 30 21:52:29 1999
+++ ethereal-new/file.c	Sat May  8 18:12:32 1999
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #ifdef NEED_SNPRINTF_H
 # ifdef HAVE_STDARG_H
@@ -66,6 +67,10 @@
 
 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
 extern guint      file_ctx;
+extern int	  sync_mode;
+extern int        sync_pipe[];
+
+guint cap_input_id;
 
 static guint32 firstsec, firstusec;
 static guint32 lastsec, lastusec;
@@ -128,6 +133,7 @@
   cf->snap  = 0;
   if (cf->plist == NULL) {
     cf->plist       = g_list_alloc();
+    cf->plist_first = cf->plist;
     cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data));
   } else {
     cf->plist = g_list_first(cf->plist);
@@ -229,6 +235,8 @@
   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
 }
 
+static int tail_cap_file(char *, capture_file *);
+
 int
 load_cap_file(char *fname, capture_file *cf) {
   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
@@ -238,6 +246,9 @@
   size_t  msg_len;
   int     err;
 
+  if (sync_mode) 
+    return tail_cap_file(fname, cf);
+
   close_cap_file(cf, info_bar, file_ctx);
 
   /* Initialize protocol-speficic variables */
@@ -318,6 +329,92 @@
   return err;
 }
 
+void 
+cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
+  
+  capture_file *cf = (capture_file *)data;
+  char buffer[256];
+
+  if (read(sync_pipe[0], buffer, 256) <= 0) {
+#ifdef WITH_WIRETAP
+    wtap_close(cf->wth);
+    cf->wth = NULL;
+#else
+    pcap_close(cf->pfh);
+    cf->pfh = NULL;
+#endif
+    gtk_input_remove(cap_input_id);
+    return;
+  }
+
+  gtk_clist_freeze(GTK_CLIST(packet_list));
+#ifdef WITH_WIRETAP
+  wtap_loop(cf->wth, 0 /* or DUMP_FREQ */, wtap_dispatch_cb, (u_char *) cf);      
+#else
+  pcap_loop(cf->pfh, 0 /* or DUMP_FREQ */, pcap_dispatch_cb, (u_char *) cf);
+#endif
+  gtk_clist_thaw(GTK_CLIST(packet_list));
+}
+
+void 
+cap_file_destroy_cb (gpointer data) {
+  capture_file *cf = (capture_file *)data;
+  cf->plist = g_list_first(cf->plist);
+#ifdef USE_ITEM
+  set_menu_sensitivity("/File/Save as", TRUE);
+#else
+  set_menu_sensitivity("<Main>/File/Save as", TRUE);
+#endif
+}
+
+int
+tail_cap_file(char *fname, capture_file *cf) {
+  int     err;
+
+  close_cap_file(cf, info_bar, file_ctx);
+
+  /* Initialize protocol-speficic variables */
+  ncp_init_protocol();
+  
+  err = open_cap_file(fname, cf);
+#ifdef WITH_WIRETAP
+  if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
+#else
+  if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
+#endif
+
+#ifdef USE_ITEM
+    set_menu_sensitivity("/File/Close", TRUE);
+    set_menu_sensitivity("/File/Reload", FALSE);
+#else
+    set_menu_sensitivity("<Main>/File/Close", TRUE);
+    set_menu_sensitivity("<Main>/File/Reload", FALSE);
+#endif
+    cf->fh = fopen(fname, "r");
+    cap_input_id = gtk_input_add_full (sync_pipe[0],
+				       GDK_INPUT_READ,
+				       cap_file_input_cb,
+				       NULL,
+				       (gpointer) cf,
+				       cap_file_destroy_cb);
+  }
+  else {
+#ifdef USE_ITEM
+    set_menu_sensitivity("/File/Close", FALSE);
+    set_menu_sensitivity("/File/Save", FALSE);
+    set_menu_sensitivity("/File/Save as", FALSE);
+    set_menu_sensitivity("/File/Reload", FALSE);
+#else
+    set_menu_sensitivity("<Main>/File/Close", FALSE);
+    set_menu_sensitivity("<Main>/File/Save", FALSE);
+    set_menu_sensitivity("<Main>/File/Save as", FALSE);
+    set_menu_sensitivity("<Main>/File/Reload", FALSE);
+#endif
+  }
+  return err;
+}
+
+
 static void
 #ifdef WITH_WIRETAP
 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
@@ -342,7 +439,7 @@
   fdata->file_off = offset;
   fdata->lnk_t = phdr->pkt_encap;
 #else
-  fdata->file_off = ftell(cf->fh) - phdr->caplen;
+  fdata->file_off = ftell(pcap_file(cf->pfh)) - phdr->caplen;
 #endif
   fdata->abs_secs  = phdr->ts.tv_sec;
   fdata->abs_usecs = phdr->ts.tv_usec;
diff -u --recursive --new-file ethereal/file.h ethereal-new/file.h
--- ethereal/file.h	Fri Apr 30 21:52:29 1999
+++ ethereal-new/file.h	Sat May  8 17:56:44 1999
@@ -92,6 +92,7 @@
    */
   /*guint8      pd[MAX_PACKET_SIZE];*/  /* Packet data */
   guint8      pd[65536];  /* Packet data */
+  GList      *plist_first;/* First packet in list */
   GList      *plist;     /* Packet list */
   frame_data *cur;       /* Current list item */
   column_info  cinfo;    /* Column formatting information */