In GTK+ 2.x, "gtk_entry_get_text()" returns a "const gchar *"; assign
[obnox/wireshark/wip.git] / gtk / mgcp_stat.c
1 /* mgcp_stat.c
2  * mgcp-statistics for ethereal
3  * Copyright 2003 Lars Roland
4  *
5  * $Id: mgcp_stat.c,v 1.18 2003/12/04 00:45:39 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <gtk/gtk.h>
37 #include <string.h>
38 #include "../epan/packet_info.h"
39 #include "../epan/epan.h"
40 #include "menu.h"
41 #include "../tap.h"
42 #include "../epan/value_string.h"
43 #include "../register.h"
44 #include "../plugins/mgcp/packet-mgcp.h"
45 #include "../timestats.h"
46 #include "gtk_stat_util.h"
47 #include "compat_macros.h"
48 #include "../simple_dialog.h"
49 #include "dlg_utils.h"
50 #include "../file.h"
51 #include "../globals.h"
52
53 extern GtkWidget *main_display_filter_widget;
54
55 #define NUM_TIMESTATS 10
56
57 /* used to keep track of the statistics for an entire program interface */
58 typedef struct _mgcpstat_t {
59         GtkWidget *win;
60         GtkWidget *vbox;
61         char *filter;
62         GtkWidget *scrolled_window;
63         GtkCList *table;
64         timestat_t rtd[NUM_TIMESTATS];
65         guint32 open_req_num;
66         guint32 disc_rsp_num;
67         guint32 req_dup_num;
68         guint32 rsp_dup_num;
69 } mgcpstat_t;
70
71 static const value_string mgcp_mesage_type[] = {
72   {  0, "EPCF"},
73   {  1, "CRCX"},
74   {  2, "MDCX"},
75   {  3, "DLCX"},
76   {  4, "RQNT"},
77   {  5, "NTFY"},
78   {  6, "AUEP"},
79   {  7, "AUCX"},
80   {  8, "RSIP"},
81   {  0, NULL}
82 };
83
84 static GtkWidget *dlg=NULL;
85 static GtkWidget *filter_entry;
86
87
88 static void
89 mgcpstat_reset(void *pms)
90 {
91         mgcpstat_t *ms=(mgcpstat_t *)pms;
92         int i;
93         char *title;
94
95         for(i=0;i<NUM_TIMESTATS;i++) {
96                 ms->rtd[i].num=0;
97                 ms->rtd[i].min_num=0;
98                 ms->rtd[i].max_num=0;
99                 ms->rtd[i].min.secs=0;
100                 ms->rtd[i].min.nsecs=0;
101                 ms->rtd[i].max.secs=0;
102                 ms->rtd[i].max.nsecs=0;
103                 ms->rtd[i].tot.secs=0;
104                 ms->rtd[i].tot.nsecs=0;
105         }
106
107         ms->open_req_num=0;
108         ms->disc_rsp_num=0;
109         ms->req_dup_num=0;
110         ms->rsp_dup_num=0;
111
112         if (! dlg)
113                 dlg=gtk_window_new(GTK_WINDOW_TOPLEVEL);
114         title = g_strdup_printf("MGCP SRT statistics: %s", cf_get_display_name(&cfile));
115         gtk_window_set_title(GTK_WINDOW(dlg), title);
116         g_free(title);
117 }
118
119
120 static int
121 mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, void *pmi)
122 {
123         mgcpstat_t *ms=(mgcpstat_t *)pms;
124         mgcp_info_t *mi=pmi;
125         nstime_t delta;
126
127         switch (mi->mgcp_type) {
128
129         case MGCP_REQUEST:
130                 if(mi->is_duplicate){
131                         /* Duplicate is ignored */
132                         ms->req_dup_num++;
133                         return 0;
134                 }
135                 else {
136                         ms->open_req_num++;
137                         return 0;
138                 }
139         break;
140
141         case MGCP_RESPONSE:
142                 if(mi->is_duplicate){
143                         /* Duplicate is ignored */
144                         ms->rsp_dup_num++;
145                         return 0;
146                 }
147                 else if (!mi->request_available) {
148                         /* no request was seen */
149                         ms->disc_rsp_num++;
150                         return 0;
151                 }
152                 else {
153                         ms->open_req_num--;
154                         /* calculate time delta between request and response */
155                         delta.secs=pinfo->fd->abs_secs-mi->req_time.secs;
156                         delta.nsecs=pinfo->fd->abs_usecs*1000-mi->req_time.nsecs;
157                         if(delta.nsecs<0){
158                                 delta.nsecs+=1000000000;
159                                 delta.secs--;
160                         }
161
162                         if (strncasecmp(mi->code, "EPCF", 4) == 0 ) {
163                                 time_stat_update(&(ms->rtd[0]),&delta, pinfo);
164                         }
165                         else if (strncasecmp(mi->code, "CRCX", 4) == 0 ) {
166                                 time_stat_update(&(ms->rtd[1]),&delta, pinfo);
167                         }
168                         else if (strncasecmp(mi->code, "MDCX", 4) == 0 ) {
169                                 time_stat_update(&(ms->rtd[2]),&delta, pinfo);
170                         }
171                         else if (strncasecmp(mi->code, "DLCX", 4) == 0 ) {
172                                 time_stat_update(&(ms->rtd[3]),&delta, pinfo);
173                         }
174                         else if (strncasecmp(mi->code, "RQNT", 4) == 0 ) {
175                                 time_stat_update(&(ms->rtd[4]),&delta, pinfo);
176                         }
177                         else if (strncasecmp(mi->code, "NTFY", 4) == 0 ) {
178                                 time_stat_update(&(ms->rtd[5]),&delta, pinfo);
179                         }
180                         else if (strncasecmp(mi->code, "AUEP", 4) == 0 ) {
181                                 time_stat_update(&(ms->rtd[6]),&delta, pinfo);
182                         }
183                         else if (strncasecmp(mi->code, "AUCX", 4) == 0 ) {
184                                 time_stat_update(&(ms->rtd[7]),&delta, pinfo);
185                         }
186                         else if (strncasecmp(mi->code, "RSIP", 4) == 0 ) {
187                                 time_stat_update(&(ms->rtd[8]),&delta, pinfo);
188                         }
189                         else {
190                                 time_stat_update(&(ms->rtd[9]),&delta, pinfo);
191                         }
192
193                         return 1;
194                 }
195         break;
196
197         default:
198                 return 0;
199         break;
200         }
201 }
202
203 static void
204 mgcpstat_draw(void *pms)
205 {
206         mgcpstat_t *ms=(mgcpstat_t *)pms;
207         int i;
208         /* gtk1 using a scrollable clist*/
209         char *str[7];
210
211         for(i=0;i<7;i++) {
212                 str[i]=g_malloc(sizeof(char[256]));
213         }
214
215         /* clear list before printing */
216         gtk_clist_clear(ms->table);
217
218         for(i=0;i<NUM_TIMESTATS;i++) {
219                 /* nothing seen, nothing to do */
220                 if(ms->rtd[i].num==0){
221                         continue;
222                 }
223
224                 sprintf(str[0], "%s", val_to_str(i,mgcp_mesage_type,"Other"));
225                 sprintf(str[1], "%d", ms->rtd[i].num);
226                 sprintf(str[2], "%8.2f msec", nstime_to_msec(&(ms->rtd[i].min)));
227                 sprintf(str[3], "%8.2f msec", nstime_to_msec(&(ms->rtd[i].max)));
228                 sprintf(str[4], "%8.2f msec", get_average(&(ms->rtd[i].tot), ms->rtd[i].num));
229                 sprintf(str[5], "%6u", ms->rtd[i].min_num);
230                 sprintf(str[6], "%6u", ms->rtd[i].max_num);
231                 gtk_clist_append(ms->table, str);
232         }
233
234         gtk_widget_show(GTK_WIDGET(ms->table));
235         for(i=0;i<7;i++) {
236                 g_free(str[i]);
237         }
238 }
239
240 void protect_thread_critical_region(void);
241 void unprotect_thread_critical_region(void);
242 static void
243 win_destroy_cb(GtkWindow *win _U_, gpointer data)
244 {
245         mgcpstat_t *ms=(mgcpstat_t *)data;
246
247         protect_thread_critical_region();
248         remove_tap_listener(ms);
249         unprotect_thread_critical_region();
250
251         if(ms->filter){
252                 g_free(ms->filter);
253                 ms->filter=NULL;
254         }
255         g_free(ms);
256 }
257
258 static gchar *titles[]={"Type",
259                         "Messages",
260                         "Min SRT",
261                         "Max SRT",
262                         "Avg SRT",
263                         "Min in Frame",
264                         "Max in Frame" };
265
266 void
267 gtk_mgcpstat_init(char *optarg)
268 {
269         mgcpstat_t *ms;
270         char *filter=NULL;
271         GString *error_string;
272
273         if(strncmp(optarg,"mgcp,srt,",9) == 0){
274                 filter=optarg+9;
275         } else {
276                 filter=g_malloc(1);
277                 *filter='\0';
278         }
279
280         ms=g_malloc(sizeof(mgcpstat_t));
281         ms->filter=g_malloc(strlen(filter)+1);
282         strcpy(ms->filter, filter);
283
284         mgcpstat_reset(ms);
285
286         ms->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
287         SIGNAL_CONNECT(ms->win, "destroy", win_destroy_cb, ms);
288
289         ms->vbox=gtk_vbox_new(FALSE, 0);
290
291         init_main_stat_window(ms->win, ms->vbox, "MGCP Service Response Time (SRT) Statistics", filter);
292
293         /* GTK1 using a scrollable clist*/
294         /* init a scrolled window*/
295         ms->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
296         WIDGET_SET_SIZE(ms->scrolled_window, 550, 150);
297
298         ms->table = create_stat_table(ms->scrolled_window, ms->vbox, 7, titles);
299
300         error_string=register_tap_listener("mgcp", ms, filter, mgcpstat_reset, mgcpstat_packet, mgcpstat_draw);
301         if(error_string){
302                 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
303                 g_string_free(error_string, TRUE);
304                 g_free(ms->filter);
305                 g_free(ms);
306                 return;
307         }
308
309         gtk_widget_show_all(ms->win);
310         redissect_packets(&cfile);
311 }
312
313
314 static void
315 dlg_destroy_cb(void)
316 {
317         dlg=NULL;
318 }
319
320 static void
321 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
322 {
323         gtk_widget_destroy(GTK_WIDGET(parent_w));
324 }
325
326 static void
327 mgcpstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
328 {
329         char *filter;
330         char str[256];
331
332         filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
333         if(filter[0]==0){
334                 gtk_mgcpstat_init("mgcp,srt");
335         } else {
336                 sprintf(str,"mgcp,srt,%s", filter);
337                 gtk_mgcpstat_init(str);
338         }
339 }
340
341
342
343 static void
344 gtk_mgcpstat_cb(GtkWidget *w _U_, gpointer d _U_)
345 {
346         const char *filter;
347         char *title;
348         GtkWidget *dlg_box;
349         GtkWidget *filter_box, *filter_label;
350         GtkWidget *bbox, *start_button, *cancel_button;
351
352         /* if the window is already open, bring it to front */
353         if(dlg){
354                 gdk_window_raise(dlg->window);
355                 return;
356         }
357
358         title = g_strdup_printf("Ethereal: Compute MGCP SRT statistics: %s", cf_get_display_name(&cfile));
359
360         dlg=dlg_window_new(title);
361         g_free(title);
362         SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
363
364         dlg_box=gtk_vbox_new(FALSE, 10);
365         gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
366         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
367         gtk_widget_show(dlg_box);
368
369         /* Filter box */
370         filter_box=gtk_hbox_new(FALSE, 3);
371
372         /* Filter label */
373         filter_label=gtk_label_new("Filter:");
374         gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
375         gtk_widget_show(filter_label);
376
377         /* Filter entry */
378         filter_entry=gtk_entry_new();
379         gtk_widget_set_usize(filter_entry, 300, -2);
380         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
381         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
382         if(filter){
383                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
384         }
385         gtk_widget_show(filter_entry);
386
387         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
388         gtk_widget_show(filter_box);
389
390         /* button box */
391         bbox = gtk_hbutton_box_new();
392         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
393         gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
394         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
395         gtk_widget_show(bbox);
396
397         /* the start button */
398         start_button=gtk_button_new_with_label("Create Stat");
399         SIGNAL_CONNECT_OBJECT(start_button, "clicked",
400                               mgcpstat_start_button_clicked, NULL);
401         gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
402         GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
403         gtk_widget_grab_default(start_button);
404         gtk_widget_show(start_button);
405
406 #if GTK_MAJOR_VERSION < 2
407         cancel_button=gtk_button_new_with_label("Cancel");
408 #else
409         cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
410 #endif
411         SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
412         GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
413         gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
414         gtk_widget_show(cancel_button);
415
416         /* Catch the "activate" signal on the filter text entry, so that
417            if the user types Return there, we act as if the "Create Stat"
418            button had been selected, as happens if Return is typed if
419            some widget that *doesn't* handle the Return key has the input
420            focus. */
421         dlg_set_activate(filter_entry, start_button);
422
423         /* Catch the "key_press_event" signal in the window, so that we can
424            catch the ESC key being pressed and act as if the "Cancel" button
425            had been selected. */
426         dlg_set_cancel(dlg, cancel_button);
427
428         /* Give the initial focus to the "Filter" entry box. */
429         gtk_widget_grab_focus(filter_entry);
430
431         gtk_widget_show_all(dlg);
432 }
433
434 void
435 register_tap_listener_gtkmgcpstat(void)
436 {
437         register_ethereal_tap("mgcp,srt", gtk_mgcpstat_init);
438 }
439
440 void
441 register_tap_menu_gtkmgcpstat(void)
442 {
443         if (find_tap_id("mgcp"))
444                 register_tap_menu_item("Statistics/Service Response Time/MGCP...",
445                     gtk_mgcpstat_cb, NULL, NULL);
446 }
447