From Lars Roland Service Response times for H225 RAS
[obnox/wireshark/wip.git] / gtk / h225_ras_srt.c
1 /* h225_ras_srt.c
2  * h225 RAS Service Response Time statistics for ethereal
3  * Copyright 2003 Lars Roland
4  *
5  * $Id: h225_ras_srt.c,v 1.1 2003/11/16 23:11:20 sahlberg 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 "../packet-h225.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 static GtkWidget *dlg=NULL;
56 static GtkWidget *filter_entry;
57
58 /* following values represent the size of their valuestring arrays */
59 #define NUM_RAS_STATS 7
60
61 static const value_string ras_message_category[] = {
62   {  0, "Gatekeeper    "},
63   {  1, "Registration  "},
64   {  2, "UnRegistration"},
65   {  3, "Admission     "},
66   {  4, "Bandwidth     "},
67   {  5, "Disengage     "},
68   {  6, "Location      "},
69   {  0, NULL }
70 };
71
72 typedef enum _ras_type {
73         RAS_REQUEST,
74         RAS_CONFIRM,
75         RAS_REJECT,
76         RAS_OTHER
77 }ras_type;
78
79 typedef enum _ras_category {
80         RAS_GATEKEEPER,
81         RAS_REGISTRATION,
82         RAS_UNREGISTRATION,
83         RAS_ADMISSION,
84         RAS_BANDWIDTH,
85         RAS_DISENGAGE,
86         RAS_LOCATION,
87         RAS_OTHERS
88 }ras_category;
89
90 /* Summary of response-time calculations*/
91 typedef struct _h225_rtd_t {
92         guint32 open_req_num;
93         guint32 disc_rsp_num;
94         guint32 req_dup_num;
95         guint32 rsp_dup_num;
96         timestat_t stats;
97 } h225_rtd_t;
98
99 /* used to keep track of the statistics for an entire program interface */
100 typedef struct _h225rassrt_t {
101         GtkWidget *win;
102         GtkWidget *vbox;
103         char *filter;
104         GtkWidget *scrolled_window;
105         GtkCList *table;
106         h225_rtd_t ras_rtd[NUM_RAS_STATS];
107 } h225rassrt_t;
108
109
110 static void
111 h225rassrt_reset(void *phs)
112 {
113         h225rassrt_t *hs=(h225rassrt_t *)phs;
114         int i;
115
116         for(i=0;i<NUM_RAS_STATS;i++) {
117                 hs->ras_rtd[i].stats.num = 0;
118                 hs->ras_rtd[i].stats.min_num = 0;
119                 hs->ras_rtd[i].stats.max_num = 0;
120                 hs->ras_rtd[i].stats.min.secs = 0;
121                 hs->ras_rtd[i].stats.min.nsecs = 0;
122                 hs->ras_rtd[i].stats.max.secs = 0;
123                 hs->ras_rtd[i].stats.max.nsecs = 0;
124                 hs->ras_rtd[i].stats.tot.secs = 0;
125                 hs->ras_rtd[i].stats.tot.nsecs = 0;
126                 hs->ras_rtd[i].open_req_num = 0;
127                 hs->ras_rtd[i].disc_rsp_num = 0;
128                 hs->ras_rtd[i].req_dup_num = 0;
129                 hs->ras_rtd[i].rsp_dup_num = 0;
130         }
131
132 }
133
134
135 static int
136 h225rassrt_packet(void *phs, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *phi)
137 {
138         h225rassrt_t *hs=(h225rassrt_t *)phs;
139         h225_packet_info *pi=phi;
140
141         ras_type rasmsg_type = RAS_OTHER;
142         ras_category rascategory = RAS_OTHERS;
143
144         if (pi->msg_type != H225_RAS || pi->msg_tag == -1) {
145                 /* No RAS Message or uninitialized msg_tag -> return */
146                 return 0;
147         }
148
149         if (pi->msg_tag < 21) {
150                 /* */
151                 rascategory = pi->msg_tag / 3;
152                 rasmsg_type = pi->msg_tag % 3;
153         }
154         else {
155                 /* No SRT yet (ToDo) */
156                 return 0;
157         }
158
159         switch(rasmsg_type) {
160
161         case RAS_REQUEST:
162                 if(pi->is_duplicate){
163                         hs->ras_rtd[rascategory].req_dup_num++;
164                 }
165                 else {
166                         hs->ras_rtd[rascategory].open_req_num++;
167                 }
168                 break;
169
170         case RAS_CONFIRM:
171                 /* no break - delay stats are identical for Confirm and Reject  */
172         case RAS_REJECT:
173                 if(pi->is_duplicate){
174                         /* Duplicate is ignored */
175                         hs->ras_rtd[rascategory].rsp_dup_num++;
176                 }
177                 else if (!pi->request_available) {
178                         /* no request was seen, ignore response  */
179                         hs->ras_rtd[rascategory].disc_rsp_num++;
180                 }
181                 else {
182                         hs->ras_rtd[rascategory].open_req_num--;
183                         time_stat_update(&(hs->ras_rtd[rascategory].stats),&(pi->delta_time), pinfo);
184                 }
185                 break;
186
187         default:
188                 return 0;
189                 break;
190         }
191         return 1;
192 }
193
194 static void
195 h225rassrt_draw(void *phs)
196 {
197         h225rassrt_t *hs=(h225rassrt_t *)phs;
198         int i;
199         char *str[11];
200
201         for(i=0;i<11;i++) {
202                 str[i]=g_malloc(sizeof(char[256]));
203         }
204         /* Now print Message and Reason Counter Table */
205         /* clear list before printing */
206         gtk_clist_clear(hs->table);
207
208         for(i=0;i<NUM_RAS_STATS;i++) {
209                 /* nothing seen, nothing to do */
210                 if(hs->ras_rtd[i].stats.num==0){
211                         continue;
212                 }
213
214                 sprintf(str[0], "%s", val_to_str(i,ras_message_category,"Other"));
215                 sprintf(str[1], "%7d", hs->ras_rtd[i].stats.num);
216                 sprintf(str[2], "%8.2f msec", nstime_to_msec(&(hs->ras_rtd[i].stats.min)));
217                 sprintf(str[3], "%8.2f msec", nstime_to_msec(&(hs->ras_rtd[i].stats.max)));;
218                 sprintf(str[4], "%8.2f msec", get_average(&(hs->ras_rtd[i].stats.tot), hs->ras_rtd[i].stats.num));
219                 sprintf(str[5], "%6u", hs->ras_rtd[i].stats.min_num);
220                 sprintf(str[6], "%6u", hs->ras_rtd[i].stats.max_num);
221                 sprintf(str[7], "%4u", hs->ras_rtd[i].open_req_num);
222                 sprintf(str[8], "%4u", hs->ras_rtd[i].disc_rsp_num);
223                 sprintf(str[9], "%4u", hs->ras_rtd[i].req_dup_num);
224                 sprintf(str[10], "%4u", hs->ras_rtd[i].rsp_dup_num);
225                 gtk_clist_append(GTK_CLIST(hs->table), str);
226         }
227
228         gtk_widget_show(GTK_WIDGET(hs->table));
229
230 }
231
232 void protect_thread_critical_region(void);
233 void unprotect_thread_critical_region(void);
234 static void
235 win_destroy_cb(GtkWindow *win _U_, gpointer data)
236 {
237         h225rassrt_t *hs=(h225rassrt_t *)data;
238
239         protect_thread_critical_region();
240         remove_tap_listener(hs);
241         unprotect_thread_critical_region();
242
243         if(hs->filter){
244                 g_free(hs->filter);
245                 hs->filter=NULL;
246         }
247         g_free(hs);
248 }
249
250
251 static gchar *titles[]={"RAS-Type",
252                         "Measurements",
253                         "Min RTT",
254                         "Max RTT",
255                         "Avg RTT",
256                         "Min in Frame",
257                         "Max in Frame",
258                         "Open Requests",
259                         "Discarded Responses",
260                         "Repeated Requests",
261                         "Repeated Responses" };
262
263 void
264 gtk_h225rassrt_init(char *optarg)
265 {
266         h225rassrt_t *hs;
267         char *filter=NULL;
268         GString *error_string;
269
270         if(strncmp(optarg,"h225,srt,",9) == 0){
271                 filter=optarg+9;
272         } else {
273                 filter=g_malloc(1);
274                 *filter='\0';
275         }
276
277         hs=g_malloc(sizeof(h225rassrt_t));
278         hs->filter=g_malloc(strlen(filter)+1);
279         strcpy(hs->filter, filter);
280
281         h225rassrt_reset(hs);
282
283         hs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
284         SIGNAL_CONNECT(hs->win, "destroy", win_destroy_cb, hs);
285
286         hs->vbox=gtk_vbox_new(FALSE, 0);
287
288         init_main_stat_window(hs->win, hs->vbox, "ITU-T H.225 RAS Service Response Time", filter);
289
290         /* init a scrolled window*/
291         hs->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
292         WIDGET_SET_SIZE(hs->scrolled_window, 600, 160);
293
294         hs->table = create_stat_table(hs->scrolled_window, hs->vbox, 11, titles);
295
296         error_string=register_tap_listener("h225", hs, filter, h225rassrt_reset, h225rassrt_packet, h225rassrt_draw);
297         if(error_string){
298                 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
299                 g_string_free(error_string, TRUE);
300                 g_free(hs->filter);
301                 g_free(hs);
302                 return;
303         }
304
305         gtk_widget_show_all(hs->win);
306         redissect_packets(&cfile);
307 }
308
309
310
311 static void
312 dlg_destroy_cb(void)
313 {
314         dlg=NULL;
315 }
316
317 static void
318 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
319 {
320         gtk_widget_destroy(GTK_WIDGET(parent_w));
321 }
322
323 static void
324 h225rassrt_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
325 {
326         char *filter;
327         char str[256];
328
329         filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
330         if(filter[0]==0){
331                 gtk_h225rassrt_init("h225,srt");
332         } else {
333                 sprintf(str,"h225,srt,%s", filter);
334                 gtk_h225rassrt_init(str);
335         }
336 }
337
338
339 static void
340 gtk_h225rassrt_cb(GtkWidget *w _U_, gpointer d _U_)
341 {
342         char *filter;
343         char *title;
344         GtkWidget *dlg_box;
345         GtkWidget *filter_box, *filter_label;
346         GtkWidget *bbox, *start_button, *cancel_button;
347
348         /* if the window is already open, bring it to front */
349         if(dlg){
350                 gdk_window_raise(dlg->window);
351                 return;
352         }
353
354         title = g_strdup_printf("Ethereal: H.225 RAS Service Response Time: %s", cf_get_display_name(&cfile));
355
356         dlg=dlg_window_new(title);
357         g_free(title);
358         SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
359
360         dlg_box=gtk_vbox_new(FALSE, 10);
361         gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
362         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
363         gtk_widget_show(dlg_box);
364
365         /* Filter box */
366         filter_box=gtk_hbox_new(FALSE, 3);
367
368         /* Filter label */
369         filter_label=gtk_label_new("Filter:");
370         gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
371         gtk_widget_show(filter_label);
372
373         /* Filter entry */
374         filter_entry=gtk_entry_new();
375         gtk_widget_set_usize(filter_entry, 300, -2);
376         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
377         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
378         if(filter){
379                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
380         }
381         gtk_widget_show(filter_entry);
382
383         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
384         gtk_widget_show(filter_box);
385
386         /* button box */
387         bbox = gtk_hbutton_box_new();
388         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
389         gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
390         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
391         gtk_widget_show(bbox);
392
393         /* the start button */
394         start_button=gtk_button_new_with_label("Create Stat");
395         SIGNAL_CONNECT_OBJECT(start_button, "clicked",
396                               h225rassrt_start_button_clicked, NULL);
397         gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
398         GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
399         gtk_widget_grab_default(start_button);
400         gtk_widget_show(start_button);
401
402 #if GTK_MAJOR_VERSION < 2
403         cancel_button=gtk_button_new_with_label("Cancel");
404 #else
405         cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
406 #endif
407         SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
408         GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
409         gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
410         gtk_widget_show(cancel_button);
411
412         /* Catch the "activate" signal on the filter text entry, so that
413            if the user types Return there, we act as if the "Create Stat"
414            button had been selected, as happens if Return is typed if
415            some widget that *doesn't* handle the Return key has the input
416            focus. */
417         dlg_set_activate(filter_entry, start_button);
418
419         /* Catch the "key_press_event" signal in the window, so that we can
420            catch the ESC key being pressed and act as if the "Cancel" button
421            had been selected. */
422         dlg_set_cancel(dlg, cancel_button);
423
424         /* Give the initial focus to the "Filter" entry box. */
425         gtk_widget_grab_focus(filter_entry);
426
427         gtk_widget_show_all(dlg);
428 }
429
430 void
431 register_tap_listener_gtk_h225rassrt(void)
432 {
433         register_ethereal_tap("h225,srt", gtk_h225rassrt_init);
434 }
435
436 void
437 register_tap_menu_gtk_h225rassrt(void)
438 {
439         register_tap_menu_item("Statistics/Service Response Time/ITU-T H.225 RAS ...",
440             gtk_h225rassrt_cb, NULL, NULL);
441 }