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