From 55cd52837f2c7fab796b54e75a8b13b714a46e05 Mon Sep 17 00:00:00 2001 From: guy Date: Tue, 4 Dec 2001 07:32:05 +0000 Subject: Support for stopping capture at specified capture file size or capture duration, from Thomas Wittwer and Matthias Nyffenegger. git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@4322 f5534014-38df-0310-8fa8-9805f1628bb7 --- AUTHORS | 7 ++ Makefile.am | 6 +- Makefile.nmake | 6 +- capture.c | 37 +++++++- capture_stop_conditions.c | 208 +++++++++++++++++++++++++++++++++++++++++++++ capture_stop_conditions.h | 29 +++++++ conditions.c | 205 ++++++++++++++++++++++++++++++++++++++++++++ conditions.h | 134 +++++++++++++++++++++++++++++ doc/ethereal.pod.template | 27 +++++- doc/tethereal.pod.template | 26 +++++- file.h | 6 +- gtk/capture_dlg.c | 124 +++++++++++++++++++++++---- gtk/main.c | 73 ++++++++++++++-- tethereal.c | 127 ++++++++++++++++++++++----- wiretap/file.c | 8 +- wiretap/libpcap.c | 6 +- wiretap/wtap-int.h | 3 +- wiretap/wtap.def | 1 + wiretap/wtap.h | 3 +- 19 files changed, 984 insertions(+), 52 deletions(-) create mode 100644 capture_stop_conditions.c create mode 100644 capture_stop_conditions.h create mode 100644 conditions.c create mode 100644 conditions.h diff --git a/AUTHORS b/AUTHORS index 9a94cba80e..53c4b3ff8a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -805,6 +805,13 @@ Thomas Wittwer { 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 { + Support for stopping capture at specified capture file size or + capture duration } Palle Lyckegaard { 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 @@ -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 @@ -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 @@ -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 + * 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 +#include +#include +#include +#include +#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 + * 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 + * 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 +#include +#include +#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 + * 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 + +#include + +/* 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 +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 is to stop writing +to a capture file. The criterion is of the form IB<:>I, +where I is one of: + +=for man .RS + +=for html

+ +=item duration + +Stop writing to a capture file after I seconds have elapsed. + +=item filesize + +Stop writing to a capture file after it reaches a size of I +kilobytes (where a kilobyte is 1000 bytes, not 1024 bytes). + +=for man .RE + +=for html
+ =item -B Sets the initial height of the byte view (bottom) pane. @@ -1198,6 +1222,7 @@ B. Terje Krogdahl Jean-Francois Mule Thomas Wittwer + Matthias Nyffenegger Palle Lyckegaard Nicolas Balkota Tom Uijldert 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 +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 is to stop writing +to a capture file. The criterion is of the form IB<:>I, +where I is one of: + +=for man .RS + +=for html

+ +=item duration + +Stop writing to a capture file after I seconds have elapsed. + +=item filesize + +Stop writing to a capture file after it reaches a size of I +kilobytes (where a kilobyte is 1000 bytes, not 1024 bytes). + +=for man .RE + +=for html
+ =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 @@ -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 @@ -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 @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include @@ -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 ] [ -c ]\n", + fprintf(stderr, "%s [ -vh ] [ -klpQS ] [ -a ] ...\n", PACKAGE); - fprintf(stderr, "\t[ -f ] [ -i ] [ -m ] \n"); - fprintf(stderr, "\t[ -n ] [ -N ]\n"); + fprintf(stderr, "\t[ -B ] [ -c ] [ -f ]\n"); + fprintf(stderr, "\t[ -i ] [ -m ] [ -n ] [ -N ]\n"); fprintf(stderr, "\t[ -o ] ... [ -P ]\n"); fprintf(stderr, "\t[ -r ] [ -R ] [ -s ] \n"); fprintf(stderr, "\t[ -t