Ethereal-dev: Re: [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: Mon, 10 May 1999 22:03:19 +0200
Gilbert Ramirez wrote:
> 
> 
> # ./ethereal -F -S
> User Signal 2
> 
> As soon as I get the first packet, "User Signal 2" is printed and my
> main ethereal window is not usable. If I stop the capture, no file is
> loaded into the ethereal GUI. "re-load" does nothing.
> 

Strange, the signal should be caught and generated only once but in 
the attached diff, I set again the signal handler in the handler
to allow multiple capture sessions.

This diff (to current CVS tree) contains also:

- sync every seconds (no more after n packets)
- reentrancy problem and potential stack overflow fixes
- much stable with heavy loaded network capture
- menu handling fixes (load, reload, close, capture etc.)
- pass -m / -b options to child
- miscellaneous non user visible fixes.

It was tested on Linux and Tru64 (but not on Solaris ;-)

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 --new-file ethereal/capture.c ethereal-new/capture.c
--- ethereal/capture.c	Fri Apr 30 21:52:21 1999
+++ ethereal-new/capture.c	Mon May 10 21:08:16 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,15 @@
 extern GtkWidget    *info_bar;
 extern guint         file_ctx;
 
+extern gchar *ethereal_path;
+extern gchar *medium_font;
+extern gchar *bold_font;
+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"
@@ -337,7 +348,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 +365,56 @@
   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
+       * -S sync mode
+       * -m / -b fonts
+       */
+       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", 
+	       "-m", medium_font, "-b", bold_font, 0);	
+       }
+       else 
+	 execl(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
+	       "-c",scount,"-s", ssnap,
+	       "-m", medium_font, "-b", bold_font, 0);	
+    }
+    else {
+       cf.filename = cf.save_file;
+       if (sync_mode) {
+	 close(sync_pipe[1]);
+	 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) 
+	   tail_cap_file(cf.save_file, &cf);
+	 sigusr2_received = FALSE;
+       }
+    }
+  }
+  else
+    capture();
 }
 
 void
@@ -381,6 +441,8 @@
   ld.counts.total = 0;
   ld.max          = cf.count;
   ld.linktype     = DLT_NULL;
+  ld.signal_sent  = 0;
+  ld.sync_time    = 0;
   ld.counts.tcp   = 0;
   ld.counts.udp   = 0;
   ld.counts.ospf  = 0;
@@ -401,6 +463,7 @@
       pcap_close(pch);
       return;
     }
+
     ld.linktype = pcap_datalink(pch);
 
     if (cf.cfilter) {
@@ -504,6 +567,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);
@@ -535,6 +603,7 @@
   const u_char *pd) {
   
   loop_data *ld = (loop_data *) user;
+  time_t *sync_time= &ld->sync_time, cur_time;
   
   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
   {
@@ -543,6 +612,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);
   
+  cur_time = time(NULL);
+  if (cur_time > *sync_time) {
+    /* sync every seconds */
+    *sync_time = cur_time;
+    fflush((FILE *)ld->pdh);
+    if (sync_mode) 
+      write(1, "D", 1);
+  }
+
   switch (ld->linktype) {
     case DLT_EN10MB :
       capture_eth(pd, phdr->caplen, &ld->counts);
@@ -563,4 +641,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 --new-file ethereal/capture.h ethereal-new/capture.h
--- ethereal/capture.h	Fri Apr 30 21:52:21 1999
+++ ethereal-new/capture.h	Mon May 10 20:30:33 1999
@@ -30,6 +30,8 @@
   gint           go;
   gint           max;
   gint           linktype;
+  gint           signal_sent;
+  time_t         sync_time;
   packet_counts  counts;
   pcap_dumper_t *pdh;
 } loop_data;
diff -u --new-file ethereal/ethereal.c ethereal-new/ethereal.c
--- ethereal/ethereal.c	Fri May  7 19:35:30 1999
+++ ethereal-new/ethereal.c	Mon May 10 21:27:03 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,20 @@
 frame_data  *fd;
 gint         start_capture = 0;
 gchar        comp_info_str[256];
+gchar       *ethereal_path = NULL;
+gchar       *medium_font = MONO_MEDIUM_FONT;
+gchar       *bold_font = MONO_BOLD_FONT;
 
 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 +291,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 +421,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 +506,17 @@
 #endif
   }
   if (start_capture) {
-    if (cf.save_file)
-      capture();
-    else
-      capture();
+    capture();
     start_capture = 0;
   }
 }
 
+static void 
+sigusr2_handler(int sig) {
+  sigusr2_received = 1;
+  signal(SIGUSR2, sigusr2_handler);
+}
+
 static void
 ethereal_proto_init(void) {
 
@@ -539,19 +557,23 @@
 #endif
   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
   gchar               *rc_file, *cf_name = NULL;
-  gchar               *medium_font = MONO_MEDIUM_FONT;
-  gchar               *bold_font = MONO_BOLD_FONT;
   e_prefs             *prefs;
   gint                *col_fmt;
   gchar              **col_title;
 
+  ethereal_path = argv[0];
+  sync_pipe[0] = -1;
+  sync_pipe[1] = -1;
+
   /* 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 +606,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 +617,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 +639,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 +679,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 --new-file ethereal/file.c ethereal-new/file.c
--- ethereal/file.c	Fri Apr 30 21:52:29 1999
+++ ethereal-new/file.c	Mon May 10 21:26:00 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);
@@ -318,6 +324,102 @@
   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);
+    cf->plist = g_list_first(cf->plist);
+#ifdef USE_ITEM
+    set_menu_sensitivity("/File/Open", TRUE);
+    set_menu_sensitivity("/File/Close", TRUE);
+    set_menu_sensitivity("/File/Save as", TRUE);
+    set_menu_sensitivity("/File/Reload", TRUE);
+    set_menu_sensitivity("/Tools/Capture", TRUE);
+#else
+    set_menu_sensitivity("<Main>/File/Open", TRUE);
+    set_menu_sensitivity("<Main>/File/Close", TRUE);
+    set_menu_sensitivity("<Main>/File/Save as", TRUE);
+    set_menu_sensitivity("<Main>/File/Reload", TRUE);
+    set_menu_sensitivity("<Main>/Tools/Capture", TRUE);
+#endif
+    sync_pipe[0] = -1;
+    return;
+  }
+
+  gtk_clist_freeze(GTK_CLIST(packet_list));
+#ifdef WITH_WIRETAP
+  wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
+#else
+  pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
+#endif
+  gtk_clist_thaw(GTK_CLIST(packet_list));
+}
+
+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/Open", FALSE);
+    set_menu_sensitivity("/File/Close", FALSE);
+    set_menu_sensitivity("/File/Reload", FALSE);
+    set_menu_sensitivity("/Tools/Capture", FALSE);
+#else
+    set_menu_sensitivity("<Main>/File/Open", FALSE);
+    set_menu_sensitivity("<Main>/File/Close", FALSE);
+    set_menu_sensitivity("<Main>/File/Reload", FALSE);
+    set_menu_sensitivity("<Main>/Tools/Capture", 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,
+				       NULL);
+  }
+  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
+    close(sync_pipe[0]);
+    sync_pipe[0] = -1;
+  }
+  return err;
+}
+
+
 static void
 #ifdef WITH_WIRETAP
 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
@@ -328,7 +430,12 @@
   frame_data   *fdata;
   gint          i, row;
   capture_file *cf = (capture_file *) user;
-  
+
+  if (sync_mode && sync_pipe[0] != -1) {
+    /* avoid reentrancy problems and stack overflow */
+    gtk_input_remove(cap_input_id);
+  }
+
   while (gtk_events_pending())
     gtk_main_iteration();
 
@@ -342,7 +449,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;
@@ -399,4 +506,15 @@
     g_list_append(cf->plist, (gpointer) fdata);
   }
   cf->plist = cf->plist->next;
+
+  if (sync_mode && sync_pipe[0] != -1) {
+    /* restore pipe handler */
+    cap_input_id = gtk_input_add_full (sync_pipe[0],
+				       GDK_INPUT_READ,
+				       cap_file_input_cb,
+				       NULL,
+				       (gpointer) cf,
+				       NULL);
+  }
+
 }
diff -u --new-file ethereal/file.h ethereal-new/file.h
--- ethereal/file.h	Fri Apr 30 21:52:29 1999
+++ ethereal-new/file.h	Mon May 10 21:08:50 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 */
@@ -120,6 +121,7 @@
 int  open_cap_file(char *, capture_file *);
 void close_cap_file(capture_file *, void *, guint);
 int  load_cap_file(char *, capture_file *);
+int  tail_cap_file(char *, capture_file *);
 /* size_t read_frame_header(capture_file *); */
 
 #endif /* file.h */