aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2001-12-04 07:32:05 +0000
committerGuy Harris <guy@alum.mit.edu>2001-12-04 07:32:05 +0000
commita1660d6d3afbaeccd77d8e34c695bf65a4f4f09e (patch)
tree20e71ed2ee0399b430f10ab92177fb1d5fc7e953
parent9426c4ad15826cee237cc1f822c8a758d01473f6 (diff)
Support for stopping capture at specified capture file size or capture
duration, from Thomas Wittwer and Matthias Nyffenegger. svn path=/trunk/; revision=4322
-rw-r--r--AUTHORS7
-rw-r--r--Makefile.am6
-rw-r--r--Makefile.nmake6
-rw-r--r--capture.c37
-rw-r--r--capture_stop_conditions.c208
-rw-r--r--capture_stop_conditions.h29
-rw-r--r--conditions.c205
-rw-r--r--conditions.h134
-rw-r--r--doc/ethereal.pod.template27
-rw-r--r--doc/tethereal.pod.template26
-rw-r--r--file.h6
-rw-r--r--gtk/capture_dlg.c124
-rw-r--r--gtk/main.c73
-rw-r--r--tethereal.c127
-rw-r--r--wiretap/file.c8
-rw-r--r--wiretap/libpcap.c6
-rw-r--r--wiretap/wtap-int.h3
-rw-r--r--wiretap/wtap.def1
-rw-r--r--wiretap/wtap.h3
19 files changed, 984 insertions, 52 deletions
diff --git a/AUTHORS b/AUTHORS
index 9a94cba80e..53c4b3ff8a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -805,6 +805,13 @@ Thomas Wittwer <thomas.wittwer[AT]iclip.ch> {
HTTP dissector registered by name
"prefs_register_string_preference()" made available to plugins
Remove unnecessary calls to "prefs_module_foreach()"
+ Support for stopping capture at specified capture file size or
+ capture duration
+}
+
+Matthias Nyffenegger <matthias.nyffenegger[AT]iclip.ch> {
+ Support for stopping capture at specified capture file size or
+ capture duration
}
Palle Lyckegaard <Palle[AT]lyckegaard.dk> {
diff --git a/Makefile.am b/Makefile.am
index 545a38c058..9a87c8aaf5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.389 2001/12/03 20:18:29 guy Exp $
+# $Id: Makefile.am,v 1.390 2001/12/04 07:31:59 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -441,6 +441,10 @@ ETHEREAL_COMMON_SRC = \
column.c \
column.h \
color.h \
+ conditions.c \
+ conditions.h \
+ capture_stop_conditions.h \
+ capture_stop_conditions.c \
etypes.h \
follow.c \
follow.h \
diff --git a/Makefile.nmake b/Makefile.nmake
index 244441c212..fcfcdeb300 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.148 2001/12/03 20:18:29 guy Exp $
+# $Id: Makefile.nmake,v 1.149 2001/12/04 07:32:00 guy Exp $
include config.nmake
include <win32.mak>
@@ -247,8 +247,10 @@ DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj)
ETHEREAL_COMMON_OBJECTS = \
afn.obj \
asn1.obj \
- capture-wpcap.obj \
+ capture_stop_conditions.obj \
+ capture-wpcap.obj \
column.obj \
+ conditions.obj \
follow.obj \
getopt.obj \
in_cksum.obj \
diff --git a/capture.c b/capture.c
index e485b1fd4f..953982c82d 100644
--- a/capture.c
+++ b/capture.c
@@ -1,7 +1,7 @@
/* capture.c
* Routines for packet capture windows
*
- * $Id: capture.c,v 1.161 2001/11/30 07:14:20 guy Exp $
+ * $Id: capture.c,v 1.162 2001/12/04 07:32:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -145,6 +145,8 @@
#include "simple_dialog.h"
#include "prefs.h"
#include "globals.h"
+#include "conditions.h"
+#include "capture_stop_conditions.h"
#include "wiretap/libpcap.h"
#include "wiretap/wtap.h"
@@ -311,7 +313,9 @@ do_capture(char *capfile_name)
if (prefs.capture_real_time) { /* do the capture in a child process */
char ssnap[24];
- char scount[24]; /* need a constant for len of numbers */
+ char scount[24]; /* need a constant for len of numbers */
+ char sautostop_filesize[24]; /* need a constant for len of numbers */
+ char sautostop_duration[24]; /* need a constant for len of numbers */
char save_file_fd[24];
char errmsg[1024+1];
int error;
@@ -350,6 +354,14 @@ do_capture(char *capfile_name)
sprintf(ssnap,"%d",cfile.snap);
argv = add_arg(argv, &argc, ssnap);
+ argv = add_arg(argv, &argc, "-a");
+ sprintf(sautostop_filesize,"filesize:%u",cfile.autostop_filesize);
+ argv = add_arg(argv, &argc, sautostop_filesize);
+
+ argv = add_arg(argv, &argc, "-a");
+ sprintf(sautostop_duration,"duration:%d",cfile.autostop_duration);
+ argv = add_arg(argv, &argc, sautostop_duration);
+
if (!prefs.capture_prom_mode)
argv = add_arg(argv, &argc, "-p");
@@ -1217,6 +1229,8 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
struct bpf_program fcode;
time_t upd_time, cur_time;
int err, inpkts;
+ condition *cnd_stop_capturesize;
+ condition *cnd_stop_timeout;
unsigned int i;
static const char capstart_msg = SP_CAPSTART;
char errmsg[4096+1];
@@ -1537,6 +1551,14 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
*/
signal(SIGUSR1, stop_capture);
#endif
+ /* initialize capture stop conditions */
+ init_capture_stop_conditions();
+ /* create stop conditions */
+ cnd_stop_capturesize =
+ cnd_new(CND_CLASS_CAPTURESIZE,(guint32)cfile.autostop_filesize * 1000);
+ cnd_stop_timeout =
+ cnd_new(CND_CLASS_TIMEOUT,(gint32)cfile.autostop_duration);
+
while (ld.go) {
while (gtk_events_pending()) gtk_main_iteration();
@@ -1606,6 +1628,13 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
}
if (inpkts > 0)
ld.sync_packets += inpkts;
+ /* check capture stop conditons */
+ if (cnd_eval(cnd_stop_timeout) == TRUE) {
+ ld.go = FALSE;
+ } else if ((cnd_eval(cnd_stop_capturesize,
+ (guint32)wtap_get_bytes_dumped(ld.pdh))) == TRUE){
+ ld.go = FALSE;
+ }
/* Only update once a second so as not to overload slow displays */
cur_time = time(NULL);
if (cur_time > upd_time) {
@@ -1637,6 +1666,10 @@ capture(gboolean *stats_known, struct pcap_stat *stats)
}
}
+ /* delete stop conditions */
+ cnd_delete(cnd_stop_capturesize);
+ cnd_delete(cnd_stop_timeout);
+
if (ld.err != 0) {
get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, ld.err,
FALSE);
diff --git a/capture_stop_conditions.c b/capture_stop_conditions.c
new file mode 100644
index 0000000000..d86bf73245
--- /dev/null
+++ b/capture_stop_conditions.c
@@ -0,0 +1,208 @@
+/* capture_stop_conditions.c
+ * Implementation for 'stop condition handler'.
+ *
+ * $Id: capture_stop_conditions.c,v 1.1 2001/12/04 07:32:00 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include "conditions.h"
+#include "capture_stop_conditions.h"
+
+/* predefined classes function prototypes */
+static condition* _cnd_constr_timeout(condition*, va_list);
+static void _cnd_destr_timeout(condition*);
+static gboolean _cnd_eval_timeout(condition*, va_list);
+static void _cnd_reset_timeout(condition*);
+
+static condition* _cnd_constr_capturesize(condition*, va_list);
+static void _cnd_destr_capturesize(condition*);
+static gboolean _cnd_eval_capturesize(condition*, va_list);
+static void _cnd_reset_capturesize(condition*);
+
+void init_capture_stop_conditions(void){
+ cnd_register_class(CND_CLASS_TIMEOUT,
+ _cnd_constr_timeout,
+ _cnd_destr_timeout,
+ _cnd_eval_timeout,
+ _cnd_reset_timeout);
+ cnd_register_class(CND_CLASS_CAPTURESIZE,
+ _cnd_constr_capturesize,
+ _cnd_destr_capturesize,
+ _cnd_eval_capturesize,
+ _cnd_reset_capturesize);
+} /* END init_capture_stop_conditions() */
+
+void cleanup_capture_stop_conditions(void){
+ cnd_unregister_class(CND_CLASS_TIMEOUT);
+ cnd_unregister_class(CND_CLASS_CAPTURESIZE);
+} /* END cleanup_capture_stop_conditions() */
+
+/*****************************************************************************/
+/* Predefined condition 'timeout'. */
+
+/* class id */
+const char* CND_CLASS_TIMEOUT = "cnd_class_timeout";
+
+/* structure that contains user supplied data for this condition */
+typedef struct _cnd_timeout_dat{
+ time_t start_time;
+ gint32 timeout_s;
+}cnd_timeout_dat;
+
+/*
+ * Constructs new condition for timeout check. This function is invoked by
+ * 'cnd_new()' in order to perform class specific initialization.
+ *
+ * parameter: cnd - Pointer to condition passed by 'cnd_new()'.
+ * ap - Pointer to user supplied arguments list for this
+ * constructor.
+ * returns: Pointer to condition - Construction was successful.
+ * NULL - Construction failed.
+ */
+static condition* _cnd_constr_timeout(condition* cnd, va_list ap){
+ cnd_timeout_dat *data = NULL;
+ /* allocate memory */
+ if((data = (cnd_timeout_dat*)malloc(sizeof(cnd_timeout_dat))) == NULL)
+ return NULL;
+ /* initialize user data */
+ data->start_time = time(NULL);
+ data->timeout_s = va_arg(ap, gint32);
+ cnd_set_user_data(cnd, (void*)data);
+ return cnd;
+} /* END _cnd_constr_timeout() */
+
+/*
+ * Destroys condition for timeout check. This function is invoked by
+ * 'cnd_delete()' in order to perform class specific clean up.
+ *
+ * parameter: cnd - Pointer to condition passed by 'cnd_delete()'.
+ */
+static void _cnd_destr_timeout(condition* cnd){
+ /* free memory */
+ free(cnd_get_user_data(cnd));
+} /* END _cnd_destr_timeout() */
+
+/*
+ * Condition handler for timeout condition. This function is invoked by
+ * 'cnd_eval()' in order to perform class specific condition checks.
+ *
+ * parameter: cnd - The inititalized timeout condition.
+ * ap - Pointer to user supplied arguments list for this
+ * handler.
+ * returns: TRUE - Condition is true.
+ * FALSE - Condition is false.
+ */
+static gboolean _cnd_eval_timeout(condition* cnd, va_list ap){
+ cnd_timeout_dat* data = (cnd_timeout_dat*)cnd_get_user_data(cnd);
+ gint32 elapsed_time;
+ /* check timeout here */
+ if(data->timeout_s == 0) return FALSE; /* 0 == infinite */
+ elapsed_time = time(NULL) - data->start_time;
+ if(elapsed_time > data->timeout_s) return TRUE;
+ return FALSE;
+} /* END _cnd_eval_timeout()*/
+
+/*
+ * Call this function to reset this condition to its initial state, i.e. the
+ * state it was in right after creation.
+ *
+ * parameter: cnd - Pointer to an initialized condition.
+ */
+static void _cnd_reset_timeout(condition *cnd){
+ ((cnd_timeout_dat*)cnd_get_user_data(cnd))->start_time = time(NULL);
+} /* END _cnd_reset_timeout() */
+
+
+/*****************************************************************************/
+/* Predefined condition 'max. capturesize'. */
+
+/* class id */
+const char* CND_CLASS_CAPTURESIZE = "cnd_class_capturesize";
+
+/* structure that contains user supplied data for this condition */
+typedef struct _cnd_capturesize_dat{
+ guint32 max_capture_size;
+}cnd_capturesize_dat;
+
+/*
+ * Constructs new condition for capturesize check. This function is invoked by
+ * 'cnd_new()' in order to perform class specific initialization.
+ *
+ * parameter: cnd - Pointer to condition passed by 'cnd_new()'.
+ * ap - Pointer to user supplied arguments list for this
+ * constructor.
+ * returns: Pointer to condition - Construction was successful.
+ * NULL - Construction failed.
+ */
+static condition* _cnd_constr_capturesize(condition* cnd, va_list ap){
+ cnd_capturesize_dat *data = NULL;
+ /* allocate memory */
+ if((data = (cnd_capturesize_dat*)malloc(sizeof(cnd_capturesize_dat))) == NULL)
+ return NULL;
+ /* initialize user data */
+ data->max_capture_size = va_arg(ap, guint32);
+ cnd_set_user_data(cnd, (void*)data);
+ return cnd;
+} /* END _cnd_constr_capturesize() */
+
+/*
+ * Destroys condition for capturesize check. This function is invoked by
+ * 'cnd_delete()' in order to perform class specific clean up.
+ *
+ * parameter: cnd - Pointer to condition passed by 'cnd_delete()'.
+ */
+static void _cnd_destr_capturesize(condition* cnd){
+ /* free memory */
+ free(cnd_get_user_data(cnd));
+} /* END _cnd_destr_capturesize() */
+
+/*
+ * Condition handler for capturesize condition. This function is invoked by
+ * 'cnd_eval()' in order to perform class specific condition checks.
+ *
+ * parameter: cnd - The inititalized capturesize condition.
+ * ap - Pointer to user supplied arguments list for this
+ * handler.
+ * returns: TRUE - Condition is true.
+ * FALSE - Condition is false.
+ */
+static gboolean _cnd_eval_capturesize(condition* cnd, va_list ap){
+ cnd_capturesize_dat* data = (cnd_capturesize_dat*)cnd_get_user_data(cnd);
+ /* check capturesize here */
+ if(data->max_capture_size == 0) return FALSE; /* 0 == infinite */
+ if(va_arg(ap, guint32) >= data->max_capture_size){
+ return TRUE;
+ }
+ return FALSE;
+} /* END _cnd_eval_capturesize() */
+
+/*
+ * Call this function to reset this condition to its initial state, i.e. the
+ * state it was in right after creation.
+ *
+ * parameter: cnd - Pointer to an initialized condition.
+ */
+static void _cnd_reset_capturesize(condition *cnd){
+} /* END _cnd_reset_capturesize() */
diff --git a/capture_stop_conditions.h b/capture_stop_conditions.h
new file mode 100644
index 0000000000..4a11636373
--- /dev/null
+++ b/capture_stop_conditions.h
@@ -0,0 +1,29 @@
+/* capture_stop_conditions.h
+ * Implementation for 'stop condition handler'.
+ *
+ * $Id: capture_stop_conditions.h,v 1.1 2001/12/04 07:32:00 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+void init_capture_stop_conditions(void);
+void cleanup_capture_stop_conditions(void);
+
+extern const char* CND_CLASS_TIMEOUT;
+extern const char* CND_CLASS_CAPTURESIZE;
diff --git a/conditions.c b/conditions.c
new file mode 100644
index 0000000000..985a452dbe
--- /dev/null
+++ b/conditions.c
@@ -0,0 +1,205 @@
+/* conditions.c
+ * Implementation for condition handler.
+ *
+ * $Id: conditions.c,v 1.1 2001/12/04 07:32:00 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "conditions.h"
+
+/* container for condition classes */
+static GHashTable* classes = NULL;
+
+/* condition data structure declaration */
+struct condition{
+ char* class_id;
+ void* user_data;
+ _cnd_eval eval_func;
+ _cnd_reset reset_func;
+};
+
+/* structure used to store class functions in GHashTable */
+typedef struct _cnd_class{
+ _cnd_constr constr_func;
+ _cnd_destr destr_func;
+ _cnd_eval eval_func;
+ _cnd_reset reset_func;
+} _cnd_class;
+
+/* helper function prototypes */
+static void _cnd_init();
+static void _cnd_find_hash_key_for_class_id(gpointer, gpointer, gpointer);
+
+condition* cnd_new(const char* class_id, ...){
+ va_list ap;
+ condition *cnd = NULL, *cnd_ref = NULL;
+ _cnd_class *cls = NULL;
+ char* id = NULL;
+ /* check if hash table is already initialized */
+ _cnd_init();
+ /* get class structure for this id */
+ if((cls = (_cnd_class*)g_hash_table_lookup(classes, class_id)) == NULL)
+ return NULL;
+ /* initialize the basic structure */
+ if((cnd_ref = (condition*)malloc(sizeof(condition))) == NULL) return NULL;
+ cnd_ref->user_data = NULL;
+ cnd_ref->eval_func = cls->eval_func;
+ cnd_ref->reset_func = cls->reset_func;
+ /* copy the class id */
+ if((id = (char*)malloc(strlen(class_id)+1)) == NULL){
+ free(cnd_ref);
+ return NULL;
+ }
+ strcpy(id, class_id);
+ cnd_ref->class_id = id;
+ /* perform class specific initialization */
+ va_start(ap, class_id);
+ cnd = (cls->constr_func)(cnd_ref, ap);
+ va_end(ap);
+ /* check for successful construction */
+ if(cnd == NULL){
+ free(cnd_ref);
+ free(id);
+ }
+ return cnd;
+} /* END cnd_new() */
+
+void cnd_delete(condition *cnd){
+ _cnd_class *cls = NULL;
+ const char* class_id = cnd->class_id;
+ /* check for valid pointer */
+ if(cnd == NULL) return;
+ /* check if hash table is already initialized */
+ _cnd_init();
+ /* get the condition class */
+ cls = (_cnd_class*)g_hash_table_lookup(classes, class_id);
+ /* call class specific destructor */
+ if(cls != NULL) (cls->destr_func)(cnd);
+ /* free memory */
+ free(cnd->class_id);
+ /* free basic structure */
+ free(cnd);
+} /* END cnd_delete() */
+
+gboolean cnd_eval(condition *cnd, ...){
+ va_list ap;
+ gboolean ret_val = FALSE;
+ /* validate cnd */
+ if(cnd == NULL) return FALSE;
+ /* call specific handler */
+ va_start(ap, cnd);
+ ret_val = (cnd->eval_func)(cnd, ap);
+ va_end(ap);
+ return ret_val;
+} /* END cnd_eval() */
+
+void cnd_reset(condition *cnd){
+ if(cnd != NULL) (cnd->reset_func)(cnd);
+} /* END cnd_reset() */
+
+void* cnd_get_user_data(condition *cnd){
+ return cnd->user_data;
+} /* END cnd_get_user_data() */
+
+void cnd_set_user_data(condition *cnd, void* user_data){
+ cnd->user_data = user_data;
+} /* END cnd_set_user_data() */
+
+gboolean cnd_register_class(const char* class_id,
+ _cnd_constr constr_func,
+ _cnd_destr destr_func,
+ _cnd_eval eval_func,
+ _cnd_reset reset_func){
+ char* key = NULL;
+ _cnd_class *cls = NULL;
+ /* check for valid parameters */
+ if((constr_func == NULL) || (destr_func == NULL) ||
+ (eval_func == NULL) || (reset_func == NULL) || (class_id == NULL))
+ return FALSE;
+ /* check if hash table is already initialized */
+ _cnd_init();
+ /* check for unique class id */
+ if((cls = (_cnd_class*)g_hash_table_lookup(classes, class_id)) != NULL)
+ return FALSE;
+ /* GHashTable keys need to be persistent for the lifetime of the hash
+ table. Allocate memory and copy the class id which we use as key. */
+ if((key = (char*)malloc(strlen(class_id)+1)) == NULL) return FALSE;
+ strcpy(key, class_id);
+ /* initialize class structure */
+ if((cls = (_cnd_class*)malloc(sizeof(_cnd_class))) == NULL){
+ free(key);
+ return FALSE;
+ }
+ cls->constr_func = constr_func;
+ cls->destr_func = destr_func;
+ cls->eval_func = eval_func;
+ cls->reset_func = reset_func;
+ /* insert new class */
+ g_hash_table_insert(classes, key, cls);
+ return TRUE;
+} /* END cnd_register_class() */
+
+static char* pkey = NULL;
+void cnd_unregister_class(const char* class_id){
+ char *key = (char*)class_id;
+ _cnd_class *cls = NULL;
+ /* check if hash table is already initialized */
+ _cnd_init();
+ /* find the key for this class id and store it in 'pkey' */
+ g_hash_table_foreach(classes,
+ _cnd_find_hash_key_for_class_id,
+ key);
+ /* find the class structure for this class id */
+ cls = (_cnd_class*)g_hash_table_lookup(classes, class_id);
+ /* remove constructor from hash table */
+ g_hash_table_remove(classes, class_id);
+ /* free the key */
+ free(pkey);
+ pkey = NULL;
+ /* free the value */
+ free(cls);
+} /* END cnd_unregister_class() */
+
+/*
+ * Initialize hash table.
+ */
+static void _cnd_init(){
+ if(classes != NULL) return;
+ /* create hash table, we use strings as keys */
+ classes = g_hash_table_new(g_str_hash, g_str_equal);
+} /* END _cnd_init() */
+
+/*
+ * Callback for function 'g_hash_table_foreach()'.
+ * We don't keep references to hash table keys. Keys have memory allocated
+ * which must be freed when they are not used anymore. This function finds
+ * the reference to a key corresponding to a particular class id. The reference
+ * to the key is stored in a global variable.
+ */
+void _cnd_find_hash_key_for_class_id(gpointer key,
+ gpointer value,
+ gpointer user_data){
+ char* class_id = (char*)user_data;
+ char* key_value = (char*)key;
+ if(strcmp(class_id, key_value) == 0) pkey = key;
+} /* END _cnd_find_hash_key_for_class_id() */
diff --git a/conditions.h b/conditions.h
new file mode 100644
index 0000000000..1aceaf95cb
--- /dev/null
+++ b/conditions.h
@@ -0,0 +1,134 @@
+/* conditions.h
+ * Header for condition handler.
+ *
+ * $Id: conditions.h,v 1.1 2001/12/04 07:32:00 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CONDITIONS_H
+#define CONDITIONS_H
+
+#include <stdarg.h>
+
+#include <glib.h>
+
+/* forward declaration for type 'condition' */
+typedef struct condition condition;
+
+/* condition evaluation handler type */
+typedef gboolean (*_cnd_eval)(condition*, va_list);
+
+/* condition reset handler type */
+typedef void (*_cnd_reset)(condition*);
+
+/* condition class constructor type */
+typedef condition* (*_cnd_constr)(condition*, va_list);
+
+/* condition class destructor type */
+typedef void (*_cnd_destr)(condition*);
+
+/*
+ * Conditions must be created with this function. They can be created for
+ * registered classes only.
+ *
+ * parameter: const char* - Identification of a registered condition class.
+ * ... - Any number of class specific initial values.
+ * returns: Pointer to a initialized condition of the particular class on
+ * success or NULL on failure.
+ */
+condition* cnd_new(const char*, ...);
+
+/*
+ * Conditions must be deleted with this function when not used anymore.
+ *
+ * parameter: condition* - Pointer to a condition created with 'cnd_new()'.
+ * returns: -
+ */
+void cnd_delete(condition*);
+
+/*
+ * Call this function to check whether or not a particular condition is true.
+ *
+ * parameter: condition* - Pointer to an initialized condition.
+ * ... - Any number of condition specific arguments.
+ * returns: TRUE - Condition is true.
+ * FALSE - Condition is false.
+ */
+gboolean cnd_eval(condition*, ...);
+
+/*
+ * Call this function to reset this condition to its initial state, i.e. the
+ * state it was in right after creation.
+ *
+ * parameter: condition* - Pointer to an initialized condition.
+ * returns: -
+ */
+void cnd_reset(condition*);
+
+/*
+ * Register a new conditon class.
+ * New conditions of this class can be created by calling 'cnd_new()' and
+ * supplying the appropriate class id.
+ *
+ * parameter: const char* - The class id.
+ * _cnd_constr - User supplied constructor function for this
+ * class.
+ * _cnd_destr - User supplied destructor function for this
+ * class.
+ * _cnd_eval - User supplied evaluation handler function for this
+ class.
+ * _cnd_reset - User supplied reset handler for this class.
+ * returns: TRUE - Success.
+ * FALSE - Failure.
+ */
+gboolean cnd_register_class(const char*,
+ _cnd_constr,
+ _cnd_destr,
+ _cnd_eval,
+ _cnd_reset);
+
+/*
+ * Unregister a previously registered conditon class. After unregistration
+ * of a class it is no longer possible to create conditions of this kind by
+ * calling 'cnd_new()'.
+ *
+ * parameter: const char* - An identification for this condition class.
+ * returns: -
+ */
+void cnd_unregister_class(const char*);
+
+/*
+ * This function returns the user data of the condition.
+ *
+ * parameter: condition* - Pointer to an initialized condition.
+ * returns: void* - Pointer to user data of this condition.
+ */
+void* cnd_get_user_data(condition*);
+
+/*
+ * This function sets the user data of the condition.
+ *
+ * parameter: condition* - Pointer to an initialized condition.
+ * void* - Pointer to user specified data structure.
+ * returns: -
+ */
+void cnd_set_user_data(condition*, void*);
+
+#endif /* CONDITIONS_H */
diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template
index 6ab13702bc..d145bafa3e 100644
--- a/doc/ethereal.pod.template
+++ b/doc/ethereal.pod.template
@@ -6,6 +6,7 @@ ethereal - Interactively browse network traffic
=head1 SYNOPSYS
B<ethereal>
+S<[ B<-a> capture autostop condition ] ...>
S<[ B<-B> byte view height ]>
S<[ B<-c> count ]>
S<[ B<-f> capture filter expression ]>
@@ -15,7 +16,7 @@ S<[ B<-k> ]>
S<[ B<-l> ]>
S<[ B<-m> font ]>
S<[ B<-n> ]>
-S<[ B<-N> resolving flags ] ...>
+S<[ B<-N> resolving flags ] >
S<[ B<-o> preference setting ] ...>
S<[ B<-p> ]>
S<[ B<-P> packet list height ]>
@@ -80,6 +81,29 @@ B<-r> option or can be specified as a command-line argument.
=over 4
+=item -a
+
+Specify a criterion that specifies when B<Tethereal> is to stop writing
+to a capture file. The criterion is of the form I<test>B<:>I<value>,
+where I<test> is one of:
+
+=for man .RS
+
+=for html <P><DL>
+
+=item duration
+
+Stop writing to a capture file after I<value> seconds have elapsed.
+
+=item filesize
+
+Stop writing to a capture file after it reaches a size of I<value>
+kilobytes (where a kilobyte is 1000 bytes, not 1024 bytes).
+
+=for man .RE
+
+=for html </DL>
+
=item -B
Sets the initial height of the byte view (bottom) pane.
@@ -1198,6 +1222,7 @@ B<http://www.ethereal.com>.
Terje Krogdahl <tekr[AT]nextra.com>
Jean-Francois Mule <jfmule[AT]clarent.com>
Thomas Wittwer <thomas.wittwer[AT]iclip.ch>
+ Matthias Nyffenegger <matthias.nyffenegger[AT]iclip.ch>
Palle Lyckegaard <Palle[AT]lyckegaard.dk>
Nicolas Balkota <balkota[AT]mac.com>
Tom Uijldert <Tom.Uijldert[AT]cmg.nl>
diff --git a/doc/tethereal.pod.template b/doc/tethereal.pod.template
index cd593bcdf1..ea34ca58ab 100644
--- a/doc/tethereal.pod.template
+++ b/doc/tethereal.pod.template
@@ -6,6 +6,7 @@ tethereal - Dump and analyze network traffic
=head1 SYNOPSYS
B<tethereal>
+S<[ B<-a> capture autostop condition ] ...>
S<[ B<-c> count ]>
S<[ B<-D> ]>
S<[ B<-f> capture filter expression ]>
@@ -14,7 +15,7 @@ S<[ B<-h> ]>
S<[ B<-i> interface ]>
S<[ B<-l> ]>
S<[ B<-n> ]>
-S<[ B<-N> resolving flags ] ...>
+S<[ B<-N> resolving flags ]>
S<[ B<-o> preference setting ] ...>
S<[ B<-p> ]>
S<[ B<-r> infile ]>
@@ -108,6 +109,29 @@ B<-r> flag was specified).
=over 4
+=item -a
+
+Specify a criterion that specifies when B<Tethereal> is to stop writing
+to a capture file. The criterion is of the form I<test>B<:>I<value>,
+where I<test> is one of:
+
+=for man .RS
+
+=for html <P><DL>
+
+=item duration
+
+Stop writing to a capture file after I<value> seconds have elapsed.
+
+=item filesize
+
+Stop writing to a capture file after it reaches a size of I<value>
+kilobytes (where a kilobyte is 1000 bytes, not 1024 bytes).
+
+=for man .RE
+
+=for html </DL>
+
=item -c
Sets the default number of packets to read when capturing live
diff --git a/file.h b/file.h
index 2c359ea98c..ed04edc0b4 100644
--- a/file.h
+++ b/file.h
@@ -1,7 +1,7 @@
/* file.h
* Definitions for file structures and routines
*
- * $Id: file.h,v 1.84 2001/07/05 00:34:39 guy Exp $
+ * $Id: file.h,v 1.85 2001/12/04 07:32:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -86,6 +86,10 @@ typedef struct _capture_file {
proto_tree *protocol_tree; /* Protocol tree for currently selected packet */
epan_dissect_t *edt; /* Protocol dissection fo rcurrently selected packet */
FILE *print_fh; /* File we're printing to */
+#ifdef HAVE_LIBPCAP
+ guint32 autostop_filesize; /* Maximum capture file size */
+ gint32 autostop_duration; /* Maximum capture duration */
+#endif
} capture_file;
/* Return values from "read_cap_file()", "continue_tail_cap_file()",
diff --git a/gtk/capture_dlg.c b/gtk/capture_dlg.c
index e141456a9b..182b95c974 100644
--- a/gtk/capture_dlg.c
+++ b/gtk/capture_dlg.c
@@ -1,7 +1,7 @@
/* capture_dlg.c
* Routines for packet capture windows
*
- * $Id: capture_dlg.c,v 1.48 2001/11/09 07:44:49 guy Exp $
+ * $Id: capture_dlg.c,v 1.49 2001/12/04 07:32:04 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -73,6 +73,8 @@
#define E_CAP_M_RESOLVE_KEY "cap_m_resolve"
#define E_CAP_N_RESOLVE_KEY "cap_n_resolve"
#define E_CAP_T_RESOLVE_KEY "cap_t_resolve"
+#define E_CAP_FILESIZE_KEY "cap_filesize"
+#define E_CAP_DURATION_KEY "cap_duration"
#define E_FS_CALLER_PTR_KEY "fs_caller_ptr"
#define E_FILE_SEL_DIALOG_PTR_KEY "file_sel_dialog_ptr"
@@ -119,14 +121,18 @@ capture_prep_cb(GtkWidget *w, gpointer d)
*count_lb, *count_cb, *main_vb,
*filter_bt, *filter_te,
*file_bt, *file_te,
+ *filesize_lb, *filesize_cb,
+ *duration_lb, *duration_cb,
*caplen_hb, *table,
*bbox, *ok_bt, *cancel_bt, *snap_lb,
*snap_sb, *promisc_cb, *sync_cb, *auto_scroll_cb,
- *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
+ *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
GtkAccelGroup *accel_group;
- GtkAdjustment *adj;
- GList *if_list, *count_list = NULL;
- gchar *count_item1 = "0 (Infinite)", count_item2[16];
+ GtkAdjustment *snap_adj;
+ GList *if_list, *count_list = NULL, *filesize_list = NULL, *duration_list = NULL;
+ gchar *count_item1 = "0 (Infinite)", count_item2[16],
+ *filesize_item1 = "0 (Infinite)", filesize_item2[16],
+ *duration_item1 = "0 (Infinite)", duration_item2[16];
int err;
char err_str[PCAP_ERRBUF_SIZE];
@@ -181,8 +187,8 @@ capture_prep_cb(GtkWidget *w, gpointer d)
gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
gtk_widget_show(main_vb);
- /* Table : container of the first 4 rows */
- table = gtk_table_new (4, 2, FALSE);
+ /* Table : container of the first 6 rows */
+ table = gtk_table_new (6, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE (table), 5);
gtk_table_set_col_spacings(GTK_TABLE (table), 5);
gtk_container_add(GTK_CONTAINER(main_vb), table);
@@ -226,34 +232,74 @@ capture_prep_cb(GtkWidget *w, gpointer d)
while (count_list)
count_list = g_list_remove_link(count_list, count_list);
+ /* Filesize row */
+
+ filesize_lb = gtk_label_new("File size:");
+ gtk_table_attach_defaults(GTK_TABLE(table), filesize_lb, 0, 1, 2, 3);
+ gtk_widget_show(filesize_lb);
+
+ filesize_list = g_list_append(filesize_list, filesize_item1);
+ if (cfile.autostop_filesize) {
+ snprintf(filesize_item2, 15, "%u", cfile.autostop_filesize);
+ filesize_list = g_list_append(filesize_list, filesize_item2);
+ }
+
+ filesize_cb = gtk_combo_new();
+ gtk_combo_set_popdown_strings(GTK_COMBO(filesize_cb), filesize_list);
+ gtk_table_attach_defaults(GTK_TABLE(table), filesize_cb, 1, 2, 2, 3);
+ gtk_widget_show(filesize_cb);
+
+ while (filesize_list)
+ filesize_list = g_list_remove_link(filesize_list, filesize_list);
+
+ /* Duration row */
+
+ duration_lb = gtk_label_new("Duration:");
+ gtk_table_attach_defaults(GTK_TABLE(table), duration_lb, 0, 1, 3, 4);
+ gtk_widget_show(duration_lb);
+
+ duration_list = g_list_append(duration_list, duration_item1);
+ if (cfile.autostop_duration) {
+ snprintf(duration_item2, 15, "%d", cfile.autostop_duration);
+ duration_list = g_list_append(duration_list, duration_item2);
+ }
+
+ duration_cb = gtk_combo_new();
+ gtk_combo_set_popdown_strings(GTK_COMBO(duration_cb), duration_list);
+ gtk_table_attach_defaults(GTK_TABLE(table), duration_cb, 1, 2, 3, 4);
+ gtk_widget_show(duration_cb);
+
+ while (duration_list)
+ duration_list = g_list_remove_link(duration_list, duration_list);
+
/* Filter row */
filter_bt = gtk_button_new_with_label("Filter:");
gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
GTK_SIGNAL_FUNC(capture_filter_construct_cb), NULL);
- gtk_table_attach_defaults(GTK_TABLE(table), filter_bt, 0, 1, 2, 3);
+ gtk_table_attach_defaults(GTK_TABLE(table), filter_bt, 0, 1, 4, 5);
gtk_widget_show(filter_bt);
filter_te = gtk_entry_new();
if (cfile.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cfile.cfilter);
gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
- gtk_table_attach_defaults(GTK_TABLE(table), filter_te, 1, 2, 2, 3);
+ gtk_table_attach_defaults(GTK_TABLE(table), filter_te, 1, 2, 4, 5);
gtk_widget_show(filter_te);
/* File row */
file_bt = gtk_button_new_with_label("File:");
- gtk_table_attach_defaults(GTK_TABLE(table), file_bt, 0, 1, 3, 4);
+ gtk_table_attach_defaults(GTK_TABLE(table), file_bt, 0, 1, 5, 6);
gtk_widget_show(file_bt);
file_te = gtk_entry_new();
- gtk_table_attach_defaults(GTK_TABLE(table), file_te, 1, 2, 3, 4);
+ gtk_table_attach_defaults(GTK_TABLE(table), file_te, 1, 2, 5, 6);
gtk_widget_show(file_te);
gtk_signal_connect(GTK_OBJECT(file_bt), "clicked",
GTK_SIGNAL_FUNC(capture_prep_file_cb), GTK_OBJECT(file_te));
- /* Misc row: Capture file checkbox and snap spinbutton */
+ /* Misc row: Snap spinbutton */
caplen_hb = gtk_hbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
gtk_widget_show(caplen_hb);
@@ -263,9 +309,9 @@ capture_prep_cb(GtkWidget *w, gpointer d)
gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
gtk_widget_show(snap_lb);
- adj = (GtkAdjustment *) gtk_adjustment_new((float) cfile.snap,
+ snap_adj = (GtkAdjustment *) gtk_adjustment_new((float) cfile.snap,
MIN_PACKET_SIZE, WTAP_MAX_PACKET_SIZE, 1.0, 10.0, 0.0);
- snap_sb = gtk_spin_button_new (adj, 0, 0);
+ snap_sb = gtk_spin_button_new (snap_adj, 0, 0);
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
gtk_widget_set_usize (snap_sb, 80, 0);
gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3);
@@ -277,6 +323,7 @@ capture_prep_cb(GtkWidget *w, gpointer d)
gtk_container_add(GTK_CONTAINER(main_vb), promisc_cb);
gtk_widget_show(promisc_cb);
+ /* Misc row: Capture file checkboxes */
sync_cb = dlg_check_button_new_with_label_with_mnemonic(
"_Update list of packets in real time", accel_group);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(sync_cb), prefs.capture_real_time);
@@ -344,6 +391,8 @@ capture_prep_cb(GtkWidget *w, gpointer d)
gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_M_RESOLVE_KEY, m_resolv_cb);
gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_N_RESOLVE_KEY, n_resolv_cb);
gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_T_RESOLVE_KEY, t_resolv_cb);
+ gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILESIZE_KEY, filesize_cb);
+ gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_DURATION_KEY, duration_cb);
/* Catch the "activate" signal on the frame number and file name text
entries, so that if the user types Return there, we act as if the
@@ -462,14 +511,45 @@ cap_prep_fs_destroy_cb(GtkWidget *win, gpointer data)
gtk_widget_destroy(GTK_WIDGET(win));
}
+static int
+get_positive_int(const char *string, const char *name)
+{
+ long number;
+ char *p;
+
+ number = strtol(string, &p, 10);
+ /*
+ * XXX - we allow extra stuff after 0, so that we don't have
+ * problems with the "(Infinite)" value.
+ */
+ if (p == string || (*p != '\0' && number != 0)) {
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "The specified %s is not a decimal number.", name);
+ return -1;
+ }
+ if (number < 0) {
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "The specified %s is a negative number.", name);
+ return -1;
+ }
+ if (number > INT_MAX) {
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "The specified %s is too large (greater than %d).", name, INT_MAX);
+ return -1;
+ }
+ return number;
+}
+
static void
capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
GtkWidget *if_cb, *filter_te, *file_te, *count_cb, *snap_sb, *promisc_cb,
- *sync_cb, *auto_scroll_cb, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
+ *sync_cb, *auto_scroll_cb, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb,
+ *filesize_cb, *duration_cb;
gchar *if_text;
gchar *if_name;
gchar *filter_text;
gchar *save_file;
+ int value;
if_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY);
filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY);
@@ -482,6 +562,8 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
m_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_M_RESOLVE_KEY);
n_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_N_RESOLVE_KEY);
t_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_T_RESOLVE_KEY);
+ filesize_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILESIZE_KEY);
+ duration_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_DURATION_KEY);
if_text =
g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
@@ -522,6 +604,18 @@ capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
cfile.count = atoi(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)));
+ value = get_positive_int(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(filesize_cb)->entry)),
+ "maximum capture file size");
+ if (value == -1)
+ return; /* error */
+ cfile.autostop_filesize = value;
+
+ value = get_positive_int(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(duration_cb)->entry)),
+ "capture duration");
+ if (value == -1)
+ return; /* error */
+ cfile.autostop_duration = value;
+
cfile.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
if (cfile.snap < 1)
cfile.snap = WTAP_MAX_PACKET_SIZE;
diff --git a/gtk/main.c b/gtk/main.c
index 901f228fe6..d6872248d8 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -1,6 +1,6 @@
/* main.c
*
- * $Id: main.c,v 1.213 2001/11/24 08:46:13 guy Exp $
+ * $Id: main.c,v 1.214 2001/12/04 07:32:04 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -46,6 +46,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -792,10 +793,10 @@ print_usage(void) {
fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
comp_info_str->str);
#ifdef HAVE_LIBPCAP
- fprintf(stderr, "%s [ -vh ] [ -klpQS ] [ -B <byte view height> ] [ -c <count> ]\n",
+ fprintf(stderr, "%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
PACKAGE);
- fprintf(stderr, "\t[ -f <capture filter> ] [ -i <interface> ] [ -m <medium font> ] \n");
- fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
+ fprintf(stderr, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
+ fprintf(stderr, "\t[ -i <interface> ] [ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
@@ -820,7 +821,7 @@ show_version(void)
printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
}
-int
+static int
get_positive_int(const char *string, const char *name)
{
long number;
@@ -845,6 +846,51 @@ get_positive_int(const char *string, const char *name)
return number;
}
+/*
+ * Given a string of the form "<autostop criterion>:<value>", as might appear
+ * as an argument to a "-a" option, parse it and set the criterion in
+ * question. Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+static gboolean
+set_autostop_criterion(const char *autostoparg)
+{
+ u_char *p, *colonp;
+
+ colonp = strchr(autostoparg, ':');
+ if (colonp == NULL)
+ return FALSE;
+
+ p = colonp;
+ *p++ = '\0';
+
+ /*
+ * Skip over any white space (there probably won't be any, but
+ * as we allow it in the preferences file, we might as well
+ * allow it here).
+ */
+ while (isspace(*p))
+ p++;
+ if (*p == '\0') {
+ /*
+ * Put the colon back, so if our caller uses, in an
+ * error message, the string they passed us, the message
+ * looks correct.
+ */
+ *colonp = ':';
+ return FALSE;
+ }
+ if (strcmp(autostoparg,"duration") == 0) {
+ cfile.autostop_duration = get_positive_int(p,"autostop duration");
+ } else if (strcmp(autostoparg,"filesize") == 0) {
+ cfile.autostop_filesize = get_positive_int(p,"autostop filesize");
+ } else {
+ return FALSE;
+ }
+ *colonp = ':'; /* put the colon back */
+ return TRUE;
+}
+
/* And now our feature presentation... [ fade to music ] */
int
main(int argc, char *argv[])
@@ -996,6 +1042,10 @@ main(int argc, char *argv[])
cfile.save_file_fd = -1;
cfile.snap = WTAP_MAX_PACKET_SIZE;
cfile.count = 0;
+#ifdef HAVE_LIBPCAP
+ cfile.autostop_duration = 0;
+ cfile.autostop_filesize = 0;
+#endif
col_init(&cfile.cinfo, prefs->num_cols);
/* Assemble the compile-time options */
@@ -1061,8 +1111,19 @@ main(int argc, char *argv[])
#endif
/* Now get our args */
- while ((opt = getopt(argc, argv, "B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
+ while ((opt = getopt(argc, argv, "a:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
switch (opt) {
+ case 'a': /* autostop criteria */
+#ifdef HAVE_LIBPCAP
+ if (set_autostop_criterion(optarg) == FALSE) {
+ fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
+ exit(1);
+ }
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
+#endif
+ break;
case 'B': /* Byte view pane height */
bv_size = get_positive_int(optarg, "byte view pane height");
break;
diff --git a/tethereal.c b/tethereal.c
index 66dbe5c8bb..05409cc504 100644
--- a/tethereal.c
+++ b/tethereal.c
@@ -1,6 +1,6 @@
/* tethereal.c
*
- * $Id: tethereal.c,v 1.99 2001/11/21 23:16:21 gram Exp $
+ * $Id: tethereal.c,v 1.100 2001/12/04 07:32:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -22,7 +22,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
*/
#ifdef HAVE_CONFIG_H
@@ -32,6 +31,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include <locale.h>
#include <limits.h>
@@ -104,6 +104,8 @@
#include "reassemble.h"
#include "plugins.h"
#include "register.h"
+#include "conditions.h"
+#include "capture_stop_conditions.h"
#ifdef WIN32
#include "capture-wpcap.h"
@@ -121,6 +123,7 @@ typedef struct _loop_data {
gint linktype;
pcap_t *pch;
wtap_dumper *pdh;
+ gboolean go;
} loop_data;
static loop_data ld;
@@ -158,8 +161,11 @@ print_usage(void)
fprintf(stderr, "This is GNU t%s %s, compiled %s\n", PACKAGE, VERSION,
comp_info_str->str);
#ifdef HAVE_LIBPCAP
- fprintf(stderr, "t%s [ -DvVhlp ] [ -c <count> ] [ -f <capture filter> ]\n", PACKAGE);
- fprintf(stderr, "\t[ -F <capture file type> ] [ -i <interface> ] [ -n ] [ -N <resolving> ]\n");
+ fprintf(stderr, "t%s [ -DvVhlp ] [ -a <capture autostop condition> ] ...\n",
+ PACKAGE);
+ fprintf(stderr, "\t[ -b <number of ring buffer files> ] [ -c <count> ]\n");
+ fprintf(stderr, "\t[ -f <capture filter> ] [ -F <capture file type> ]\n");
+ fprintf(stderr, "\t[ -i <interface> ] [ -n ] [ -N <resolving> ]\n");
fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
fprintf(stderr, "\t[ -s <snaplen> ] [ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
#else
@@ -176,7 +182,7 @@ print_usage(void)
fprintf(stderr, "\tdefault is libpcap\n");
}
-int
+static int
get_positive_int(const char *string, const char *name)
{
long number;
@@ -201,6 +207,51 @@ get_positive_int(const char *string, const char *name)
return number;
}
+/*
+ * Given a string of the form "<autostop criterion>:<value>", as might appear
+ * as an argument to a "-a" option, parse it and set the criterion in
+ * question. Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+static gboolean
+set_autostop_criterion(const char *autostoparg)
+{
+ u_char *p, *colonp;
+
+ colonp = strchr(autostoparg, ':');
+ if (colonp == NULL)
+ return FALSE;
+
+ p = colonp;
+ *p++ = '\0';
+
+ /*
+ * Skip over any white space (there probably won't be any, but
+ * as we allow it in the preferences file, we might as well
+ * allow it here).
+ */
+ while (isspace(*p))
+ p++;
+ if (*p == '\0') {
+ /*
+ * Put the colon back, so if our caller uses, in an
+ * error message, the string they passed us, the message
+ * looks correct.
+ */
+ *colonp = ':';
+ return FALSE;
+ }
+ if (strcmp(autostoparg,"duration") == 0) {
+ cfile.autostop_duration = get_positive_int(p,"autostop duration");
+ } else if (strcmp(autostoparg,"filesize") == 0) {
+ cfile.autostop_filesize = get_positive_int(p,"autostop filesize");
+ } else {
+ return FALSE;
+ }
+ *colonp = ':'; /* put the colon back */
+ return TRUE;
+}
+
int
main(int argc, char *argv[])
{
@@ -223,7 +274,7 @@ main(int argc, char *argv[])
int err;
#ifdef HAVE_LIBPCAP
gboolean capture_filter_specified = FALSE;
- int packet_count = 0;
+ guint packet_count = 0;
GList *if_list, *if_entry;
gchar err_str[PCAP_ERRBUF_SIZE];
#else
@@ -291,6 +342,10 @@ main(int argc, char *argv[])
cfile.save_file_fd = -1;
cfile.snap = WTAP_MAX_PACKET_SIZE;
cfile.count = 0;
+#ifdef HAVE_LIBPCAP
+ cfile.autostop_duration = 0;
+ cfile.autostop_filesize = 0;
+#endif
col_init(&cfile.cinfo, prefs->num_cols);
/* Assemble the compile-time options */
@@ -347,8 +402,19 @@ main(int argc, char *argv[])
#endif
/* Now get our args */
- while ((opt = getopt(argc, argv, "c:Df:F:hi:lnN:o:pr:R:s:t:vw:Vx")) != EOF) {
+ while ((opt = getopt(argc, argv, "a:c:Df:F:hi:lnN:o:pr:R:s:t:vw:Vx")) != EOF) {
switch (opt) {
+ case 'a': /* autostop criteria */
+#ifdef HAVE_LIBPCAP
+ if (set_autostop_criterion(optarg) == FALSE) {
+ fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
+ exit(1);
+ }
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
+#endif
+ break;
case 'c': /* Capture xxx packets */
#ifdef HAVE_LIBPCAP
packet_count = get_positive_int(optarg, "packet count");
@@ -652,6 +718,8 @@ capture(int packet_count, int out_file_type)
void (*oldhandler)(int);
int err, inpkts;
char errmsg[1024+1];
+ condition *cnd_stop_capturesize;
+ condition *cnd_stop_timeout;
#ifndef _WIN32
static const char ppamsg[] = "can't find PPA for ";
char *libpcap_warn;
@@ -787,7 +855,35 @@ capture(int packet_count, int out_file_type)
fprintf(stderr, "Capturing on %s\n", cfile.iface);
fflush(stderr);
- inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
+ /* initialize capture stop conditions */
+ init_capture_stop_conditions();
+ /* create stop conditions */
+ cnd_stop_capturesize = cnd_new((char*)CND_CLASS_CAPTURESIZE,
+ (guint32)cfile.autostop_filesize * 1000);
+ cnd_stop_timeout = cnd_new((char*)CND_CLASS_TIMEOUT,
+ (gint32)cfile.autostop_duration);
+
+ if (packet_count == 0)
+ packet_count = -1; /* infinite capturng */
+ ld.go = TRUE;
+ while (ld.go) {
+ if (packet_count > 0)
+ packet_count--;
+ inpkts = pcap_dispatch(ld.pch, 1, capture_pcap_cb, (u_char *) &ld);
+ if (packet_count == 0) {
+ ld.go = FALSE;
+ } else if (cnd_eval(cnd_stop_timeout) == TRUE) {
+ ld.go = FALSE;
+ } else if ((cnd_eval(cnd_stop_capturesize,
+ (guint32)wtap_get_bytes_dumped(ld.pdh))) == TRUE){
+ /* A capture stop condition has become true. */
+ ld.go = FALSE;
+ }
+ }
+
+ /* delete stop conditions */
+ cnd_delete(cnd_stop_capturesize);
+ cnd_delete(cnd_stop_timeout);
if (cfile.save_file != NULL) {
/* We're saving to a file, which means we're printing packet counts
@@ -812,6 +908,7 @@ capture(int packet_count, int out_file_type)
fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
pcap_geterr(ld.pch));
}
+
pcap_close(ld.pch);
if (cfile.save_file != NULL) {
@@ -860,17 +957,9 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
static void
capture_cleanup(int signum)
{
- int err;
-
- fprintf(stderr, "\n");
- pcap_close(ld.pch);
- if (ld.pdh != NULL) {
- if (!wtap_dump_close(ld.pdh, &err)) {
- show_capture_file_io_error(cfile.save_file, err, TRUE);
- exit(2);
- }
- }
- exit(0);
+ /* Just set the loop flag to false. This will initiate
+ a proper termination. */
+ ld.go = FALSE;
}
#endif /* HAVE_LIBPCAP */
diff --git a/wiretap/file.c b/wiretap/file.c
index 6af9dc5536..edc3fd076c 100644
--- a/wiretap/file.c
+++ b/wiretap/file.c
@@ -1,6 +1,6 @@
/* file.c
*
- * $Id: file.c,v 1.74 2001/11/13 23:55:43 gram Exp $
+ * $Id: file.c,v 1.75 2001/12/04 07:32:05 guy Exp $
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -544,6 +544,7 @@ static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
wdh->file_type = filetype;
wdh->snaplen = snaplen;
wdh->encap = encap;
+ wdh->bytes_dumped = 0;
wdh->dump.opaque = NULL;
wdh->subtype_write = NULL;
wdh->subtype_close = NULL;
@@ -604,3 +605,8 @@ gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
g_free(wdh);
return ret;
}
+
+int wtap_get_bytes_dumped(wtap_dumper *wdh)
+{
+ return wdh->bytes_dumped;
+}
diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c
index 88175f72f8..b10d1d2317 100644
--- a/wiretap/libpcap.c
+++ b/wiretap/libpcap.c
@@ -1,6 +1,6 @@
/* libpcap.c
*
- * $Id: libpcap.c,v 1.61 2001/11/30 07:14:22 guy Exp $
+ * $Id: libpcap.c,v 1.62 2001/12/04 07:32:05 guy Exp $
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -1022,6 +1022,7 @@ gboolean libpcap_dump_open(wtap_dumper *wdh, int *err)
*err = WTAP_ERR_SHORT_WRITE;
return FALSE;
}
+ wdh->bytes_dumped += sizeof magic;
/* current "libpcap" format is 2.4 */
file_hdr.version_major = 2;
@@ -1038,6 +1039,7 @@ gboolean libpcap_dump_open(wtap_dumper *wdh, int *err)
*err = WTAP_ERR_SHORT_WRITE;
return FALSE;
}
+ wdh->bytes_dumped += sizeof file_hdr;
return TRUE;
}
@@ -1122,6 +1124,7 @@ static gboolean libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
*err = WTAP_ERR_SHORT_WRITE;
return FALSE;
}
+ wdh->bytes_dumped += hdr_size;
nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
if (nwritten != phdr->caplen) {
if (nwritten == 0 && ferror(wdh->fh))
@@ -1130,5 +1133,6 @@ static gboolean libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
*err = WTAP_ERR_SHORT_WRITE;
return FALSE;
}
+ wdh->bytes_dumped += phdr->caplen;
return TRUE;
}
diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h
index 1171d6af24..972b1d1988 100644
--- a/wiretap/wtap-int.h
+++ b/wiretap/wtap-int.h
@@ -1,6 +1,6 @@
/* wtap-int.h
*
- * $Id: wtap-int.h,v 1.15 2001/11/13 23:55:44 gram Exp $
+ * $Id: wtap-int.h,v 1.16 2001/12/04 07:32:05 guy Exp $
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -186,6 +186,7 @@ struct wtap_dumper {
int file_type;
int snaplen;
int encap;
+ int bytes_dumped;
union {
void *opaque;
diff --git a/wiretap/wtap.def b/wiretap/wtap.def
index 552753abf2..1df14018f7 100644
--- a/wiretap/wtap.def
+++ b/wiretap/wtap.def
@@ -16,6 +16,7 @@ wtap_file_encap
wtap_file_type
wtap_file_type_short_string
wtap_file_type_string
+wtap_get_bytes_dumped
wtap_loop
wtap_open_offline
wtap_pcap_encap_to_wtap_encap
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index 6ea5c84f3d..8835636079 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -1,6 +1,6 @@
/* wtap.h
*
- * $Id: wtap.h,v 1.96 2001/11/30 07:14:22 guy Exp $
+ * $Id: wtap.h,v 1.97 2001/12/04 07:32:05 guy Exp $
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
@@ -339,6 +339,7 @@ gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *,
const union wtap_pseudo_header *pseudo_header, const u_char *, int *err);
FILE* wtap_dump_file(wtap_dumper *);
gboolean wtap_dump_close(wtap_dumper *, int *);
+int wtap_get_bytes_dumped(wtap_dumper *);
/* XXX - needed until "wiretap" can do live packet captures */
int wtap_pcap_encap_to_wtap_encap(int encap);