Routines called by "g_node_traverse()" are supposed to return TRUE if
[obnox/wireshark/wip.git] / proto_hier_stats.c
1 /* proto_hier_stats.c
2  * Routines for calculating statistics based on protocol.
3  *
4  * $Id: proto_hier_stats.c,v 1.2 2001/03/23 21:55:36 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "globals.h"
32 #include "proto_hier_stats.h"
33 #include <wtap.h>
34
35 #include <stdio.h>
36 #include <glib.h>
37
38 static GNode*
39 find_stat_node(GNode *parent_node, header_field_info *needle_hfinfo)
40 {
41         GNode                   *needle_node;
42         field_info              *finfo;
43         ph_stats_node_t *stats;
44
45         needle_node = g_node_first_child(parent_node);
46
47         while (needle_node) {
48                 finfo = needle_node->data;
49                 if (finfo && finfo->hfinfo && finfo->hfinfo->id == needle_hfinfo->id) {
50                         return needle_node;
51                 }
52                 needle_node = g_node_next_sibling(needle_node);
53         }
54
55         /* None found. Create one. */
56         stats = g_new(ph_stats_node_t, 1);
57
58         /* Intialize counters */
59         stats->hfinfo = needle_hfinfo;
60         stats->num_pkts_total = 0;
61         stats->num_pkts_last = 0;
62         stats->num_bytes_total = 0;
63         stats->num_bytes_last = 0;
64
65         needle_node = g_node_new(stats);
66         g_node_append(parent_node, needle_node);
67         return needle_node;
68 }
69
70
71 static void
72 process_node(proto_item *proto_node, GNode *parent_stat_node, ph_stats_t *ps, guint pkt_len)
73 {
74         field_info              *finfo;
75         ph_stats_node_t *stats;
76         proto_item              *proto_sibling_node;
77         GNode                   *stat_node;
78
79         finfo = proto_node->data;
80         g_assert(finfo);
81
82         stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
83         
84         /* Assert that the finfo is related to a protocol, not a field. */
85         g_assert(finfo->hfinfo->parent == -1);
86
87         stats = stat_node->data;
88         stats->num_pkts_total++;
89         stats->num_bytes_total += pkt_len;
90
91         proto_sibling_node = g_node_next_sibling(proto_node);
92
93         if (proto_sibling_node) {
94                 process_node(proto_sibling_node, stat_node, ps, pkt_len);
95         }
96         else {
97                 stats->num_pkts_last++;
98                 stats->num_bytes_last += pkt_len;
99         }
100 }
101
102
103
104 static void
105 process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
106 {
107         proto_item      *proto_node;
108
109         proto_node = g_node_first_child(protocol_tree);
110         if (!proto_node) {
111                 return;
112         }
113
114         process_node(proto_node, ps->stats_tree, ps, pkt_len);
115 }
116
117 static void
118 process_frame(frame_data *frame, ph_stats_t* ps)
119 {
120         epan_dissect_t                  *edt;
121         union wtap_pseudo_header        phdr;
122         proto_tree                      *protocol_tree;
123         guint8                          pd[WTAP_MAX_PACKET_SIZE];
124
125         protocol_tree = proto_tree_create_root();
126
127         /* Load the frame from the capture file */
128         wtap_seek_read(cfile.wth, frame->file_off, &phdr,
129                         pd, frame->cap_len);
130
131         /* Dissect the frame */
132         edt = epan_dissect_new(&phdr, pd, frame, protocol_tree);
133
134         /* Get stats from this protocol tree */
135         process_tree(protocol_tree, ps, frame->pkt_len);
136
137         /* Free our memory. */
138         epan_dissect_free(edt);
139         proto_tree_free(protocol_tree);
140 }
141
142
143
144 ph_stats_t*
145 ph_stats_new(void)
146 {
147         ph_stats_t      *ps;
148         frame_data      *frame;
149         guint           tot_packets, tot_bytes;
150
151         /* Initialize the data */
152         ps = g_new(ph_stats_t, 1);
153         ps->tot_packets = 0;
154         ps->tot_bytes = 0;
155         ps->stats_tree = g_node_new(NULL);
156
157         frame = cfile.plist;
158         tot_packets = 0;
159         tot_bytes = 0;
160
161         while (frame) {
162                 /* Skip frames that are hidden due to the display filter */
163                 if (!frame->flags.passed_dfilter) {
164                         continue;
165                 }
166
167                 process_frame(frame, ps);
168
169                 tot_packets++;
170                 tot_bytes += frame->pkt_len;
171
172                 frame = frame->next;
173         }
174
175         ps->tot_packets = tot_packets;
176         ps->tot_bytes = tot_bytes;
177
178         return ps;
179 }
180
181 static gboolean
182 stat_node_free(GNode *node, gpointer data)
183 {
184         ph_stats_node_t *stats = node->data;
185
186         if (stats) {
187                 g_free(stats);
188         }
189         return FALSE;
190 }
191
192 void
193 ph_stats_free(ph_stats_t *ps)
194 {
195
196         if (ps->stats_tree) {
197                 g_node_traverse(ps->stats_tree, G_IN_ORDER,
198                                 G_TRAVERSE_ALL, -1,
199                                 stat_node_free, NULL);
200                 g_node_destroy(ps->stats_tree);
201         }
202
203         g_free(ps);
204 }