aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/stats_tree.c532
-rw-r--r--epan/stats_tree.h131
-rw-r--r--epan/stats_tree_priv.h179
-rw-r--r--gtk/stats_tree_stat.c327
-rw-r--r--tap-stats_tree.c118
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);
+}