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);
- Follow-Ups:
- Re: [ethereal-dev] John's almost-real-time capture
- From: Laurent Deniel
- Re: [ethereal-dev] John's almost-real-time capture
- From: Guy Harris
- Re: [ethereal-dev] John's almost-real-time capture
- Prev by Date: [ethereal-dev] Linux Weekly News.
- Next by Date: Re: [ethereal-dev] John's almost-real-time capture
- Previous by thread: [ethereal-dev] Linux Weekly News.
- Next by thread: Re: [ethereal-dev] John's almost-real-time capture
- Index(es):