nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* proto_hier_stats.c
2 * Routines for calculating statistics based on protocol.
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22  
23 #include "config.h"
24  
25 #include "file.h"
26 #include "frame_tvbuff.h"
27 #include "ui/proto_hier_stats.h"
28 #include "ui/progress_dlg.h"
29 #include "epan/epan_dissect.h"
30 #include "epan/proto.h"
31  
32 #include <string.h>
33  
34 /* Update the progress bar this many times when scanning the packet list. */
35 #define N_PROGBAR_UPDATES 100
36  
37 #define STAT_NODE_STATS(n) ((ph_stats_node_t*)(n)->data)
38 #define STAT_NODE_HFINFO(n) (STAT_NODE_STATS(n)->hfinfo)
39  
40 static int pc_proto_id = -1;
41  
42 static GNode*
43 find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
44 {
45 GNode *needle_stat_node, *up_parent_stat_node;
46 header_field_info *hfinfo;
47 ph_stats_node_t *stats;
48  
49 /* Look down the tree */
50 needle_stat_node = g_node_first_child(parent_stat_node);
51  
52 while (needle_stat_node) {
53 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
54 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
55 return needle_stat_node;
56 }
57 needle_stat_node = g_node_next_sibling(needle_stat_node);
58 }
59  
60 /* Look up the tree */
61 up_parent_stat_node = parent_stat_node;
62 while (up_parent_stat_node && up_parent_stat_node->parent)
63 {
64 needle_stat_node = g_node_first_child(up_parent_stat_node->parent);
65 while (needle_stat_node) {
66 hfinfo = STAT_NODE_HFINFO(needle_stat_node);
67 if (hfinfo && hfinfo->id == needle_hfinfo->id) {
68 return needle_stat_node;
69 }
70 needle_stat_node = g_node_next_sibling(needle_stat_node);
71 }
72  
73 up_parent_stat_node = up_parent_stat_node->parent;
74 }
75  
76 /* None found. Create one. */
77 stats = g_new(ph_stats_node_t, 1);
78  
79 /* Intialize counters */
80 stats->hfinfo = needle_hfinfo;
81 stats->num_pkts_total = 0;
82 stats->num_pkts_last = 0;
83 stats->num_bytes_total = 0;
84 stats->num_bytes_last = 0;
85  
86 needle_stat_node = g_node_new(stats);
87 g_node_append(parent_stat_node, needle_stat_node);
88 return needle_stat_node;
89 }
90  
91  
92 static void
93 process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps)
94 {
95 field_info *finfo;
96 ph_stats_node_t *stats;
97 proto_node *proto_sibling_node;
98 GNode *stat_node;
99  
100 finfo = PNODE_FINFO(ptree_node);
101 /* We don't fake protocol nodes we expect them to have a field_info.
102 * Dissection with faked proto tree? */
103 g_assert(finfo);
104  
105 /* If the field info isn't related to a protocol but to a field,
106 * don't count them, as they don't belong to any protocol.
107 * (happens e.g. for toplevel tree item of desegmentation "[Reassembled TCP Segments]") */
108 if (finfo->hfinfo->parent != -1) {
109 /* Skip this element, use parent status node */
110 stat_node = parent_stat_node;
111 stats = STAT_NODE_STATS(stat_node);
112 } else {
113 stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
114  
115 stats = STAT_NODE_STATS(stat_node);
116 stats->num_pkts_total++;
117 stats->num_bytes_total += finfo->length;
118 }
119  
120 proto_sibling_node = ptree_node->next;
121  
122 if (proto_sibling_node) {
123 /* If the name does not exist for this proto_sibling_node, then it is
124 * not a normal protocol in the top-level tree. It was instead
125 * added as a normal tree such as IPv6's Hop-by-hop Option Header and
126 * should be skipped when creating the protocol hierarchy display. */
127 if(strlen(PNODE_FINFO(proto_sibling_node)->hfinfo->name) == 0 && ptree_node->next)
128 proto_sibling_node = proto_sibling_node->next;
129  
130 process_node(proto_sibling_node, stat_node, ps);
131 } else {
132 stats->num_pkts_last++;
133 stats->num_bytes_last += finfo->length;
134 }
135 }
136  
137  
138  
139 static void
140 process_tree(proto_tree *protocol_tree, ph_stats_t* ps)
141 {
142 proto_node *ptree_node;
143  
144 /*
145 * If our first item is a comment, skip over it. This keeps
146 * us from having a top-level "Packet comments" item that
147 * steals items from "Frame".
148 */
149 ptree_node = ((proto_node *)protocol_tree)->first_child;
150 if (ptree_node && ptree_node->finfo->hfinfo->id == pc_proto_id) {
151 ptree_node = ptree_node->next;
152 }
153  
154 if (!ptree_node) {
155 return;
156 }
157  
158 process_node(ptree_node, ps->stats_tree, ps);
159 }
160  
161 static gboolean
162 process_record(capture_file *cf, frame_data *frame, column_info *cinfo, ph_stats_t* ps)
163 {
164 epan_dissect_t edt;
165 struct wtap_pkthdr phdr;
166 Buffer buf;
167 double cur_time;
168  
169 wtap_phdr_init(&phdr);
170  
171 /* Load the record from the capture file */
172 ws_buffer_init(&buf, 1500);
173 if (!cf_read_record_r(cf, frame, &phdr, &buf))
174 return FALSE; /* failure */
175  
176 /* Dissect the record tree not visible */
177 epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
178 /* Don't fake protocols. We need them for the protocol hierarchy */
179 epan_dissect_fake_protocols(&edt, FALSE);
180 epan_dissect_run(&edt, cf->cd_t, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
181  
182 /* Get stats from this protocol tree */
183 process_tree(edt.tree, ps);
184  
185 if (frame->flags.has_ts) {
186 /* Update times */
187 cur_time = nstime_to_sec(&frame->abs_ts);
188 if (cur_time < ps->first_time)
189 ps->first_time = cur_time;
190 if (cur_time > ps->last_time)
191 ps->last_time = cur_time;
192 }
193  
194 /* Free our memory. */
195 epan_dissect_cleanup(&edt);
196 wtap_phdr_cleanup(&phdr);
197 ws_buffer_free(&buf);
198  
199 return TRUE; /* success */
200 }
201  
202 ph_stats_t*
203 ph_stats_new(capture_file *cf)
204 {
205 ph_stats_t *ps;
206 guint32 framenum;
207 frame_data *frame;
208 guint tot_packets, tot_bytes;
209 progdlg_t *progbar = NULL;
210 gboolean stop_flag;
211 int count;
212 float progbar_val;
213 GTimeVal start_time;
214 gchar status_str[100];
215 int progbar_nextstep;
216 int progbar_quantum;
217  
218 if (!cf) return NULL;
219  
220 pc_proto_id = proto_get_id_by_filter_name("pkt_comment");
221  
222 /* Initialize the data */
223 ps = g_new(ph_stats_t, 1);
224 ps->tot_packets = 0;
225 ps->tot_bytes = 0;
226 ps->stats_tree = g_node_new(NULL);
227 ps->first_time = 0.0;
228 ps->last_time = 0.0;
229  
230 /* Update the progress bar when it gets to this value. */
231 progbar_nextstep = 0;
232 /* When we reach the value that triggers a progress bar update,
233 bump that value by this amount. */
234 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
235 /* Count of packets at which we've looked. */
236 count = 0;
237 /* Progress so far. */
238 progbar_val = 0.0f;
239  
240 stop_flag = FALSE;
241 g_get_current_time(&start_time);
242  
243 tot_packets = 0;
244 tot_bytes = 0;
245  
246 for (framenum = 1; framenum <= cf->count; framenum++) {
247 frame = frame_data_sequence_find(cf->frames, framenum);
248  
249 /* Create the progress bar if necessary.
250 We check on every iteration of the loop, so that
251 it takes no longer than the standard time to create
252 it (otherwise, for a large file, we might take
253 considerably longer than that standard time in order
254 to get to the next progress bar step). */
255 if (progbar == NULL)
256 progbar = delayed_create_progress_dlg(
257 cf->window, "Computing",
258 "protocol hierarchy statistics",
259 TRUE, &stop_flag, &start_time, progbar_val);
260  
261 /* Update the progress bar, but do it only N_PROGBAR_UPDATES
262 times; when we update it, we have to run the GTK+ main
263 loop to get it to repaint what's pending, and doing so
264 may involve an "ioctl()" to see if there's any pending
265 input from an X server, and doing that for every packet
266 can be costly, especially on a big file. */
267 if (count >= progbar_nextstep) {
268 /* let's not divide by zero. I should never be started
269 * with count == 0, so let's assert that
270 */
271 g_assert(cf->count > 0);
272  
273 progbar_val = (gfloat) count / cf->count;
274  
275 if (progbar != NULL) {
276 g_snprintf(status_str, sizeof(status_str),
277 "%4u of %u frames", count, cf->count);
278 update_progress_dlg(progbar, progbar_val, status_str);
279 }
280  
281 progbar_nextstep += progbar_quantum;
282 }
283  
284 if (stop_flag) {
285 /* Well, the user decided to abort the statistics.
286 computation process Just stop. */
287 break;
288 }
289  
290 /* Skip frames that are hidden due to the display filter.
291 XXX - should the progress bar count only packets that
292 passed the display filter? If so, it should
293 probably do so for other loops (see "file.c") that
294 look only at those packets. */
295 if (frame->flags.passed_dfilter) {
296  
297 if (frame->flags.has_ts) {
298 if (tot_packets == 0) {
299 double cur_time = nstime_to_sec(&frame->abs_ts);
300 ps->first_time = cur_time;
301 ps->last_time = cur_time;
302 }
303 }
304  
305 /* we don't care about colinfo */
306 if (!process_record(cf, frame, NULL, ps)) {
307 /*
308 * Give up, and set "stop_flag" so we
309 * just abort rather than popping up
310 * the statistics window.
311 */
312 stop_flag = TRUE;
313 break;
314 }
315  
316 tot_packets++;
317 tot_bytes += frame->pkt_len;
318 }
319  
320 count++;
321 }
322  
323 /* We're done calculating the statistics; destroy the progress bar
324 if it was created. */
325 if (progbar != NULL)
326 destroy_progress_dlg(progbar);
327  
328 if (stop_flag) {
329 /*
330 * We quit in the middle; throw away the statistics
331 * and return NULL, so our caller doesn't pop up a
332 * window with the incomplete statistics.
333 */
334 ph_stats_free(ps);
335 return NULL;
336 }
337  
338 ps->tot_packets = tot_packets;
339 ps->tot_bytes = tot_bytes;
340  
341 return ps;
342 }
343  
344 static gboolean
345 stat_node_free(GNode *node, gpointer data _U_)
346 {
347 ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
348  
349 if (stats) {
350 g_free(stats);
351 }
352 return FALSE;
353 }
354  
355 void
356 ph_stats_free(ph_stats_t *ps)
357 {
358  
359 if (ps->stats_tree) {
360 g_node_traverse(ps->stats_tree, G_IN_ORDER,
361 G_TRAVERSE_ALL, -1,
362 stat_node_free, NULL);
363 g_node_destroy(ps->stats_tree);
364 }
365  
366 g_free(ps);
367 }
368  
369 /*
370 * Editor modelines - http://www.wireshark.org/tools/modelines.html
371 *
372 * Local variables:
373 * c-basic-offset: 8
374 * tab-width: 8
375 * indent-tabs-mode: t
376 * End:
377 *
378 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
379 * :indentSize=8:tabSize=8:noTabs=false:
380 */