diff options
Diffstat (limited to 'epan/proto.c')
-rw-r--r-- | epan/proto.c | 158 |
1 files changed, 143 insertions, 15 deletions
diff --git a/epan/proto.c b/epan/proto.c index e45a77e963..eba7cb41ac 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -48,6 +48,35 @@ #define cVALS(x) (const value_string*)(x) +#if 1 +#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex) \ + /* If this item is not referenced we dont have to do much work \ + at all but we should still return a node so that \ + field items below this node ( think proto_item_add_subtree() )\ + will still have somewhere to attach to \ + or else filtering will not work (they would be ignored since tree\ + would be NULL). \ + DONT try to fake a node where PITEM_FINFO(pi) is NULL \ + since dissectors that want to do proto_item_set_len() ot \ + other operations that dereference this would crash. \ + We dont fake FT_PROTOCOL either since these are cheap and \ + some stuff (proto hier stat) assumes they always exist. \ + */ \ + if(!(PTREE_DATA(tree)->visible)){ \ + if(PITEM_FINFO(tree)){ \ + register header_field_info *hfinfo; \ + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); \ + if((hfinfo->ref_count == 0) \ + && (hfinfo->type!=FT_PROTOCOL)){ \ + /* just return tree back to the caller */\ + return tree; \ + } \ + } \ + } +#else +#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex) ; +#endif + static gboolean proto_tree_free_node(proto_node *node, gpointer data); @@ -187,6 +216,10 @@ static SLAB_FREE_LIST_DEFINE(item_label_t) SLAB_FREE(il, item_label_t) +#define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \ + DISSECTOR_ASSERT((guint)hfindex < gpa_hfinfo.len); \ + hfinfo=gpa_hfinfo.hfi[hfindex]; + /* List which stores protocols and fields that have been registered */ typedef struct _gpa_hfinfo_t { @@ -426,6 +459,23 @@ static void free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_) { GPtrArray *ptrs = value; + gint hfid = (gint)key; + header_field_info *hfinfo; + + + PROTO_REGISTRAR_GET_NTH(hfid, hfinfo); + if(hfinfo->ref_count){ + /* when a field is referenced by a filter this also + affects the refcount for the parent protocol so we need + to adjust the refcount for the parent as well + */ + if( (hfinfo->parent != -1) && (hfinfo->ref_count) ){ + header_field_info *parent_hfinfo; + PROTO_REGISTRAR_GET_NTH(hfinfo->parent, parent_hfinfo); + parent_hfinfo->ref_count -= hfinfo->ref_count; + } + hfinfo->ref_count = 0; + } g_ptr_array_free(ptrs, TRUE); } @@ -483,9 +533,32 @@ proto_tree_set_visible(proto_tree *tree, gboolean visible) PTREE_DATA(tree)->visible = visible; } -#define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \ - DISSECTOR_ASSERT((guint)hfindex < gpa_hfinfo.len); \ - hfinfo=gpa_hfinfo.hfi[hfindex]; +/* Assume dissector set only its protocol fields. + This function is called by dissectors and allowes to speed up filtering + in ethereal, if this function returns FALSE it is safe to reset tree to NULL + and thus skip calling most of the expensive proto_tree_add_...() + functions. + If the tree is visible we implicitely assume the field is referenced. +*/ +gboolean +proto_field_is_referenced(proto_tree *tree, int proto_id) +{ + register header_field_info *hfinfo; + + + if (!tree) + return FALSE; + + if (PTREE_DATA(tree)->visible) + return TRUE; + + PROTO_REGISTRAR_GET_NTH(proto_id, hfinfo); + if (hfinfo->ref_count != 0) + return TRUE; + + return FALSE; +} + /* Finds a record in the hf_info_records array by id. */ header_field_info* @@ -667,6 +740,8 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, if (!tree) return(NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + new_fi = alloc_field_info(tree, hfindex, tvb, start, &length); if (new_fi == NULL) @@ -891,10 +966,12 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, /* 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); + if (new_fi->hfinfo->ref_count) { + 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; @@ -992,6 +1069,8 @@ proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_BYTES); @@ -1065,6 +1144,8 @@ proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_ABSOLUTE_TIME || hfinfo->type == FT_RELATIVE_TIME); @@ -1127,6 +1208,8 @@ proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_IPXNET); @@ -1188,6 +1271,8 @@ proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_IPv4); @@ -1249,6 +1334,8 @@ proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_IPv6); @@ -1334,6 +1421,8 @@ proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ); @@ -1436,6 +1525,8 @@ proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_ETHER); @@ -1503,6 +1594,8 @@ proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_BOOLEAN); @@ -1564,6 +1657,8 @@ proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_FLOAT); @@ -1625,6 +1720,8 @@ proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_DOUBLE); @@ -1686,6 +1783,8 @@ proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); switch(hfinfo->type) { case FT_UINT8: @@ -1772,6 +1871,8 @@ proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_UINT64); @@ -1811,6 +1912,8 @@ proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gin if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); switch(hfinfo->type) { case FT_INT8: @@ -1896,6 +1999,8 @@ proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g if (!tree) return (NULL); + TRY_TO_FAKE_THIS_ITEM(tree, hfindex); + PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo); DISSECTOR_ASSERT(hfinfo->type == FT_INT64); @@ -1988,10 +2093,12 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, /* 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); + if (fi->hfinfo->ref_count) { + 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? */ @@ -2299,10 +2406,26 @@ proto_tree_create_root(void) void proto_tree_prime_hfid(proto_tree *tree, gint hfid) { + header_field_info *hfinfo; + g_hash_table_insert(PTREE_DATA(tree)->interesting_hfids, GINT_TO_POINTER(hfid), g_ptr_array_new()); -} + PROTO_REGISTRAR_GET_NTH(hfid, hfinfo); + /* this field is referenced by a filter so increase the refcount. + also increase the refcount for the parent, i.e the protocol. + */ + hfinfo->ref_count++; + /* only increase the refcount if there is a parent. + if this is a protocol and not a field then parent will be -1 + and there is no parent to add any refcounting for. + */ + if (hfinfo->parent != -1) { + header_field_info *parent_hfinfo; + PROTO_REGISTRAR_GET_NTH(hfinfo->parent, parent_hfinfo); + parent_hfinfo->ref_count++; + } +} proto_tree* proto_item_add_subtree(proto_item *pi, gint idx) { @@ -2314,6 +2437,7 @@ proto_item_add_subtree(proto_item *pi, gint idx) { fi = PITEM_FINFO(pi); DISSECTOR_ASSERT(idx >= 0 && idx < num_tree_types); fi->tree_type = idx; + return (proto_tree*) pi; } @@ -2331,14 +2455,16 @@ proto_item_get_subtree(proto_item *pi) { proto_item* proto_item_get_parent(proto_item *ti) { - if (!ti) + /* dont bother if tree is not visible */ + if( (!ti) || (!(PTREE_DATA(ti)->visible)) ) return (NULL); return ti->parent; } proto_item* proto_item_get_parent_nth(proto_item *ti, int gen) { - if (!ti) + /* dont bother if tree is not visible */ + if( (!ti) || (!(PTREE_DATA(ti)->visible)) ) return (NULL); while (gen--) { ti = ti->parent; @@ -2351,7 +2477,8 @@ proto_item_get_parent_nth(proto_item *ti, int gen) { proto_item* proto_tree_get_parent(proto_tree *tree) { - if (!tree) + /* dont bother if tree is not visible */ + if( (!tree) || (!(PTREE_DATA(tree)->visible)) ) return (NULL); return (proto_item*) tree; } @@ -2445,6 +2572,7 @@ proto_register_protocol(char *name, char *short_name, char *filter_name) hfinfo->strings = protocol; hfinfo->bitmask = 0; hfinfo->bitshift = 0; + hfinfo->ref_count = 0; hfinfo->blurb = ""; hfinfo->parent = -1; /* this field differentiates protos and fields */ |