diff options
author | Guy Harris <guy@alum.mit.edu> | 2001-12-04 07:32:05 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2001-12-04 07:32:05 +0000 |
commit | a1660d6d3afbaeccd77d8e34c695bf65a4f4f09e (patch) | |
tree | 20e71ed2ee0399b430f10ab92177fb1d5fc7e953 | |
parent | 9426c4ad15826cee237cc1f822c8a758d01473f6 (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-- | AUTHORS | 7 | ||||
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | Makefile.nmake | 6 | ||||
-rw-r--r-- | capture.c | 37 | ||||
-rw-r--r-- | capture_stop_conditions.c | 208 | ||||
-rw-r--r-- | capture_stop_conditions.h | 29 | ||||
-rw-r--r-- | conditions.c | 205 | ||||
-rw-r--r-- | conditions.h | 134 | ||||
-rw-r--r-- | doc/ethereal.pod.template | 27 | ||||
-rw-r--r-- | doc/tethereal.pod.template | 26 | ||||
-rw-r--r-- | file.h | 6 | ||||
-rw-r--r-- | gtk/capture_dlg.c | 124 | ||||
-rw-r--r-- | gtk/main.c | 73 | ||||
-rw-r--r-- | tethereal.c | 127 | ||||
-rw-r--r-- | wiretap/file.c | 8 | ||||
-rw-r--r-- | wiretap/libpcap.c | 6 | ||||
-rw-r--r-- | wiretap/wtap-int.h | 3 | ||||
-rw-r--r-- | wiretap/wtap.def | 1 | ||||
-rw-r--r-- | wiretap/wtap.h | 3 |
19 files changed, 984 insertions, 52 deletions
@@ -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 \ @@ -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 @@ -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); |