diff options
-rw-r--r-- | epan/stats_tree.c | 532 | ||||
-rw-r--r-- | epan/stats_tree.h | 131 | ||||
-rw-r--r-- | epan/stats_tree_priv.h | 179 | ||||
-rw-r--r-- | gtk/stats_tree_stat.c | 327 | ||||
-rw-r--r-- | tap-stats_tree.c | 118 |
5 files changed, 1287 insertions, 0 deletions
diff --git a/epan/stats_tree.c b/epan/stats_tree.c new file mode 100644 index 0000000000..3efd11f29f --- /dev/null +++ b/epan/stats_tree.c @@ -0,0 +1,532 @@ +/* stats_tree.c + * API for a counter tree for ethereal + * 2004, Luis E. G. Ontanon + * + * $Id: $ + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <epan/stats_tree_priv.h> + +/* used to contain the registered stat trees */ +static GHashTable* registry = NULL; + +/* writes into the buffers pointed by value, rate and percent + the string representations of a node*/ +extern void get_strings_from_node(const stat_node* node, guint8* value, guint8* rate, guint8* percent) { + float f; + + if (value) g_snprintf(value,NUM_BUF_SIZE,"%u",node->counter); + + if (rate) { + *rate = '\0'; + if (node->st->elapsed > 0.0) { + f = ((float)node->counter) / node->st->elapsed; + g_snprintf(rate,NUM_BUF_SIZE,"%f",f); + } + } + + if (percent) { + *percent = '\0'; + if (node->parent->counter > 0) { + f = ((float)node->counter * 100.0) / node->parent->counter; + g_snprintf(percent,NUM_BUF_SIZE,"%.2f%%",f); + } + } +} + + +/* a text representation of a node +if buffer is NULL returns a newly allocated string */ +extern guint8* stat_node_to_str(const stat_node* node, + guint8* buffer, guint len) { + if (buffer) { + g_snprintf(buffer,len,"%s: %i",node->name, node->counter); + return buffer; + } else { + return g_strdup_printf("%s: %i",node->name, node->counter); + } +} + +/* populates the given GString with a tree representation of a branch given by node, +using indent spaces as initial indentation */ +extern void stat_branch_to_str(const stat_node* node, GString* s, guint indent) { + stat_node* child; + static gchar indentation[INDENT_MAX]; + static gchar value[NUM_BUF_SIZE]; + static gchar rate[NUM_BUF_SIZE]; + static gchar percent[NUM_BUF_SIZE]; + guint i; + + get_strings_from_node(node, value, rate, percent); + + indent = indent > INDENT_MAX ? INDENT_MAX : indent; + + /* fill indentation with indent spaces */ + for ( i = 0 ; i<(indent-1); i++) indentation[i] = ' '; + indentation[i] = '\0'; + + g_string_sprintfa(s,"%s%s = %s (%s/s) (%s)\n", + indentation,node->name,value,rate,percent); + + if (node->children) { + for (child = node->children; child; child = child->next ) { + stat_branch_to_str(child,s,indent+1); + } + } +} + +/* frees the resources allocated by a stat_tree node */ +static void free_stat_node( stat_node* node ) { + stat_node* child; + + if (node->children) { + for (child = node->children; child; child = child->next ) + free_stat_node(child); + } + + if(node->st->free_node_pr) node->st->free_node_pr(node); + + if (node->hash) g_hash_table_destroy(node->hash); + if (node->rng) g_free(node->rng); + + if (node->name) g_free(node->name); + + g_free(node); +} + +/* destroys the whole tree */ +extern void free_stats_tree(stats_tree* st) { + stat_node* child; + + g_free(st->abbr); + g_free(st->filter); + + for (child = st->root.children; child; child = child->next ) + free_stat_node(child); + + if (st->free_tree_pr) + st->free_tree_pr(st); + + g_free(st); +} + + +/* reset a node to its original state */ +static void reset_stat_node(stat_node* node) { + stat_node* child; + + if (node->children) { + for (child = node->children; child; child = child->next ) + reset_stat_node(child); + } + + node->counter = 0; + + if(node->st->reset_node) { + node->st->reset_node(node); + } + +} + +/* reset the whole stats_tree */ +extern void reset_stats_tree(void *psp ) { + stats_tree *st=psp; + + if (st) { + reset_stat_node(&st->root); + } + + if (st->reset_tree) { + st->reset_tree(st); + } +} + +/* register a new stats_tree */ +extern void register_stats_tree(guint8* abbr, + guint8* name, + stat_tree_packet_cb packet, + stat_tree_init_cb init ) { + + stats_tree* st = g_malloc( sizeof(stats_tree) ); + + /* at the very least the abbrev and the packet function should be given */ + g_assert( abbr && packet ); + + st->abbr = g_strdup(abbr); + st->name = name ? g_strdup(name) : g_strdup(abbr); + st->filter = NULL; + + st->root.counter = 0; + st->root.name = STAT_TREE_ROOT; + st->root.st = st; + st->root.parent = NULL; + st->root.children = NULL; + st->root.next = NULL; + st->root.hash = NULL; + st->root.pr = NULL; + + st->names = g_hash_table_new(g_str_hash,g_str_equal); + st->parents = g_ptr_array_new(); + + g_ptr_array_add(st->parents,&st->root); + + st->start = -1.0; + st->elapsed = 0.0; + + st->packet = packet; + st->init = init; + + /* these have to be filled in by implementations */ + st->setup_node_pr = NULL; + st->new_tree_pr = NULL; + st->free_node_pr = NULL; + st->free_tree_pr = NULL; + st->draw_node = NULL; + st->draw_tree = NULL; + st->reset_node = NULL; + st->reset_tree = NULL; + + if (!registry) registry = g_hash_table_new(g_str_hash,g_str_equal); + + g_hash_table_insert(registry,st->abbr,st); + +} + +/* will be the tap packet cb */ +extern int stats_tree_packet(void* p, packet_info* pinfo, epan_dissect_t *edt, const void *pri) { + stats_tree* st = p; + + float now = (((float)pinfo->fd->rel_secs) + (((float)pinfo->fd->rel_usecs)/1000000) ); + + if (st->start < 0.0) st->start = now; + + st->elapsed = now - st->start; + + if (st->packet) + return st->packet(st,pinfo,edt,pri); + else + return 0; +} + +extern GHashTable* stat_tree_registry(void) { + return registry; +} + +extern stats_tree* get_stats_tree_by_abbr(guint8* abbr) { + return g_hash_table_lookup(registry,abbr); +} + + +struct _stats_tree_pres_stuff { + void (*setup_node_pr)(stat_node*); + void (*free_node_pr)(stat_node*); + void (*draw_node)(stat_node*); + void (*reset_node)(stat_node*); + tree_pres* (*new_tree_pr)(stats_tree*); + void (*free_tree_pr)(stats_tree*); + void (*draw_tree)(stats_tree*); + void (*reset_tree)(stats_tree*); +}; + +static void setup_tree_presentation(gpointer k _U_, gpointer v, gpointer p) { + stats_tree* st = v; + struct _stats_tree_pres_stuff *d = p; + + st->setup_node_pr = d->setup_node_pr; + st->new_tree_pr = d->new_tree_pr; + st->free_node_pr = d->free_node_pr; + st->free_tree_pr = d->free_tree_pr; + st->draw_node = d->draw_node; + st->draw_tree = d->draw_tree; + st->reset_node = d->reset_node; + st->reset_tree = d->reset_tree; + +} + +extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), + void (*setup_node_pr)(stat_node*), + void (*free_node_pr)(stat_node*), + void (*draw_node)(stat_node*), + void (*reset_node)(stat_node*), + tree_pres* (*new_tree_pr)(stats_tree*), + void (*free_tree_pr)(stats_tree*), + void (*draw_tree)(stats_tree*), + void (*reset_tree)(stats_tree*), + void* data) { + struct _stats_tree_pres_stuff d = {setup_node_pr,free_node_pr,draw_node,reset_node,new_tree_pr,free_tree_pr,draw_tree,reset_tree}; + + if (registry) g_hash_table_foreach(registry,setup_tree_presentation,&d); + + if (registry_iterator && registry) + g_hash_table_foreach(registry,registry_iterator,data); + +} + + +/* creates a stat_tree node +* name: the name of the stats_tree node +* parent_name: the name of the ALREADY REGISTERED parent +* with_hash: whether or not it should keep a hash with it's children names +* as_named_node: whether or not it has to be registered in the root namespace +*/ +static stat_node* new_stat_node(stats_tree* st, + const gchar* name, + int parent_id, + gboolean with_hash, + gboolean as_parent_node) { + + stat_node *node = g_malloc (sizeof(stat_node)); + stat_node* last_chld = NULL; + + node->counter = 0; + node->name = g_strdup(name); + node->children = NULL; + node->next = NULL; + node->st = (stats_tree*) st; + node->hash = with_hash ? g_hash_table_new(g_str_hash,g_str_equal) : NULL; + node->parent = NULL; + + if (as_parent_node) { + g_hash_table_insert(st->names, + node->name, + node); + + g_ptr_array_add(st->parents,node); + + node->id = st->parents->len - 1; + } else { + node->id = -1; + } + + if (parent_id >= 0 && parent_id < (int) st->parents->len ) { + node->parent = g_ptr_array_index(st->parents,parent_id); + } else { + /* ??? should we set the parent to be root ??? */ + g_assert_not_reached(); + } + + if (node->parent->children) { + /* insert as last child */ + + for (last_chld = node->parent->children; + last_chld->next; + last_chld = last_chld->next ) ; + + last_chld->next = node; + + } else { + /* insert as first child */ + node->parent->children = node; + } + + if(node->parent->hash) { + g_hash_table_insert(node->parent->hash,node->name,node); + } + + if (st->setup_node_pr) { + st->setup_node_pr(node); + } else { + node->pr = NULL; + } + + return node; +} + + +extern int create_node(stats_tree* st, const gchar* name, int parent_id, gboolean with_hash) { + stat_node* node = new_stat_node(st,name,parent_id,with_hash,TRUE); + + if (node) + return node->id; + else + return 0; +} + +/* XXX: should this be a macro? */ +extern int create_node_with_parent_name(stats_tree* st, + const gchar* name, + const gchar* parent_name, + gboolean with_children) { + return create_node(st,name,get_parent_id_by_name(st,parent_name),with_children); +} + + + +/* + * Increases by delta the counter of the node whose name is given + * if the node does not exist yet it's created (with counter=1) + * using parent_name as parent node. + * with_hash=TRUE to indicate that the created node will have a parent + */ +extern guint8* manip_stat_node(manip_node_mode mode, stats_tree* st, const guint8* name, int parent_id, gboolean with_hash, gint value) { + stat_node* node = NULL; + stat_node* parent = NULL; + + if (parent_id >= 0 && parent_id < (int) st->parents->len ) { + parent = g_ptr_array_index(st->parents,parent_id); + } else { + g_assert_not_reached(); + } + + if( parent->hash ) { + node = g_hash_table_lookup(parent->hash,name); + } else { + node = g_hash_table_lookup(st->names,name); + } + + if ( node == NULL ) + node = new_stat_node(st,name,parent_id,with_hash,with_hash); + + switch (mode) { + case MN_INCREASE: node->counter += value; break; + case MN_SET: node->counter = value; break; + } + + if (node) + return node->name; + else + return NULL; +} + + +extern guint8* get_st_abbr(const guint8* optarg) { + guint i; + + for (i=0; optarg[i] && optarg[i] != ','; i++); + + if (optarg[i] == ',') { + return g_strndup(optarg,i); + } else { + return NULL; + } +} + + +static range_pair_t* get_range(guint8* rngstr) { + gchar** split; + range_pair_t* rng = g_malloc(sizeof(range_pair_t)); + + split = g_strsplit(rngstr,"-",2); + + rng->floor = strtol(split[0],NULL,10); + rng->ceil = strtol(split[1],NULL,10); + + if (rng->ceil == 0) rng->ceil = G_MAXINT; + if (rng->floor == 0) rng->floor = G_MININT; + + g_strfreev(split); + + return rng; +} + + +extern int create_range_node(stats_tree* st, + const gchar* name, + int parent_id, + ...) { + va_list list; + guint8* curr_range; + stat_node* rng_root = new_stat_node(st, name, parent_id, FALSE, TRUE); + stat_node* range_node = NULL; + + va_start( list, parent_id ); + while (( curr_range = va_arg(list, guint8*) )) { + range_node = new_stat_node(st, curr_range, rng_root->id, FALSE, FALSE); + range_node->rng = get_range(curr_range); + } + va_end( list ); + + return rng_root->id; +} + +extern int get_parent_id_by_name(stats_tree* st, const gchar* parent_name) { + stat_node* node = g_hash_table_lookup(st->names,parent_name); + + if (node) + return node->id; + else + return 0; /* ??? -1 ??? */ +} + + +extern int create_range_node_with_parent_name(stats_tree* st, + const gchar* name, + const gchar* parent_name, + ...) { + va_list list; + guint8* curr_range; + stat_node* range_node = NULL; + int parent_id = get_parent_id_by_name(st,parent_name); + stat_node* rng_root = new_stat_node(st, name, parent_id, FALSE, TRUE); + + va_start( list, parent_name ); + while (( curr_range = va_arg(list, guint8*) )) { + range_node = new_stat_node(st, curr_range, rng_root->id, FALSE, FALSE); + range_node->rng = get_range(curr_range); + } + va_end( list ); + + return rng_root->id; +} + + +extern int tick_range(stats_tree* st, + const gchar* name, + int parent_id, + int value_in_range) { + + stat_node* node = NULL; + stat_node* parent = NULL; + stat_node* child = NULL; + gint floor, ceil; + + if (parent_id >= 0 && parent_id < (int) st->parents->len) { + parent = g_ptr_array_index(st->parents,parent_id); + } else { + g_assert_not_reached(); + } + + if( parent->hash ) { + node = g_hash_table_lookup(parent->hash,name); + } else { + node = g_hash_table_lookup(st->names,name); + } + + if ( node == NULL ) + return node->id; + + for ( child = node->children; child; child = child->next) { + floor = child->rng->floor; + ceil = child->rng->ceil; + + if ( value_in_range >= floor && value_in_range <= ceil ) { + child->counter++; + return node->id; + } + } + + return node->id; +} diff --git a/epan/stats_tree.h b/epan/stats_tree.h new file mode 100644 index 0000000000..16a1333d46 --- /dev/null +++ b/epan/stats_tree.h @@ -0,0 +1,131 @@ +/* stats_tree.h + * A counter tree API for ethereal dissectors + * 2005, Luis E. G. Ontanon + * + * $Id: $ + * + * 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 __STATS_TREE_H +#define __STATS_TREE_H + +#include <glib.h> +#include <epan/epan.h> +#include <epan/packet_info.h> +#include <epan/to_str.h> +#include <epan/tap.h> +#include "../register.h" + +#define STAT_TREE_ROOT "root" + +/* obscure information regarding the stats_tree */ +typedef struct _stats_tree stats_tree; + +/* tap packet callback for stats_tree */ +typedef int (*stat_tree_packet_cb)(stats_tree*, + packet_info*, + epan_dissect_t*, + const void *); + +/* stats_tree initilaization callback */ +typedef void (*stat_tree_init_cb)(stats_tree*); + +/* registers a new stats tree + * abbr: protocol abbr + * name: protocol name + * packet: per packet callback + * init: tree initialization callback + */ +extern void register_stats_tree(guint8* abbr, + guint8* name, + stat_tree_packet_cb packet, + stat_tree_init_cb init ); + +extern int get_parent_id_by_name(stats_tree* st, const gchar* parent_name); + +/* Creates a node in the tree (to be used in the in init_cb) +* st: the stats_tree in which to create it +* name: the name of the new node +* parent_name: the name of the parent_node (NULL for root) +* with_children: TRUE if this node will have "dynamically created" children +*/ +extern int create_node(stats_tree* st, + const gchar* name, + int parent_id, + gboolean with_children); + +extern int create_node_with_parent_name(stats_tree* st, + const gchar* name, + const gchar* parent_name, + gboolean with_children); + +/* creates a node in the tree, that will contain a ranges list. + example: + create_range_node(st,name,parent, + "-99","100-199","200-299","300-399","400-", NULL); +*/ +extern int create_range_node(stats_tree* st, + const gchar* name, + int parent_id, + ...); + +extern int create_range_node_with_parent_name(stats_tree* st, + const gchar* name, + const gchar* parent_name, + ...); +/* */ + +extern int tick_range(stats_tree* st, + const gchar* name, + int parent_id, + int value_in_range); + +extern int tick_range_with_parent_name(stats_tree* st, + const gchar* name, + const gchar* parent_name, + int value_in_range); + + +/* + * manipulates the value of the node whose name is given + * if the node does not exist yet it's created (with counter=1) + * using parent_name as parent node (NULL for root). + * with_children=TRUE to indicate that the created node will be a parent + */ +typedef enum _manip_node_mode { MN_INCREASE, MN_SET } manip_node_mode; +extern guint8* manip_stat_node(manip_node_mode mode, + stats_tree* st, + const guint8* name, + int parent_id, + gboolean with_children, + gint value); + +#define increase_stat_node(st,name,parent_id,with_children,value) \ +(manip_stat_node(MN_INCREASE,(st),(name),(parent_id),(with_children),(value))) + +#define tick_stat_node(st,name,parent_id,with_children) \ +(manip_stat_node(MN_INCREASE,(st),(name),(parent_id),(with_children),1)) + +#define set_stat_node(st,name,parent_id,with_children,value) \ +(manip_stat_node(MN_SET,(st),(name),(parent_id),(with_children),value)) + +#define zero_stat_node(st,name,parent_id,with_children) \ +(manip_stat_node(MN_SET,(st),(name),(parent_id),(with_children),0)) + +#endif /* __STATS_TREE_H */ diff --git a/epan/stats_tree_priv.h b/epan/stats_tree_priv.h new file mode 100644 index 0000000000..893269c017 --- /dev/null +++ b/epan/stats_tree_priv.h @@ -0,0 +1,179 @@ +/* stats_tree_priv.h + * implementor's API for stats_tree + * 2005, Luis E. G. Ontanon + * + * $Id: $ + * + * 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 __STATS_TREE_PRIV_H +#define __STATS_TREE_PRIV_H + +#include "stats_tree.h" + +#define INDENT_MAX 32 +#define NUM_BUF_SIZE 32 + +/* implementations should define this to contain its own node related data + * as well as some operations on it */ +typedef struct _st_node_pres st_node_pres; + +/* implementations should define this to contain its own tree related data +* as well as some operations on it */ +typedef struct _tree_pres tree_pres; + +typedef struct _stat_node stat_node; + + +typedef struct _range_pair { + gint floor; + gint ceil; +} range_pair_t; + +struct _stat_node { + gchar* name; + int id; + + /* the counter it keeps */ + gint counter; + + /* children nodes by name */ + GHashTable* hash; + + /* the owner of this node */ + stats_tree* st; + + /* relatives */ + stat_node* parent; + stat_node* children; + stat_node* next; + + /* used to check if value is within range */ + range_pair_t* rng; + + /* node presentation data */ + st_node_pres* pr; +} ; + +struct _stats_tree { + guint8* abbr; + guint8* name; + + /* is this realy needed? */ + char* filter; + + /* times */ + float start; + float elapsed; + + + /* used to lookup named parents: + * key: parent node name + * value: parent node + */ + GHashTable* names; + + /* used for quicker lookups of parent nodes */ + GPtrArray* parents; + + /* every tree in nature has one */ + stat_node root; + + /* dissector defined callbacks */ + stat_tree_packet_cb packet; + stat_tree_init_cb init; + + /**** tree representation + * to be defined (if needed) by the implementations + */ + tree_pres* pr; + + /* node presentation callbacks + */ + + /* last to be called at node creation */ + void (*setup_node_pr)(stat_node*); + + /* last to be called at node destruction */ + void (*free_node_pr)(stat_node*); + + /* to be called for every node in the tree */ + void (*draw_node)(stat_node*); + void (*reset_node)(stat_node*); + + /* tree presentation callbacks */ + + tree_pres* (*new_tree_pr)(stats_tree*); + void (*free_tree_pr)(stats_tree*); + void (*draw_tree)(stats_tree*); + void (*reset_tree)(stats_tree*); +}; + +/* guess what, this is it! */ +extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), + void (*setup_node_pr)(stat_node*), + void (*free_node_pr)(stat_node*), + void (*draw_node)(stat_node*), + void (*reset_node)(stat_node*), + tree_pres* (*new_tree_pr)(stats_tree*), + void (*free_tree_pr)(stats_tree*), + void (*draw_tree)(stats_tree*), + void (*reset_tree)(stats_tree*), + void* data); + +/* callback for taps */ +extern int stats_tree_packet(void*, packet_info*, epan_dissect_t*, const void *); + +/* callback for reset */ +extern void reset_stats_tree(void*); + +/* callback for destoy */ +extern void free_stats_tree(stats_tree* st); + +/* given an optarg splits the abbr part + and returns a newly allocated buffer containing it */ +extern guint8* get_st_abbr(const guint8* optarg); + +/* obtains a stats tree from the registry given its abbr */ +extern stats_tree* get_stats_tree_by_abbr(guint8* abbr); + +/* extracts node data as strings from a stat_node into + the buffers given by value, rate and precent + if NULL they are ignored */ +extern void get_strings_from_node(const stat_node* node, + guint8* value, + guint8* rate, + guint8* percent); + +/* populates the given GString with a tree representation of a branch given by node, + using indent spaces as indentation */ +extern void stat_branch_to_str(const stat_node* node, + GString* s, + guint indent); + +/* a text representation of a node, + if buffer is NULL returns a newly allocated string */ +extern guint8* stat_node_to_str(const stat_node* node, + guint8* buffer, guint len); + +/* destroys the stats_tree */ +extern void free_stats_tree(stats_tree* st); + +#endif /* __STATS_TREE_PRIV_H */ diff --git a/gtk/stats_tree_stat.c b/gtk/stats_tree_stat.c new file mode 100644 index 0000000000..2cedd67239 --- /dev/null +++ b/gtk/stats_tree_stat.c @@ -0,0 +1,327 @@ +/* stats_tree_stat.c + * GTK Tap implementation of stats_tree + * 2005, Luis E. G. Ontanon + * + * $Id: $ + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <gtk/gtk.h> + +#include <epan/stats_tree_priv.h> + +#include "simple_dialog.h" +#include "globals.h" +#include "tap_menu.h" +#include "ui_util.h" +#include "dlg_utils.h" +#include "compat_macros.h" +#include "tap_dfilter_dlg.h" +#include "../tap_dfilter_dlg.h" + +struct _st_node_pres { +#if GTK_MAJOR_VERSION >= 2 + GtkTreeIter* iter; +#else + /* g_malloc(0) ??? */ + void* dummy; +#endif +}; + + +struct _tree_pres { + tap_dfilter_dlg* stat_dlg; + GString* text; + GtkWidget* win; + +#if GTK_MAJOR_VERSION >= 2 + GtkTreeStore* store; + GtkWidget* tree; +#else + GtkText* textbox; +#endif +}; + +/* the columns of the tree pane */ +enum _stat_tree_columns { + COUNT_COLUMN, + RATE_COLUMN, + TITLE_COLUMN, + PERCENT_COLUMN, + N_COLUMNS +}; + +/* used for converting numbers */ +#define NUM_BUF_SIZE 32 + +/* creates the gtk representation for a stat_node + * node: the node + */ +static void setup_gtk_node_pr(stat_node* node) { + node->pr = g_malloc(sizeof(st_node_pres)); + + +#if GTK_MAJOR_VERSION >= 2 + GtkTreeIter* parent = NULL; + + if ( node->parent && node->parent->pr ) + parent = node->parent->pr->iter; + + node->pr->iter = g_malloc(sizeof(GtkTreeIter)); + + if (node->st->pr->store) { + gtk_tree_store_append (node->st->pr->store, node->pr->iter, parent); + gtk_tree_store_set(node->st->pr->store, node->pr->iter, TITLE_COLUMN, node->name, RATE_COLUMN, "", COUNT_COLUMN, "", -1); + } +#else + node->pr->dummy = NULL; +#endif +} + + +#if GTK_MAJOR_VERSION >= 2 +static void draw_gtk_node(stat_node* node) { + static gchar value[NUM_BUF_SIZE]; + static gchar rate[NUM_BUF_SIZE]; + static gchar percent[NUM_BUF_SIZE]; + stat_node* child; + + get_strings_from_node(node, value, rate, percent); + + if (node->st->pr->store) + gtk_tree_store_set(node->st->pr->store, node->pr->iter, + RATE_COLUMN, rate, + COUNT_COLUMN, value, + PERCENT_COLUMN, percent, + -1); + + if (node->children) { + for (child = node->children; child; child = child->next ) + draw_gtk_node(child); + } +} +#endif + +static void draw_gtk_tree( void *psp ) { + stats_tree *st = psp; + stat_node* child; + +#if GTK_MAJOR_VERSION >= 2 + for (child = st->root.children; child; child = child->next ) + draw_gtk_node(child); + + gtk_tree_view_set_model(GTK_TREE_VIEW(st->pr->tree),GTK_TREE_MODEL(st->pr->store)); +#else + GString* text = g_string_new(""); + + for (child = st->root.children; child; child = child->next ) { + stat_node_to_str(child,text,0); + } + + gtk_text_freeze(st->textbox); + gtk_text_set_point(st->textbox,0); + gtk_text_forward_delete(st->textbox,gtk_text_get_length(st->textbox)); + gtk_text_insert(st->textbox,NULL,st->textbox->style->black,NULL,text->str,-1); + gtk_text_thaw(st->textbox); + + g_string_free(text,TRUE); +#endif +} + +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); + +static void free_gtk_tree(GtkWindow *win _U_, stats_tree *st) +{ + + protect_thread_critical_region(); + remove_tap_listener(st); + unprotect_thread_critical_region(); + + free_stats_tree(st); +} + + +/* initializes the stats_tree window */ +static void init_gtk_tree(char* optarg) { + guint8* abbr = get_st_abbr(optarg); + stats_tree* st = NULL; + guint8* title = NULL; + guint8* window_name = NULL; + GString* error_string; +#if GTK_MAJOR_VERSION >= 2 + GtkTreeViewColumn* column; + GtkCellRenderer* renderer; + GtkWidget *scr_win; +#endif + + if (abbr) { + st = get_stats_tree_by_abbr(abbr); + + if (st != NULL) { + if (strncmp (optarg, st->pr->stat_dlg->init_string, strlen(st->pr->stat_dlg->init_string)) == 0){ + st->filter=((guint8*)optarg)+strlen(st->pr->stat_dlg->init_string); + } else { + st->filter=NULL; + } + } else { + g_error("no such stats_tree (%s) found in stats_tree registry",abbr); + } + } else { + g_error("could not obtain stats_tree abbr from optarg"); + } + + window_name = g_strdup_printf("%s_stat", st->abbr); + + st->pr->win = window_new_with_geom(GTK_WINDOW_TOPLEVEL,window_name,window_name); + g_free(window_name); + + if(st->filter){ + title=g_strdup_printf("%s with filter: %s",st->name,st->filter); + } else { + st->filter=NULL; + title=g_strdup_printf("%s", st->name); + } + + gtk_window_set_title(GTK_WINDOW(st->pr->win), title); + g_free(title); + +#if GTK_MAJOR_VERSION >= 2 + scr_win = scrolled_window_new(NULL, NULL); + + st->pr->store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING); + + st->pr->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (st->pr->store)); + + gtk_container_add( GTK_CONTAINER(scr_win), st->pr->tree); + gtk_container_add( GTK_CONTAINER(st->pr->win), scr_win); + + /* the columns */ + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("What", renderer, + "text", TITLE_COLUMN, + NULL); + gtk_tree_view_column_set_resizable (column,TRUE); + gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("count", renderer, + "text", COUNT_COLUMN, + NULL); + + gtk_tree_view_column_set_resizable (column,TRUE); + gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("rate", renderer, + "text", RATE_COLUMN, + NULL); + gtk_tree_view_column_set_resizable (column,TRUE); + gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("percent", renderer, + "text", PERCENT_COLUMN, + NULL); + gtk_tree_view_column_set_resizable(column,TRUE); + gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column); +#else + pr->textbox = gtk_text_new(NULL,NULL); + gtk_container_add( GTK_CONTAINER(scr_win), st->pr->textbox); + gtk_container_add( GTK_CONTAINER(st->pr->win), scr_win); +#endif + + error_string = register_tap_listener( st->abbr, + st, + st->filter, + reset_stats_tree, + stats_tree_packet, + draw_gtk_tree); + + if (error_string) { + /* error, we failed to attach to the tap. clean up */ + simple_dialog( ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str ); + /* destroy_stat_tree_window(st); */ + g_string_free(error_string, TRUE); + g_error("stats_tree for: %s failed to attach to the tap: %s",st->name,error_string->str); + } + + SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "destroy", free_gtk_tree, st); + + gtk_widget_show_all(st->pr->win); + window_present(st->pr->win); + + if (st->init) st->init(st); + + cf_retap_packets(&cfile); + +} + + +void register_gtk_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_) { + stats_tree* st = v; + guint8* s; + + s = g_strdup_printf("%s,stat",st->abbr); + + register_ethereal_tap(s, init_gtk_tree); + g_free(s); + + st->pr = g_malloc(sizeof(tree_pres)); + st->pr->text = NULL; + st->pr->win = NULL; + +#if GTK_MAJOR_VERSION >= 2 + st->pr->store = NULL; + st->pr->tree = NULL; +#else + st->pr->textbox = NULL; +#endif + + st->pr->stat_dlg = g_malloc(sizeof(tap_dfilter_dlg)); + + st->pr->stat_dlg->win_title = g_strdup_printf("%s Packet Counter",st->name); + st->pr->stat_dlg->init_string = g_strdup_printf("%s,stat",st->abbr); + st->pr->stat_dlg->tap_init_cb = init_gtk_tree; + st->pr->stat_dlg->index = -1; + + register_tap_menu_item(st->name, REGISTER_TAP_GROUP_NONE, + gtk_tap_dfilter_dlg_cb, NULL, NULL, st->pr->stat_dlg); +} + +void +register_tap_listener_stats_tree_stat(void) +{ + stats_tree_presentation(register_gtk_stats_tree_tap, + setup_gtk_node_pr, NULL, + draw_gtk_node, + NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/tap-stats_tree.c b/tap-stats_tree.c new file mode 100644 index 0000000000..8150260eb2 --- /dev/null +++ b/tap-stats_tree.c @@ -0,0 +1,118 @@ +/* tap-stats_tree.c + * tethereal's tap implememntation of stats_tree + * 2005, Luis E. G. Ontanon + * + * $Id: $ + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdio.h> +#include <glib.h> +#include <epan/stats_tree_priv.h> + +/* actually unused */ +struct _st_node_pres { + void* dummy; +}; + + +struct _tree_pres { + guint8* init_string; +}; + +static void draw_stats_tree(void *psp) { + stats_tree *st = psp; + GString* s; + stat_node* child; + + s = g_string_new("\n===================================================================\n"); + + g_string_sprintfa(s,"Statistics for %s\n===================================================================\n", + st->name); + + for (child = st->root.children; child; child = child->next ) { + stat_branch_to_str(child,s,1); + } + + s = g_string_append(s,"\n===================================================================\n"); + + printf("%s",s->str); + +} + +static void init_stats_tree(char *optarg) { + guint8* abbr = get_st_abbr(optarg); + GString *error_string; + stats_tree *st = NULL; + + if (abbr) { + st = get_stats_tree_by_abbr(abbr); + + if (st != NULL) { + if (strncmp (optarg, st->pr->init_string, strlen(st->pr->init_string)) == 0){ + st->filter=((guint8*)optarg)+strlen(st->pr->init_string); + } else { + st->filter=NULL; + } + } else { + g_error("no such stats_tree (%s) found in stats_tree registry",abbr); + } + } else { + g_error("could not obtain stats_tree abbr from optarg"); + } + + error_string = register_tap_listener( st->abbr, + st, + st->filter, + reset_stats_tree, + stats_tree_packet, + draw_stats_tree); + + if (error_string) { + g_error("stats_tree for: %s failed to attach to the tap: %s",st->name,error_string->str); + } + + if (st->init) st->init(st); + +} + +void register_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_) { + stats_tree* st = v; + + st->pr = g_malloc(sizeof(tree_pres)); + st->pr->init_string = g_strdup_printf("%s,stat",st->abbr); + + register_ethereal_tap(st->pr->init_string, init_stats_tree); + +} + + +void +register_tap_listener_stats_tree_stat(void) +{ + stats_tree_presentation(register_stats_tree_tap, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); +} |