diff options
author | Gilbert Ramirez <gram@alumni.rice.edu> | 2001-12-18 19:09:08 +0000 |
---|---|---|
committer | Gilbert Ramirez <gram@alumni.rice.edu> | 2001-12-18 19:09:08 +0000 |
commit | 791f5774d0fdabdb706bfd7056e534713cc4e4d6 (patch) | |
tree | 35f987f9914fead0fb5fefe79df280b7340831b4 /epan | |
parent | 4e013a44de86f8146cfd7d440adb67366e37273a (diff) | |
download | wireshark-791f5774d0fdabdb706bfd7056e534713cc4e4d6.tar.gz |
Provide for per-protocol-tree data in the proto_tree code.
Put a hash-table of "interesting" fields in the per-proto-tree data.
The dfilter code records which fields/protocols are "interesting" (by which
I mean, their value or existence is checked). Thus, the proto_tree routines
can create special arrays of field_info*'s that are ready for the dfilter
engine to use during a filter operation.
Also store the "proto_tree_is_visible" boolean, renamed "visible", in
the per-proto-tree data.
Move epan_dissect_t to its own header file to make #include dependencies
easier to handle.
Provide epan_dissect_fill_in_columns(), which accepts just the epan_dissect_t*
as an argument.
epan_dissect_new() needs to be followed by epan_dissect_run() for the
dissection to actually take place. Between those two calls,
epan_dissect_prime_dfilter() can be run 0, 1, or multiple times in order to
prime the empty proto_tree with the "intersesting" fields from the dfilter_t.
svn path=/trunk/; revision=4422
Diffstat (limited to 'epan')
-rw-r--r-- | epan/Makefile.am | 3 | ||||
-rw-r--r-- | epan/dfilter/dfilter-int.h | 5 | ||||
-rw-r--r-- | epan/dfilter/dfilter.c | 27 | ||||
-rw-r--r-- | epan/dfilter/dfilter.h | 12 | ||||
-rw-r--r-- | epan/dfilter/dfvm.c | 6 | ||||
-rw-r--r-- | epan/dfilter/gencode.c | 50 | ||||
-rw-r--r-- | epan/dfilter/gencode.h | 3 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 3 | ||||
-rw-r--r-- | epan/epan.c | 61 | ||||
-rw-r--r-- | epan/epan.h | 50 | ||||
-rw-r--r-- | epan/epan_dissect.h | 44 | ||||
-rw-r--r-- | epan/packet.c | 3 | ||||
-rw-r--r-- | epan/packet.h | 4 | ||||
-rw-r--r-- | epan/proto.c | 349 | ||||
-rw-r--r-- | epan/proto.h | 39 |
15 files changed, 441 insertions, 218 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am index 02e2c2b782..cefe353d0d 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -2,7 +2,7 @@ # Automake file for the EPAN library # (Ethereal Protocol ANalyzer Library) # -# $Id: Makefile.am,v 1.29 2001/11/22 03:07:06 hagbard Exp $ +# $Id: Makefile.am,v 1.30 2001/12/18 19:09:03 gram Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@zing.org> @@ -46,6 +46,7 @@ libethereal_a_SOURCES = \ column-utils.h \ epan.c \ epan.h \ + epan_dissect.h \ except.c \ except.h \ exceptions.h \ diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index c1e6774438..89e1857f8f 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -1,5 +1,5 @@ /* - * $Id: dfilter-int.h,v 1.3 2001/02/15 06:22:45 guy Exp $ + * $Id: dfilter-int.h,v 1.4 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -35,6 +35,8 @@ struct _dfilter_t { int num_registers; GList **registers; gboolean *attempted_load; + int *interesting_fields; + int num_interesting_fields; }; typedef struct { @@ -43,6 +45,7 @@ typedef struct { gboolean syntax_error; GPtrArray *insns; GHashTable *loaded_fields; + GHashTable *interesting_fields; int next_insn_id; int next_register; } dfwork_t; diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index 0380f15662..1f5743d23e 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -1,5 +1,5 @@ /* - * $Id: dfilter.c,v 1.5 2001/07/13 00:55:54 guy Exp $ + * $Id: dfilter.c,v 1.6 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -37,6 +37,7 @@ #include "gencode.h" #include "semcheck.h" #include "dfvm.h" +#include "epan_dissect.h" /* Balanced tree of abbreviations and IDs */ @@ -228,6 +229,10 @@ dfilter_free(dfilter_t *df) free_insns(df->insns); } + if (df->interesting_fields) { + g_free(df->interesting_fields); + } + g_free(df->registers); g_free(df->attempted_load); g_free(df); @@ -245,6 +250,7 @@ dfwork_new(void) dfw->syntax_error = FALSE; dfw->insns = NULL; dfw->loaded_fields = NULL; + dfw->interesting_fields = NULL; dfw->next_insn_id = 0; dfw->next_register = 0; @@ -262,10 +268,15 @@ dfwork_free(dfwork_t *dfw) g_hash_table_destroy(dfw->loaded_fields); } + if (dfw->interesting_fields) { + g_hash_table_destroy(dfw->interesting_fields); + } + if (dfw->insns) { free_insns(dfw->insns); } + g_free(dfw); } @@ -333,6 +344,8 @@ dfilter_compile(gchar *text, dfilter_t **dfp) dfilter = dfilter_new(); dfilter->insns = dfw->insns; dfw->insns = NULL; + dfilter->interesting_fields = dfw_interesting_fields(dfw, + &dfilter->num_interesting_fields); /* Initialize run-time space */ dfilter->num_registers = dfw->next_register; @@ -378,6 +391,18 @@ dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt) void +dfilter_foreach_interesting_field(dfilter_t *df, GFunc func, + gpointer user_data) +{ + int i; + + for (i = 0; i < df->num_interesting_fields; i++) { + func(GINT_TO_POINTER(df->interesting_fields[i]), user_data); + } +} + + +void dfilter_dump(dfilter_t *df) { dfvm_dump(stdout, df->insns); diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index afd93fb824..49eba9c5db 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -1,5 +1,5 @@ /* - * $Id: dfilter.h,v 1.2 2001/02/01 20:31:18 gram Exp $ + * $Id: dfilter.h,v 1.3 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -25,12 +25,14 @@ #define DFILTER_H #include <glib.h> -#include "epan.h" -#include "proto.h" /* Passed back to user */ typedef struct _dfilter_t dfilter_t; +#include "epan.h" +#include "proto.h" + + /* Module-level initialization */ void dfilter_init(void); @@ -75,6 +77,10 @@ dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); gboolean dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree); +/* Run a callback for each interesting field in the dfilter. */ +void +dfilter_foreach_interesting_field(dfilter_t *df, GFunc func, + gpointer user_data); /* Print bytecode of dfilter to stdout */ void diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c index bc1c48c21d..02bf948a5c 100644 --- a/epan/dfilter/dfvm.c +++ b/epan/dfilter/dfvm.c @@ -1,5 +1,5 @@ /* - * $Id: dfvm.c,v 1.4 2001/12/13 05:55:23 gram Exp $ + * $Id: dfvm.c,v 1.5 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -211,6 +211,9 @@ read_tree(dfilter_t *df, proto_tree *tree, int field_id, int reg) if (!finfos) { return FALSE; } + else if (g_ptr_array_len(finfos) == 0) { + return FALSE; + } len = finfos->len; for (i = 0; i < len; i++) { @@ -218,7 +221,6 @@ read_tree(dfilter_t *df, proto_tree *tree, int field_id, int reg) fvalues = g_list_prepend(fvalues, finfo->value); } fvalues = g_list_reverse(fvalues); - g_ptr_array_free(finfos, TRUE); df->registers[reg] = fvalues; return TRUE; diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c index cf3e1d5787..d8d0119005 100644 --- a/epan/dfilter/gencode.c +++ b/epan/dfilter/gencode.c @@ -1,5 +1,5 @@ /* - * $Id: gencode.c,v 1.3 2001/02/27 19:23:28 gram Exp $ + * $Id: gencode.c,v 1.4 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -57,7 +57,7 @@ dfw_append_read_tree(dfwork_t *dfw, int field_id) * can re-use registers. */ reg = GPOINTER_TO_UINT( g_hash_table_lookup(dfw->loaded_fields, - GUINT_TO_POINTER(field_id))); + GINT_TO_POINTER(field_id))); if (reg) { /* Reg's are stored in has as reg+1, so * that the non-existence of a field_id in @@ -70,6 +70,10 @@ dfw_append_read_tree(dfwork_t *dfw, int field_id) g_hash_table_insert(dfw->loaded_fields, GUINT_TO_POINTER(field_id), GUINT_TO_POINTER(reg + 1)); + + /* Record the FIELD_ID in hash of interesting fields. */ + g_hash_table_insert(dfw->interesting_fields, + GINT_TO_POINTER(field_id), GUINT_TO_POINTER(TRUE)); } insn = dfvm_insn_new(READ_TREE); @@ -232,6 +236,11 @@ gen_test(dfwork_t *dfw, stnode_t *st_node) insn = dfvm_insn_new(CHECK_EXISTS); insn->arg1 = val1; dfw_append_insn(dfw, insn); + + /* Record the FIELD_ID in hash of interesting fields. */ + g_hash_table_insert(dfw->interesting_fields, + GINT_TO_POINTER(hfinfo->id), GUINT_TO_POINTER(TRUE)); + break; case TEST_OP_NOT: @@ -312,7 +321,44 @@ dfw_gencode(dfwork_t *dfw) { dfw->insns = g_ptr_array_new(); dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal); + dfw->interesting_fields = g_hash_table_new(g_direct_hash, g_direct_equal); gencode(dfw, dfw->st_root); dfw_append_insn(dfw, dfvm_insn_new(RETURN)); } + + +typedef struct { + int i; + int *fields; +} hash_key_iterator; + +static void +get_hash_key(gpointer key, gpointer value, gpointer user_data) +{ + int field_id = GPOINTER_TO_INT(key); + hash_key_iterator *hki = user_data; + + hki->fields[hki->i] = field_id; + hki->i++; +} + +int* +dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields) +{ + int num_fields = g_hash_table_size(dfw->interesting_fields); + + hash_key_iterator hki; + + if (num_fields == 0) { + *caller_num_fields = 0; + return NULL; + } + + hki.fields = g_new(int, num_fields); + hki.i = 0; + + g_hash_table_foreach(dfw->interesting_fields, get_hash_key, &hki); + *caller_num_fields = num_fields; + return hki.fields; +} diff --git a/epan/dfilter/gencode.h b/epan/dfilter/gencode.h index db56b9082c..2148b2be58 100644 --- a/epan/dfilter/gencode.h +++ b/epan/dfilter/gencode.h @@ -4,4 +4,7 @@ void dfw_gencode(dfwork_t *dfw); +int* +dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields); + #endif diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index 025d471baa..5afb7b6b0a 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -1,5 +1,5 @@ /* - * $Id: semcheck.c,v 1.6 2001/11/02 10:09:49 guy Exp $ + * $Id: semcheck.c,v 1.7 2001/12/18 19:09:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -32,6 +32,7 @@ #include "sttype-test.h" #include "exceptions.h" +#include "packet.h" static void semcheck(dfwork_t *dfw, stnode_t *st_node); diff --git a/epan/epan.c b/epan/epan.c index 20edfb4b42..4be784e8b2 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -1,6 +1,6 @@ /* epan.h * - * $Id: epan.c,v 1.14 2001/12/16 22:16:13 guy Exp $ + * $Id: epan.c,v 1.15 2001/12/18 19:09:03 gram Exp $ * * Ethereal Protocol Analyzer Library * @@ -11,14 +11,13 @@ #endif #include <glib.h> -#include <epan.h> +#include "epan.h" +#include "epan_dissect.h" #include "conversation.h" -#include "dfilter/dfilter.h" #include "except.h" #include "packet.h" -#include "proto.h" -#include "tvbuff.h" +#include "column-utils.h" /* * XXX - this takes the plugin directory as an argument, because @@ -74,37 +73,34 @@ epan_conversation_init(void) epan_dissect_t* -epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, - gboolean create_proto_tree, gboolean proto_tree_visible, - column_info *cinfo) +epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible) { epan_dissect_t *edt; edt = g_new(epan_dissect_t, 1); - /* start with empty data source list */ - if ( fd->data_src) - g_slist_free( fd->data_src); - fd->data_src = 0; - - /* - * Set the global "proto_tree_is_visible" to control whether - * to fill in the text representation field in the protocol - * tree fields. - */ - proto_tree_is_visible = proto_tree_visible; if (create_proto_tree) { edt->tree = proto_tree_create_root(); + proto_tree_set_visible(edt->tree, proto_tree_visible); } else { edt->tree = NULL; } - dissect_packet(edt, pseudo_header, data, fd, cinfo); + return edt; +} - proto_tree_is_visible = FALSE; +void +epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, + const guint8* data, frame_data *fd, column_info *cinfo) +{ + /* start with empty data source list */ + if (fd->data_src) { + g_slist_free(fd->data_src); + } + fd->data_src = NULL; - return edt; + dissect_packet(edt, pseudo_header, data, fd, cinfo); } @@ -122,3 +118,24 @@ epan_dissect_free(epan_dissect_t* edt) g_free(edt); } + +static void +prime_dfilter(gpointer data, gpointer user_data) +{ + int hfid = GPOINTER_TO_INT(data); + proto_tree *tree = user_data; + + proto_tree_prime_hfid(tree, hfid); +} + +void +epan_dissect_prime_dfilter(epan_dissect_t *edt, dfilter_t* dfcode) +{ + dfilter_foreach_interesting_field(dfcode, prime_dfilter, edt->tree); +} + +void +epan_dissect_fill_in_columns(epan_dissect_t *edt) +{ + fill_in_columns(&edt->pi); +} diff --git a/epan/epan.h b/epan/epan.h index f33cb1034e..3a3197f540 100644 --- a/epan/epan.h +++ b/epan/epan.h @@ -1,21 +1,37 @@ /* epan.h * - * $Id: epan.h,v 1.11 2001/12/16 22:16:13 guy Exp $ + * $Id: epan.h,v 1.12 2001/12/18 19:09:03 gram Exp $ * * Ethereal Protocol Analyzer Library * + * Copyright (c) 2001 by Gerald Combs <gerald@ethereal.com> + * + * 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 EPAN_H #define EPAN_H #include <glib.h> +#include "frame_data.h" +#include "column_info.h" -struct _epan_dissect_t; +typedef struct _epan_dissect_t epan_dissect_t; -/* XXX - for now */ -#include "packet.h" -#include "packet_info.h" +#include "dfilter/dfilter.h" void epan_init(const char * plugindir, void (register_all_protocols)(void), void (register_all_handoffs)(void)); @@ -40,24 +56,18 @@ void epan_free(epan_t*); +epan_dissect_t* +epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible); +void +epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, + const guint8* data, frame_data *fd, column_info *cinfo); -/* Dissection of a single byte array. Holds tvbuff info as - * well as proto_tree info. As long as the epan_dissect_t for a byte - * array is in existence, you must not free or move that byte array, - * as the structures that the epan_dissect_t contains might have pointers - * to addresses in your byte array. - */ -typedef struct _epan_dissect_t { - tvbuff_t *tvb; - proto_tree *tree; - packet_info pi; -} epan_dissect_t; +void +epan_dissect_prime_dfilter(epan_dissect_t *edt, dfilter_t*); -epan_dissect_t* -epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, - gboolean create_proto_tree, gboolean proto_tree_visible, - column_info *cinfo); +void +epan_dissect_fill_in_columns(epan_dissect_t *edt); void epan_dissect_free(epan_dissect_t* edt); diff --git a/epan/epan_dissect.h b/epan/epan_dissect.h new file mode 100644 index 0000000000..424ea60484 --- /dev/null +++ b/epan/epan_dissect.h @@ -0,0 +1,44 @@ +/* epan_dissect.h + * + * $Id: epan_dissect.h,v 1.1 2001/12/18 19:09:03 gram Exp $ + * + * Ethereal Protocol Analyzer Library + * + * Copyright (c) 2001 by Gerald Combs <gerald@ethereal.com> + * + * 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 EPAN_DISSECT_H +#define EPAN_DISSECT_H + +#include "tvbuff.h" +#include "proto.h" +#include "packet_info.h" + +/* Dissection of a single byte array. Holds tvbuff info as + * well as proto_tree info. As long as the epan_dissect_t for a byte + * array is in existence, you must not free or move that byte array, + * as the structures that the epan_dissect_t contains might have pointers + * to addresses in your byte array. + */ +struct _epan_dissect_t { + tvbuff_t *tvb; + proto_tree *tree; + packet_info pi; +}; + + +#endif /* EPAN_DISSECT_H */ diff --git a/epan/packet.c b/epan/packet.c index b6f299a0a1..6ef976a430 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1,7 +1,7 @@ /* packet.c * Routines for packet disassembly * - * $Id: packet.c,v 1.54 2001/12/10 00:26:16 guy Exp $ + * $Id: packet.c,v 1.55 2001/12/18 19:09:03 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -79,6 +79,7 @@ #include "resolv.h" #include "tvbuff.h" #include "plugins.h" +#include "epan_dissect.h" static gint proto_malformed = -1; static dissector_handle_t frame_handle = NULL; diff --git a/epan/packet.h b/epan/packet.h index 812e653cbf..5d4a048c75 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -1,7 +1,7 @@ /* packet.h * Definitions for packet disassembly structures and routines * - * $Id: packet.h,v 1.47 2001/12/10 00:26:16 guy Exp $ + * $Id: packet.h,v 1.48 2001/12/18 19:09:03 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -226,7 +226,7 @@ extern void init_all_protocols(void); /* * Dissectors should never modify the packet data. */ -extern void dissect_packet(struct _epan_dissect_t *edt, +extern void dissect_packet(epan_dissect_t *edt, union wtap_pseudo_header *pseudo_header, const u_char *pd, frame_data *fd, column_info *cinfo); diff --git a/epan/proto.c b/epan/proto.c index 0db8366551..56e68454b2 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -1,7 +1,7 @@ /* proto.c * Routines for protocol tree * - * $Id: proto.c,v 1.47 2001/12/07 03:39:26 gram Exp $ + * $Id: proto.c,v 1.48 2001/12/18 19:09:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -73,11 +73,12 @@ static proto_item* proto_tree_add_node(proto_tree *tree, field_info *fi); static field_info * -alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length); +alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length); static proto_item * -proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, - field_info **pfi); +proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, field_info **pfi); static void proto_tree_set_representation(proto_item *pi, const char *format, va_list ap); @@ -138,6 +139,12 @@ typedef struct { /* List of all protocols */ static GList *protocols; +#define INITIAL_NUM_PROTOCOL_HFINFO 200 +#define INITIAL_NUM_FIELD_INFO 100 +#define INITIAL_NUM_PROTO_NODE 100 +#define INITIAL_NUM_ITEM_LABEL 100 + + /* Contains information about protocols and header fields. Used when * dissectors register their data */ static GMemChunk *gmc_hfinfo = NULL; @@ -146,6 +153,9 @@ static GMemChunk *gmc_hfinfo = NULL; * proto_tree_add_item. */ static GMemChunk *gmc_field_info = NULL; +/* Contains the space for proto_nodes. */ +static GMemChunk *gmc_proto_node = NULL; + /* String space for protocol and field items for the GUI */ static GMemChunk *gmc_item_labels = NULL; @@ -160,12 +170,6 @@ gboolean *tree_is_expanded; /* Number of elements in that array. */ int num_tree_types; -/* Is the parsing being done for a visible proto_tree or an invisible one? - * By setting this correctly, the proto_tree creation is sped up by not - * having to call vsnprintf and copy strings around. - */ -gboolean proto_tree_is_visible = FALSE; - /* initialize data structures and register protocols and fields */ void proto_init(const char *plugin_dir,void (register_all_protocols)(void), @@ -181,6 +185,8 @@ proto_init(const char *plugin_dir,void (register_all_protocols)(void), g_mem_chunk_destroy(gmc_hfinfo); if (gmc_field_info) g_mem_chunk_destroy(gmc_field_info); + if (gmc_proto_node) + g_mem_chunk_destroy(gmc_proto_node); if (gmc_item_labels) g_mem_chunk_destroy(gmc_item_labels); if (gpa_hfinfo) @@ -189,13 +195,25 @@ proto_init(const char *plugin_dir,void (register_all_protocols)(void), g_free(tree_is_expanded); gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo", - sizeof(header_field_info), 50 * sizeof(header_field_info), G_ALLOC_ONLY); + sizeof(header_field_info), + INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info), + G_ALLOC_ONLY); + gmc_field_info = g_mem_chunk_new("gmc_field_info", - sizeof(struct field_info), 200 * sizeof(struct field_info), + sizeof(field_info), + INITIAL_NUM_FIELD_INFO * sizeof(field_info), G_ALLOC_AND_FREE); + + gmc_proto_node = g_mem_chunk_new("gmc_proto_node", + sizeof(proto_node), + INITIAL_NUM_PROTO_NODE * sizeof(proto_node), + G_ALLOC_AND_FREE); + gmc_item_labels = g_mem_chunk_new("gmc_item_labels", - ITEM_LABEL_LENGTH, 20 * ITEM_LABEL_LENGTH, + ITEM_LABEL_LENGTH, + INITIAL_NUM_ITEM_LABEL* ITEM_LABEL_LENGTH, G_ALLOC_AND_FREE); + gpa_hfinfo = g_ptr_array_new(); /* Allocate "tree_is_expanded", with one element for ETT_NONE, @@ -248,10 +266,14 @@ proto_cleanup(void) g_mem_chunk_destroy(gmc_hfinfo); if (gmc_field_info) g_mem_chunk_destroy(gmc_field_info); + if (gmc_proto_node) + g_mem_chunk_destroy(gmc_proto_node); if (gmc_item_labels) g_mem_chunk_destroy(gmc_item_labels); if (gpa_hfinfo) g_ptr_array_free(gpa_hfinfo, TRUE); + if (tree_is_expanded != NULL) + g_free(tree_is_expanded); /* Cleanup the ftype subsystem */ ftypes_cleanup(); @@ -261,8 +283,11 @@ proto_cleanup(void) void proto_tree_free(proto_tree *tree) { + /* Free all the data pointed to by the tree. */ g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, -1, proto_tree_free_node, NULL); + + /* Then free the tree. */ g_node_destroy((GNode*)tree); } @@ -273,20 +298,69 @@ free_field_info(void *fi) g_mem_chunk_free(gmc_field_info, (field_info*)fi); } -static gboolean -proto_tree_free_node(GNode *node, gpointer data) +static void +free_GPtrArray_value(gpointer key, gpointer value, gpointer user_data) { - field_info *fi = (field_info*) (node->data); + GPtrArray *ptrs = value; - if (fi != NULL) { - if (fi->representation) { - g_mem_chunk_free(gmc_item_labels, fi->representation); + g_ptr_array_free(ptrs, TRUE); +} + +static void +free_node_tree_data(tree_data_t *tree_data) +{ + /* Free all the GPtrArray's in the interesting_hfids hash. */ + g_hash_table_foreach(tree_data->interesting_hfids, + free_GPtrArray_value, NULL); + + /* And then destroy the hash. */ + g_hash_table_destroy(tree_data->interesting_hfids); + + /* And finally the tree_data_t itself. */ + g_free(tree_data); +} + +static void +free_node_field_info(field_info* finfo) +{ + if (finfo->representation) { + g_mem_chunk_free(gmc_item_labels, finfo->representation); } - fvalue_free(fi->value); - free_field_info(fi); + fvalue_free(finfo->value); + free_field_info(finfo); +} + +static gboolean +proto_tree_free_node(GNode *node, gpointer data) +{ + field_info *finfo = PITEM_FINFO(node); + + if (finfo == NULL) { + /* This is the root GNode. Destroy the per-tree data. + * There is no field_info to destroy. */ + free_node_tree_data(PTREE_DATA(node)); + } + else { + /* This is a child GNode. Don't free the per-tree data, but + * do free the field_info data. */ + free_node_field_info(finfo); } + + /* Free the proto_node. */ + g_mem_chunk_free(gmc_proto_node, GNODE_PNODE(node)); + return FALSE; /* FALSE = do not end traversal of GNode tree */ -} +} + +/* Is the parsing being done for a visible proto_tree or an invisible one? + * By setting this correctly, the proto_tree creation is sped up by not + * having to call vsnprintf and copy strings around. + */ +void +proto_tree_set_visible(proto_tree *tree, gboolean visible) +{ + PTREE_DATA(tree)->visible = visible; +} /* Finds a record in the hf_info_records array by id. */ header_field_info* @@ -451,11 +525,13 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint32 value, n; char *string; int found_length; + GHashTable *hash; + GPtrArray *ptrs; if (!tree) return(NULL); - new_fi = alloc_field_info(hfindex, tvb, start, length); + new_fi = alloc_field_info(tree, hfindex, tvb, start, length); if (new_fi == NULL) return(NULL); @@ -574,6 +650,14 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, * raised by a tvbuff access method doesn't leave junk in the proto_tree. */ pi = proto_tree_add_node(tree, new_fi); + /* If the proto_tree wants to keep a record of this finfo + * for quick lookup, then record it. */ + hash = PTREE_DATA(tree)->interesting_hfids; + ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex)); + if (ptrs) { + g_ptr_array_add(ptrs, new_fi); + } + return pi; } @@ -588,7 +672,7 @@ proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, if (pi == NULL) return(NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -691,7 +775,7 @@ proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -767,7 +851,7 @@ proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -830,7 +914,7 @@ proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -893,7 +977,7 @@ proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -956,7 +1040,7 @@ proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1047,7 +1131,7 @@ proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1122,7 +1206,7 @@ proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1191,7 +1275,7 @@ proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1254,7 +1338,7 @@ proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1326,7 +1410,7 @@ proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1413,7 +1497,7 @@ proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint sta if (pi == NULL) return (NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->visible = FALSE; return pi; @@ -1464,12 +1548,17 @@ proto_tree_set_int(field_info *fi, gint32 value) static proto_item * proto_tree_add_node(proto_tree *tree, field_info *fi) { - proto_item *pi; + GNode *new_gnode; + proto_node *pnode; - pi = (proto_item*) g_node_new(fi); - g_node_append((GNode*)tree, (GNode*)pi); + pnode = g_mem_chunk_alloc(gmc_proto_node); + pnode->finfo = fi; + pnode->tree_data = PTREE_DATA(tree); - return pi; + new_gnode = g_node_new(pnode); + g_node_append((GNode*)tree, new_gnode); + + return (proto_item*) new_gnode; } @@ -1481,13 +1570,24 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint { proto_item *pi; field_info *fi; + GHashTable *hash; + GPtrArray *ptrs; if (!tree) return(NULL); - fi = alloc_field_info(hfindex, tvb, start, length); + fi = alloc_field_info(tree, hfindex, tvb, start, length); pi = proto_tree_add_node(tree, fi); + /* If the proto_tree wants to keep a record of this finfo + * for quick lookup, then record it. */ + hash = PTREE_DATA(tree)->interesting_hfids; + ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex)); + if (ptrs) { + g_ptr_array_add(ptrs, fi); + } + + /* Does the caller want to know the fi pointer? */ if (pfi) { *pfi = fi; } @@ -1496,7 +1596,7 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint } static field_info * -alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length) +alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length) { field_info *fi; @@ -1517,7 +1617,7 @@ alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length) } fi->length = length; fi->tree_type = ETT_NONE; - fi->visible = proto_tree_is_visible; + fi->visible = PTREE_DATA(tree)->visible; fi->representation = NULL; fi->value = fvalue_new(fi->hfinfo->type); @@ -1537,7 +1637,7 @@ alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length) static void proto_tree_set_representation(proto_item *pi, const char *format, va_list ap) { - field_info *fi = (field_info*) (((GNode*)pi)->data); + field_info *fi = PITEM_FINFO(pi); if (fi->visible) { fi->representation = g_mem_chunk_alloc(gmc_item_labels); @@ -1556,7 +1656,7 @@ proto_item_set_text(proto_item *pi, const char *format, ...) return; } - fi = (field_info *)(((GNode*)pi)->data); + fi = PITEM_FINFO(pi); if (fi->representation) g_mem_chunk_free(gmc_item_labels, fi->representation); @@ -1578,7 +1678,7 @@ proto_item_append_text(proto_item *pi, const char *format, ...) return; } - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); if (fi->visible) { va_start(ap, format); @@ -1603,21 +1703,45 @@ proto_item_set_len(proto_item *pi, gint length) if (pi == NULL) return; - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); fi->length = length; } int proto_item_get_len(proto_item *pi) { - field_info *fi = (field_info*) (((GNode*)pi)->data); + field_info *fi = PITEM_FINFO(pi); return fi->length; } proto_tree* proto_tree_create_root(void) { - return (proto_tree*) g_node_new(NULL); + proto_node *pnode; + + /* Initialize the proto_node */ + pnode = g_mem_chunk_alloc(gmc_proto_node); + pnode->finfo = NULL; + pnode->tree_data = g_new(tree_data_t, 1); + + /* Initialize the tree_data_t */ + pnode->tree_data->interesting_hfids = + g_hash_table_new(g_direct_hash, g_direct_equal); + + /* Set the default to FALSE so it's easier to + * find errors; if we expect to see the protocol tree + * but for some reason the default 'visible' is not + * changed, then we'll find out very quickly. */ + pnode->tree_data->visible = FALSE; + + return (proto_tree*) g_node_new(pnode); +} + +void +proto_tree_prime_hfid(proto_tree *tree, int hfid) +{ + g_hash_table_insert(PTREE_DATA(tree)->interesting_hfids, + GINT_TO_POINTER(hfid), g_ptr_array_new()); } proto_tree* @@ -1627,7 +1751,7 @@ proto_item_add_subtree(proto_item *pi, gint idx) { if (!pi) return(NULL); - fi = (field_info*) (((GNode*)pi)->data); + fi = PITEM_FINFO(pi); g_assert(idx >= 0 && idx < num_tree_types); fi->tree_type = idx; return (proto_tree*) pi; @@ -2594,7 +2718,7 @@ proto_find_protocol_multi(proto_tree* tree, GNodeTraverseFunc callback, static gboolean traverse_subtree_for_field(GNode *node, gpointer data) { - field_info *fi = (field_info*) (node->data); + field_info *fi = PITEM_FINFO(node); proto_tree_search_info *sinfo = (proto_tree_search_info*) data; if (fi) { /* !fi == the top most container node which holds nothing */ @@ -2606,126 +2730,37 @@ traverse_subtree_for_field(GNode *node, gpointer data) return FALSE; /* keep traversing */ } -static gboolean -check_for_protocol_or_field_id(GNode *node, gpointer data) -{ - field_info *fi = (field_info*) (node->data); - proto_tree_search_info *sinfo = (proto_tree_search_info*) data; - header_field_info *hfinfo; - - if (fi) { /* !fi == the top most container node which holds nothing */ - /* Is this field one of the fields in the specified list - * of fields? */ - for (hfinfo = sinfo->target; hfinfo != NULL; - hfinfo = hfinfo->same_name_next) { - if (fi->hfinfo == hfinfo) { - sinfo->result.node = node; - return TRUE; /* halt traversal */ - } - } - } - return FALSE; /* keep traversing */ -} - /* Looks for a protocol or a field in a proto_tree. Returns TRUE if * it exists anywhere, or FALSE if it exists nowhere. */ gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id) { - proto_tree_search_info sinfo; - header_field_info *hfinfo; - - hfinfo = proto_registrar_get_nth(id); - - /* Find the first entry on the list of fields with the same - * name as this field. */ - while (hfinfo->same_name_prev != NULL) - hfinfo = hfinfo->same_name_prev; - - sinfo.target = hfinfo; - sinfo.result.node = NULL; - sinfo.traverse_func = check_for_protocol_or_field_id; - sinfo.halt_on_first_hit = TRUE; - - /* do a quicker check if target is a protocol */ - if (proto_registrar_is_protocol(id) == TRUE) { - proto_find_protocol_multi(tree, check_for_protocol_or_field_id, &sinfo); - } - else { - /* Go through each protocol subtree. */ - g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, - traverse_subtree_for_field, &sinfo); - } - - if (sinfo.result.node) - return TRUE; - else - return FALSE; -} - - - -static gboolean -get_finfo_ptr_array(GNode *node, gpointer data) -{ - field_info *fi = (field_info*) (node->data); - proto_tree_search_info *sinfo = (proto_tree_search_info*) data; - header_field_info *hfinfo; + GPtrArray *ptrs = proto_get_finfo_ptr_array(tree, id); - if (fi) { /* !fi == the top most container node which holds nothing */ - /* Is this field one of the fields in the specified list - * of fields? */ - for (hfinfo = sinfo->target; hfinfo != NULL; - hfinfo = hfinfo->same_name_next) { - if (fi->hfinfo == hfinfo) { - if (!sinfo->result.ptr_array) { - sinfo->result.ptr_array = g_ptr_array_new(); - } - g_ptr_array_add(sinfo->result.ptr_array, - (gpointer)fi); - return FALSE; /* keep traversing */ - } - } - } - return FALSE; /* keep traversing */ + if (!ptrs) { + return FALSE; + } + else if (g_ptr_array_len(ptrs) > 0) { + return TRUE; + } + else { + return FALSE; + } } -/* Return GPtrArray* of field_info pointers for all hfindex that appear in tree - * (we assume that a field will only appear under its registered parent's subtree) */ +/* Return GPtrArray* of field_info pointers for all hfindex that appear in tree. + * This only works if the hfindex was "primed" before the dissection + * took place, as we just pass back the already-created GPtrArray*. + * The caller should *not* free the GPtrArray*; proto_tree_free_node() + * handles that. */ GPtrArray* proto_get_finfo_ptr_array(proto_tree *tree, int id) { - proto_tree_search_info sinfo; - header_field_info *hfinfo; - - hfinfo = proto_registrar_get_nth(id); - - /* Find the first entry on the list of fields with the same - * name as this field. */ - while (hfinfo->same_name_prev != NULL) - hfinfo = hfinfo->same_name_prev; - - sinfo.target = hfinfo; - sinfo.result.ptr_array = NULL; - sinfo.traverse_func = get_finfo_ptr_array; - sinfo.halt_on_first_hit = FALSE; - - /* do a quicker check if target is a protocol */ - if (proto_registrar_is_protocol(id) == TRUE) { - proto_find_protocol_multi(tree, get_finfo_ptr_array, &sinfo); - } - else { - /* Go through each protocol subtree. */ - sinfo.traverse_func = get_finfo_ptr_array; - g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, - traverse_subtree_for_field, &sinfo); - } - - return sinfo.result.ptr_array; + return g_hash_table_lookup(PTREE_DATA(tree)->interesting_hfids, + GINT_TO_POINTER(id)); } - typedef struct { guint offset; field_info *finfo; @@ -2735,7 +2770,7 @@ typedef struct { static gboolean check_for_offset(GNode *node, gpointer data) { - field_info *fi = node->data; + field_info *fi = PITEM_FINFO(node); offset_search_t *offsearch = data; /* !fi == the top most container node which holds nothing */ diff --git a/epan/proto.h b/epan/proto.h index 57ed884705..6d86378ff8 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1,7 +1,7 @@ /* proto.h * Definitions for protocol display * - * $Id: proto.h,v 1.24 2001/12/07 03:39:26 gram Exp $ + * $Id: proto.h,v 1.25 2001/12/18 19:09:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -42,9 +42,6 @@ #include "tvbuff.h" #include "ftypes/ftypes.h" - -typedef GNode proto_tree; -typedef GNode proto_item; struct value_string; #define ITEM_LABEL_LENGTH 240 @@ -107,7 +104,7 @@ typedef struct hf_register_info { } hf_register_info; -/* Info stored in each proto_item GNode */ +/* Contains the field information for the proto_item. */ typedef struct field_info { header_field_info *hfinfo; gint start; @@ -119,6 +116,31 @@ typedef struct field_info { gchar *ds_name; /* data source name */ } field_info; +/* One of these exists for the entire protocol tree. Each proto_node + * in the protocol tree points to the same copy. */ +typedef struct { + GHashTable *interesting_hfids; + gboolean visible; +} tree_data_t; + +/* Each GNode (proto_tree, proto_item) points to one of + * these. */ +typedef struct { + field_info *finfo; + tree_data_t *tree_data; +} proto_node; + +typedef GNode proto_tree; +typedef GNode proto_item; + +/* Retrieve the proto_node from a GNode. */ +#define GNODE_PNODE(t) ((proto_node*)((GNode*)(t))->data) + +/* Retrieve the field_info from a proto_item */ +#define PITEM_FINFO(t) (GNODE_PNODE(t)->finfo) + +/* Retrieve the tree_data_t from a proto_tree */ +#define PTREE_DATA(t) (GNODE_PNODE(t)->tree_data) /* Sets up memory used by proto routines. Called at program startup */ extern void proto_init(const char *plugin_dir, @@ -153,6 +175,10 @@ extern int proto_item_get_len(proto_item *ti); /* Creates new proto_tree root */ extern proto_tree* proto_tree_create_root(void); +/* Mark a field/protocol ID as "interesting". */ +void +proto_tree_prime_hfid(proto_tree *tree, int hfid); + /* Clear memory for entry proto_tree. Clears proto_tree struct also. */ extern void proto_tree_free(proto_tree *tree); @@ -457,6 +483,9 @@ proto_tree_add_debug_text(proto_tree *tree, const char *format, ...); extern void proto_item_fill_label(field_info *fi, gchar *label_str); +extern void +proto_tree_set_visible(proto_tree *tree, gboolean visible); + /* Returns number of items (protocols or header fields) registered. */ extern int proto_registrar_n(void); |