aaa1c896261c5aa19af1757e0811a66cfc13ff60
[obnox/wireshark/wip.git] / gtk / gsm_map_stat.c
1 /* gsm_map_stat.c
2  *
3  * Copyright 2004, Michael Lum <mlum [AT] telostech.com>
4  * In association with Telos Technology Inc.
5  *
6  * MUCH code modified from service_response_time_table.c.
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 /*
30  * This TAP provides statistics for GSM MAP Operations:
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36 #include <string.h>
37
38 #include <gtk/gtk.h>
39
40 #include <epan/epan.h>
41 #include <epan/packet.h>
42 #include <epan/packet_info.h>
43 #include <epan/value_string.h>
44 #include <epan/stat_cmd_args.h>
45 #include <epan/tap.h>
46 #include <epan/asn1.h>
47 #include <epan/dissectors/packet-gsm_map.h>
48
49 #include "../stat_menu.h"
50 #include "../simple_dialog.h"
51 #include "../register.h"
52 #include "../globals.h"
53
54 #include "gtk/gui_stat_menu.h"
55 #include "gtk/dlg_utils.h"
56 #include "gtk/gui_utils.h"
57 #include "gtk/filter_dlg.h"
58 #include "gtk/gsm_map_stat.h"
59
60
61 enum
62 {
63    ID_COLUMN,
64    OP_CODE_COLUMN,
65    INVOKES_COLUMN,
66    NUM_BYTES_FWD_COLUMN,
67    AVG_BYTES_FWD_COLUMN,
68    RET_RES_COLUMN,
69    NUM_BYTES_REV_COLUMN,
70    AVG_BYTES_REV_COLUMN,
71    TOT_BYTES_COLUMN,
72    AVG_BYTES_COLUMN,
73    N_COLUMN /* The number of columns */
74 };
75
76 /* Create list */
77 static
78 GtkWidget* create_list()
79 {
80
81     GtkListStore *list_store;
82     GtkWidget *list;
83     GtkTreeViewColumn *column;
84     GtkCellRenderer *renderer;
85     GtkTreeSortable *sortable;
86         GtkTreeView     *list_view;
87         GtkTreeSelection  *selection;
88
89         /* Create the store */
90     list_store = gtk_list_store_new(N_COLUMN,   /* Total number of columns XXX*/
91                                G_TYPE_UINT,             /* ID                           */
92                                G_TYPE_STRING,   /* Operation Code       */
93                                G_TYPE_INT,              /* Invokes                      */
94                                G_TYPE_INT,              /* Num Bytes            */
95                                G_TYPE_FLOAT,    /* Avg Bytes            */
96                                G_TYPE_INT,              /* RetResult            */
97                                G_TYPE_INT,              /* Num Bytes            */
98                                G_TYPE_FLOAT,    /* Avg Bytes            */
99                                G_TYPE_INT,              /* Total Bytes          */
100                                G_TYPE_FLOAT);   /* Avg Bytes            */
101
102     /* Create a view */
103     list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
104
105         list_view = GTK_TREE_VIEW(list);
106         sortable = GTK_TREE_SORTABLE(list_store);
107
108 #if GTK_CHECK_VERSION(2,6,0)
109         /* Speed up the list display */
110         gtk_tree_view_set_fixed_height_mode(list_view, TRUE);
111 #endif
112
113     /* Setup the sortable columns */
114     gtk_tree_sortable_set_sort_column_id(sortable, ID_COLUMN, GTK_SORT_ASCENDING);
115     gtk_tree_view_set_headers_clickable(list_view, FALSE);
116
117     /* The view now holds a reference.  We can get rid of our own reference */
118     g_object_unref (G_OBJECT (list_store));
119
120     /* 
121          * Create the first column packet, associating the "text" attribute of the
122      * cell_renderer to the first column of the model 
123          */
124         /* 1:st column */
125         renderer = gtk_cell_renderer_text_new ();
126     column = gtk_tree_view_column_new_with_attributes ("ID", renderer, 
127                 "text", ID_COLUMN, 
128                 NULL);
129
130         gtk_tree_view_column_set_sort_column_id(column, ID_COLUMN);
131     gtk_tree_view_column_set_resizable(column, TRUE);
132     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
133     gtk_tree_view_column_set_min_width(column, 40);
134
135         /* Add the column to the view. */
136     gtk_tree_view_append_column (list_view, column);
137
138     /* 2:nd column..Operation Code. */
139     renderer = gtk_cell_renderer_text_new ();
140     column = gtk_tree_view_column_new_with_attributes ("Operation Code", renderer, 
141                 "text", OP_CODE_COLUMN,
142                 NULL);
143     gtk_tree_view_column_set_sort_column_id(column, OP_CODE_COLUMN);
144     gtk_tree_view_column_set_resizable(column, TRUE);
145     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
146     gtk_tree_view_column_set_min_width(column, 210);
147     gtk_tree_view_append_column (list_view, column);
148
149         /* 3:d column..Invokes. */
150     renderer = gtk_cell_renderer_text_new ();
151     column = gtk_tree_view_column_new_with_attributes ("Invokes", renderer, 
152                 "text", INVOKES_COLUMN,
153                 NULL);
154     gtk_tree_view_column_set_sort_column_id(column, INVOKES_COLUMN);
155     gtk_tree_view_column_set_resizable(column, TRUE);
156     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
157     gtk_tree_view_column_set_min_width(column, 60);
158     gtk_tree_view_append_column (list_view, column);
159
160     /* 4:th column.. Num Bytes. */
161     renderer = gtk_cell_renderer_text_new ();
162         column = gtk_tree_view_column_new_with_attributes ("Num Bytes", renderer, 
163                 "text", NUM_BYTES_FWD_COLUMN, 
164                 NULL);
165         
166
167     gtk_tree_view_column_set_sort_column_id(column, NUM_BYTES_FWD_COLUMN);
168     gtk_tree_view_column_set_resizable(column, TRUE);
169     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
170     gtk_tree_view_column_set_min_width(column, 100);
171     gtk_tree_view_append_column (list_view, column);
172
173     /* 5:th column.. Avg Bytes. */
174     renderer = gtk_cell_renderer_text_new ();
175         column = gtk_tree_view_column_new_with_attributes ("Avg Bytes", renderer, 
176                 "text", AVG_BYTES_FWD_COLUMN, 
177                 NULL);
178         gtk_tree_view_column_set_cell_data_func(column, renderer, float_data_func, 
179                 GINT_TO_POINTER(AVG_BYTES_FWD_COLUMN), NULL);
180
181     gtk_tree_view_column_set_sort_column_id(column, AVG_BYTES_FWD_COLUMN);
182     gtk_tree_view_column_set_resizable(column, TRUE);
183     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
184     gtk_tree_view_column_set_min_width(column, 80);
185     gtk_tree_view_append_column (list_view, column);
186
187         /* 6:d column..Invokes. */
188     renderer = gtk_cell_renderer_text_new ();
189     column = gtk_tree_view_column_new_with_attributes ("ReturnResult", renderer, 
190                 "text", RET_RES_COLUMN,
191                 NULL);
192     gtk_tree_view_column_set_sort_column_id(column, RET_RES_COLUMN);
193     gtk_tree_view_column_set_resizable(column, TRUE);
194     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
195     gtk_tree_view_column_set_min_width(column, 60);
196     gtk_tree_view_append_column (list_view, column);
197
198     /* 7:th column.. Num Bytes. */
199     renderer = gtk_cell_renderer_text_new ();
200         column = gtk_tree_view_column_new_with_attributes ("Num Bytes", renderer, 
201                 "text", NUM_BYTES_REV_COLUMN, 
202                 NULL);
203         
204
205     gtk_tree_view_column_set_sort_column_id(column, NUM_BYTES_FWD_COLUMN);
206     gtk_tree_view_column_set_resizable(column, TRUE);
207     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
208     gtk_tree_view_column_set_min_width(column, 100);
209     gtk_tree_view_append_column (list_view, column);
210
211     /* 8:th column.. Avg Bytes. */
212     renderer = gtk_cell_renderer_text_new ();
213         column = gtk_tree_view_column_new_with_attributes ("Avg Bytes", renderer, 
214                 "text", AVG_BYTES_REV_COLUMN, 
215                 NULL);
216         gtk_tree_view_column_set_cell_data_func(column, renderer, float_data_func, 
217                 GINT_TO_POINTER(AVG_BYTES_REV_COLUMN), NULL);
218
219
220     gtk_tree_view_column_set_sort_column_id(column, AVG_BYTES_REV_COLUMN);
221     gtk_tree_view_column_set_resizable(column, TRUE);
222     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
223     gtk_tree_view_column_set_min_width(column, 80);
224     gtk_tree_view_append_column (list_view, column);
225
226     /* 9:th column.. Total Bytes. */
227     renderer = gtk_cell_renderer_text_new ();
228         column = gtk_tree_view_column_new_with_attributes ("Total Bytes", renderer, 
229                 "text", TOT_BYTES_COLUMN, 
230                 NULL);
231         
232
233     gtk_tree_view_column_set_sort_column_id(column, NUM_BYTES_FWD_COLUMN);
234     gtk_tree_view_column_set_resizable(column, TRUE);
235     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
236     gtk_tree_view_column_set_min_width(column, 100);
237     gtk_tree_view_append_column (list_view, column);
238
239     /* 10:th column.. Avg Bytes. */
240     renderer = gtk_cell_renderer_text_new ();
241         column = gtk_tree_view_column_new_with_attributes ("Avg Bytes", renderer, 
242                 "text", AVG_BYTES_COLUMN, 
243                 NULL);
244         gtk_tree_view_column_set_cell_data_func(column, renderer, float_data_func, 
245                 GINT_TO_POINTER(AVG_BYTES_COLUMN), NULL);
246
247     gtk_tree_view_column_set_sort_column_id(column, AVG_BYTES_COLUMN);
248     gtk_tree_view_column_set_resizable(column, TRUE);
249     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
250     gtk_tree_view_column_set_min_width(column, 60);
251     gtk_tree_view_append_column (list_view, column);
252
253         /* Now enable the sorting of each column */
254     gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(list_view), TRUE);
255     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(list_view), TRUE);
256
257         /* Setup the selection handler */
258         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
259         gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
260
261         return list;
262
263 }
264
265 typedef struct _gsm_map_stat_dlg_t {
266     GtkWidget           *win;
267     GtkWidget           *scrolled_win;
268     GtkWidget           *table;
269 } gsm_map_stat_dlg_t;
270
271 static gsm_map_stat_dlg_t       dlg;
272
273 /*
274  * used by gsm_map_summary.c
275  */
276 gsm_map_stat_t                  gsm_map_stat;
277
278
279 static void
280 gsm_map_stat_reset(
281     void                *tapdata)
282 {
283     gsm_map_stat_t      *stat_p = tapdata;
284
285     memset(stat_p, 0, sizeof(gsm_map_stat_t));
286 }
287
288
289 static int
290 gsm_map_stat_packet(
291     void                *tapdata,
292     packet_info         *pinfo _U_,
293     epan_dissect_t      *edt _U_,
294     const void          *data)
295 {
296     gsm_map_stat_t      *stat_p = tapdata;
297     const gsm_map_tap_rec_t     *data_p = data;
298
299 #if 0   /* always false because message_type is 8 bit value */
300     if (data_p->opr_code_idx > sizeof(stat_p->opr_code))
301     {
302         /*
303          * unknown message type !!!
304          */
305         return(0);
306     }
307 #endif
308
309     if (data_p->invoke)
310     {
311         stat_p->opr_code[data_p->opr_code_idx]++;
312         stat_p->size[data_p->opr_code_idx] += data_p->size;
313     }
314     else
315     {
316         stat_p->opr_code_rr[data_p->opr_code_idx]++;
317         stat_p->size_rr[data_p->opr_code_idx] += data_p->size;
318     }
319
320     return(1);
321 }
322
323
324 static void
325 gsm_map_stat_draw(
326     void                *tapdata)
327 {
328     gsm_map_stat_t      *stat_p = tapdata;
329     int                 i;
330     GtkListStore *list_store;
331         GtkTreeIter  iter;
332         guint id;
333
334     if (dlg.win && tapdata)
335     {
336                 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (dlg.table))); /* Get store */
337
338                 i = 0;
339                 while (gsm_map_opr_code_strings[i].strptr){
340                         float avrage_bytes_fwd;
341                         float avrage_bytes_rev;
342                         float avrage_bytes_tot;
343
344                         id = gsm_map_opr_code_strings[i].value;
345                         if (stat_p->opr_code[i] >0){
346                                 avrage_bytes_fwd =(float)stat_p->size[i]/(float)stat_p->opr_code[i];
347                         }else{
348                                 avrage_bytes_fwd = 0;
349                         }
350                         if (stat_p->opr_code_rr[i] >0){
351                                 avrage_bytes_rev = (float)stat_p->size_rr[i]/(float)stat_p->opr_code_rr[i];
352                         }else{
353                                 avrage_bytes_rev = 0;
354                         }
355                         if ((stat_p->opr_code[i] + stat_p->opr_code_rr[i])>0){
356                                 avrage_bytes_tot = (float)(stat_p->size[i] +stat_p->size_rr[i])/(float)(stat_p->opr_code[i] + stat_p->opr_code_rr[i]);
357                         }else{
358                                 avrage_bytes_tot = 0;
359                         }
360                         /* Creates a new row at position. iter will be changed to point to this new row. 
361                          * If position is larger than the number of rows on the list, then the new row will be appended to the list.
362                          * The row will be filled with the values given to this function.
363                          * :
364                          * should generally be preferred when inserting rows in a sorted list store.
365                          */
366 #if GTK_CHECK_VERSION(2,6,0)
367                         gtk_list_store_insert_with_values( list_store , &iter, G_MAXINT,
368 #else
369                         gtk_list_store_append  (list_store, &iter);
370                         gtk_list_store_set  (list_store, &iter,
371 #endif
372                                    ID_COLUMN,                           gsm_map_opr_code_strings[i].value,
373                                    OP_CODE_COLUMN,                      (char*)gsm_map_opr_code_strings[i].strptr,
374                                    INVOKES_COLUMN,                      stat_p->opr_code[i],
375                                    NUM_BYTES_FWD_COLUMN,        (gint)stat_p->size[i],
376                                    AVG_BYTES_FWD_COLUMN,        avrage_bytes_fwd,
377                                    RET_RES_COLUMN,                      stat_p->opr_code_rr[i],
378                                    NUM_BYTES_REV_COLUMN,        stat_p->size_rr[i],
379                                    AVG_BYTES_REV_COLUMN,        avrage_bytes_rev,
380                                    TOT_BYTES_COLUMN,            stat_p->size[i] + stat_p->size_rr[i],
381                                    AVG_BYTES_COLUMN,            avrage_bytes_tot,
382                                    -1);
383                         i++;
384                 }
385         }
386 }
387
388 static void
389 gsm_map_stat_gtk_win_destroy_cb(
390     GtkWindow           *win _U_,
391     gpointer            user_data _U_)
392 {
393     memset((void *) user_data, 0, sizeof(gsm_map_stat_dlg_t));
394 }
395
396
397 static void
398 gsm_map_stat_gtk_win_create(
399     gsm_map_stat_dlg_t  *dlg_p,
400     const char          *title)
401 {
402     GtkWidget           *vbox;
403     GtkWidget           *bt_close;
404     GtkWidget           *bbox;
405
406
407     dlg_p->win = window_new(GTK_WINDOW_TOPLEVEL, title);
408     gtk_window_set_default_size(GTK_WINDOW(dlg_p->win), 560, 390);
409
410     vbox = gtk_vbox_new(FALSE, 3);
411         gtk_container_add(GTK_CONTAINER(dlg_p->win), vbox);
412     gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
413
414     dlg_p->scrolled_win = scrolled_window_new(NULL, NULL);
415     gtk_box_pack_start(GTK_BOX(vbox), dlg_p->scrolled_win, TRUE, TRUE, 0);
416
417         dlg_p->table = create_list();
418         gtk_widget_show(dlg_p->table);
419
420     gtk_container_add(GTK_CONTAINER(dlg_p->scrolled_win), dlg_p->table);
421
422     /* Button row. */
423     bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
424     gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
425
426     bt_close = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
427     window_set_cancel_button(dlg_p->win, bt_close, window_cancel_button_cb);
428
429     g_signal_connect(dlg_p->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
430     g_signal_connect(dlg_p->win, "destroy", G_CALLBACK(gsm_map_stat_gtk_win_destroy_cb), dlg_p);
431
432     gtk_widget_show_all(dlg_p->win);
433     window_present(dlg_p->win);
434 }
435
436
437 static void
438 gsm_map_stat_gtk_cb(
439     GtkWidget           *w _U_,
440     gpointer            d _U_)
441 {
442
443
444     /*
445      * if the window is already open, bring it to front
446      */
447     if (dlg.win){
448                 gdk_window_raise(dlg.win->window);
449                 return;
450     }
451
452     gsm_map_stat_gtk_win_create(&dlg, "GSM MAP Operation Statistics");
453
454         gsm_map_stat_draw(&gsm_map_stat);
455 }
456
457
458 static void
459 gsm_map_stat_gtk_init(const char                *optarg _U_,
460                       void* userdata _U_)
461 {
462     gsm_map_stat_gtk_cb(NULL, NULL);
463 }
464
465
466 void
467 register_tap_listener_gtkgsm_map_stat(void)
468 {
469     GString             *err_p;
470
471
472     memset((void *) &gsm_map_stat, 0, sizeof(gsm_map_stat_t));
473
474     err_p =
475         register_tap_listener("gsm_map", &gsm_map_stat, NULL,
476             gsm_map_stat_reset,
477             gsm_map_stat_packet,
478             gsm_map_stat_draw);
479
480     if (err_p != NULL)
481     {
482         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_p->str);
483         g_string_free(err_p, TRUE);
484
485         exit(1);
486     }
487
488     register_stat_menu_item("GSM/MAP Operation",  REGISTER_STAT_GROUP_TELEPHONY,
489         gsm_map_stat_gtk_cb, NULL, NULL, NULL);
490     register_stat_cmd_arg("gsm_map", gsm_map_stat_gtk_init,NULL);
491 }