Rename the tap_dfilter_dlg.[ch] files to reflect that they can do more
[obnox/wireshark/wip.git] / gtk / sip_stat.c
1 /* sip_stat.c
2  * sip_stat   2004 Martin Mathieson
3  *
4  * $Id$
5  * Copied from http_stat.c
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
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 #include <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include <epan/packet_info.h>
34 #include <epan/epan.h>
35 #include <epan/tap.h>
36 #include <epan/dissectors/packet-sip.h>
37
38 #include "../simple_dialog.h"
39 #include "../globals.h"
40 #include "../stat_menu.h"
41
42 #include "gtk/gui_utils.h"
43 #include "gtk/dlg_utils.h"
44 #include "gtk/tap_param_dlg.h"
45 #include "gtk/main.h"
46
47
48 #define SUM_STR_MAX     1024
49
50 /* Used to keep track of the statistics for an entire program interface */
51 typedef struct _sip_stats_t {
52     char        *filter;
53     GtkWidget   *win;
54     GHashTable  *hash_responses;
55     GHashTable  *hash_requests;
56     guint32         packets;        /* number of sip packets, including continuations */
57     guint32     resent_packets;
58         guint32         average_setup_time;
59         guint32         max_setup_time;
60         guint32         min_setup_time;
61         guint32         no_of_completed_calls;
62         guint64         total_setup_time;
63     GtkWidget   *packets_label;
64     GtkWidget   *resent_label;
65     GtkWidget   *average_setup_time_label;
66
67     GtkWidget   *request_box;           /* container for INVITE, ... */
68
69     GtkWidget   *informational_table;   /* Status code between 100 and 199 */
70     GtkWidget   *success_table;         /*   200 and 299 */
71     GtkWidget   *redirection_table;         /*   300 and 399 */
72     GtkWidget   *client_error_table;    /*   400 and 499 */
73     GtkWidget   *server_errors_table;   /*   500 and 599 */
74     GtkWidget   *global_failures_table; /*   600 and 699 */
75 } sipstat_t;
76
77 /* Used to keep track of the stats for a specific response code
78  * for example it can be { 3, 404, "Not Found" ,...}
79  * which means we captured 3 reply sip/1.1 404 Not Found */
80 typedef struct _sip_response_code_t {
81     guint32      packets;               /* 3 */
82     guint        response_code;         /* 404 */
83     const gchar *name;                  /* "Not Found" */
84     GtkWidget   *widget;                /* Label where we display it */
85     GtkWidget   *table;                 /* Table in which we put it,
86                                            e.g. client_error_table */
87     sipstat_t   *sp;                    /* Pointer back to main struct */
88 } sip_response_code_t;
89
90 /* Used to keep track of the stats for a specific request string */
91 typedef struct _sip_request_method_t {
92     gchar               *response;              /* eg. : INVITE */
93     guint32              packets;
94     GtkWidget   *widget;
95     sipstat_t   *sp;                /* Pointer back to main struct */
96 } sip_request_method_t;
97
98 /* TODO: extra codes to be added from SIP extensions? */
99 static const value_string vals_status_code[] = {
100     { 100, "Trying"},
101     { 180, "Ringing"},
102     { 181, "Call Is Being Forwarded"},
103     { 182, "Queued"},
104     { 183, "Session Progress"},
105     { 199, "Informational - Others" },
106
107     { 200, "OK"},
108     { 202, "Accepted"},
109     { 204, "No Notification"},
110     { 299, "Success - Others"}, /* used to keep track of other Success packets */
111
112     { 300, "Multiple Choices"},
113     { 301, "Moved Permanently"},
114     { 302, "Moved Temporarily"},
115     { 305, "Use Proxy"},
116     { 380, "Alternative Service"},
117     { 399, "Redirection - Others"},
118
119     { 400, "Bad Request"},
120     { 401, "Unauthorized"},
121     { 402, "Payment Required"},
122     { 403, "Forbidden"},
123     { 404, "Not Found"},
124     { 405, "Method Not Allowed"},
125     { 406, "Not Acceptable"},
126     { 407, "Proxy Authentication Required"},
127     { 408, "Request Timeout"},
128     { 410, "Gone"},
129     { 412, "Conditional Request Failed"},
130     { 413, "Request Entity Too Large"},
131     { 414, "Request-URI Too Long"},
132     { 415, "Unsupported Media Type"},
133     { 416, "Unsupported URI Scheme"},
134     { 420, "Bad Extension"},
135     { 421, "Extension Required"},
136     { 422, "Session Timer Too Small"},
137     { 423, "Interval Too Brief"},
138     { 428, "Use Identity Header"},
139     { 429, "Provide Referrer Identity"},
140     { 430, "Flow Failed"},
141     { 433, "Anonymity Disallowed"},
142     { 436, "Bad Identity-Info"},
143     { 437, "Unsupported Certificate"},
144     { 438, "Invalid Identity Header"},
145     { 439, "First Hop Lacks Outbound Support"},
146     { 440, "Max-Breadth Exceeded"},
147     { 470, "Consent Needed"},
148     { 480, "Temporarily Unavailable"},
149     { 481, "Call/Transaction Does Not Exist"},
150     { 482, "Loop Detected"},
151     { 483, "Too Many Hops"},
152     { 484, "Address Incomplete"},
153     { 485, "Ambiguous"},
154     { 486, "Busy Here"},
155     { 487, "Request Terminated"},
156     { 488, "Not Acceptable Here"},
157     { 489, "Bad Event"},
158     { 491, "Request Pending"},
159     { 493, "Undecipherable"},
160     { 494, "Security Agreement Required"},
161     { 499, "Client Error - Others"},
162
163     { 500, "Server Internal Error"},
164     { 501, "Not Implemented"},
165     { 502, "Bad Gateway"},
166     { 503, "Service Unavailable"},
167     { 504, "Server Time-out"},
168     { 505, "Version Not Supported"},
169     { 513, "Message Too Large"},
170     { 599, "Server Error - Others"},
171
172     { 600, "Busy Everywhere"},
173     { 603, "Decline"},
174     { 604, "Does Not Exist Anywhere"},
175     { 606, "Not Acceptable"},
176     { 699, "Global Failure - Others"},
177
178     { 0,        NULL}
179 };
180
181 void register_tap_listener_gtksipstat(void);
182
183
184 /* Create tables for responses and requests */
185 static void
186 sip_init_hash(sipstat_t *sp)
187 {
188     int i;
189
190     /* Create responses table */
191     sp->hash_responses = g_hash_table_new(g_int_hash, g_int_equal);
192
193     /* Add all response codes */
194     for (i=0 ; vals_status_code[i].strptr ; i++)
195     {
196         gint *key = g_malloc (sizeof(gint));
197         sip_response_code_t *sc = g_malloc (sizeof(sip_response_code_t));
198         *key = vals_status_code[i].value;
199         sc->packets=0;
200         sc->response_code =  *key;
201         sc->name=vals_status_code[i].strptr;
202         sc->widget=NULL;
203         sc->table=NULL;
204         sc->sp = sp;
205         g_hash_table_insert(sc->sp->hash_responses, key, sc);
206     }
207
208     /* Create empty requests table */
209     sp->hash_requests = g_hash_table_new(g_str_hash, g_str_equal);
210 }
211
212 /* Draw the entry for an individual request message */
213 static void
214 sip_draw_hash_requests(gchar *key _U_ , sip_request_method_t *data, gchar * unused _U_)
215 {
216     gchar string_buff[SUM_STR_MAX];
217
218     g_assert(data!=NULL);
219
220     if (data->packets==0)
221     {
222         return;
223     }
224
225     /* Build string showing method and count */
226     g_snprintf(string_buff, sizeof(string_buff),
227                "     %-11s : %3d packets", data->response, data->packets);
228     if (data->widget==NULL)
229     {
230         /* Create new label */
231         data->widget=gtk_label_new(string_buff);
232         gtk_misc_set_alignment(GTK_MISC(data->widget), 0.0f, 0.5f);
233         gtk_box_pack_start(GTK_BOX(data->sp->request_box), data->widget,FALSE,FALSE, 0);
234         gtk_widget_show(data->widget);
235     }
236     else
237     {
238         /* Update existing label */
239          gtk_label_set_text(GTK_LABEL(data->widget), string_buff);
240     }
241 }
242
243 /* Draw an individual response entry */
244 static void
245 sip_draw_hash_responses(gint * key _U_ , sip_response_code_t *data, gchar * unused _U_)
246 {
247     gchar string_buff[SUM_STR_MAX];
248
249     g_assert(data!=NULL);
250
251     if (data->packets==0)
252     {
253         return;
254     }
255
256     /* Create an entry in the relevant box of the window */
257     if (data->widget==NULL)
258     {
259         guint16 x;
260         GtkWidget *tmp;
261         guint i = data->response_code;
262
263         /* Out of valid range - ignore */
264         if ((i<100)||(i>=700))
265         {
266             return;
267         }
268
269         /* Find the table matching the code */
270         if (i<200)
271         {
272             data->table = data->sp->informational_table;
273         }
274         else if (i<300)
275         {
276             data->table = data->sp->success_table;
277         }
278         else if (i<400)
279         {
280             data->table = data->sp->redirection_table;
281         }
282         else if (i<500)
283         {
284             data->table = data->sp->client_error_table;
285         }
286         else if (i < 600)
287         {
288             data->table = data->sp->server_errors_table;
289         }
290         else
291         {
292             data->table = data->sp->global_failures_table;
293         }
294
295         /* Get number of rows in table */
296         x = GTK_TABLE(data->table)->nrows;
297
298         /* Create a new label with this response, e.g. "SIP 180 Ringing" */
299         g_snprintf(string_buff, sizeof(string_buff),
300                    "SIP %3d %s ", data->response_code, data->name);
301         tmp = gtk_label_new(string_buff);
302
303         /* Insert the label in the correct place in the table */
304         gtk_table_attach_defaults(GTK_TABLE(data->table), tmp,  0, 1, x, x+1);
305         gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT);
306         gtk_widget_show(tmp);
307
308         /* Show number of packets */
309         g_snprintf(string_buff, sizeof(string_buff), "%9d", data->packets);
310         data->widget=gtk_label_new(string_buff);
311
312         /* Show this widget in the right place */
313         gtk_table_attach_defaults(GTK_TABLE(data->table), data->widget, 1, 2,x,x+1);
314         gtk_label_set_justify(GTK_LABEL(data->widget), GTK_JUSTIFY_RIGHT);
315         gtk_widget_show(data->widget);
316
317         gtk_table_resize(GTK_TABLE(data->table), x+1, 4);
318
319     } else
320     {
321         /* Just update the existing label string */
322         g_snprintf(string_buff, sizeof(string_buff), "%9d", data->packets);
323          gtk_label_set_text(GTK_LABEL(data->widget), string_buff);
324     }
325 }
326
327
328
329 static void
330 sip_free_hash(gpointer key, gpointer value, gpointer user_data _U_)
331 {
332     g_free(key);
333     g_free(value);
334 }
335
336 static void
337 sip_reset_hash_responses(gchar *key _U_ , sip_response_code_t *data, gpointer ptr _U_)
338 {
339     data->packets = 0;
340 }
341
342 static void
343 sip_reset_hash_requests(gchar *key _U_ , sip_request_method_t *data, gpointer ptr _U_)
344 {
345     data->packets = 0;
346 }
347
348 static void
349 sipstat_reset(void *psp)
350 {
351     sipstat_t *sp = psp;
352     if (sp)
353     {
354         sp->packets = 0;
355         sp->resent_packets = 0;
356                 sp->average_setup_time = 0;
357                 sp->max_setup_time = 0;
358                 sp->max_setup_time = 0;
359                 sp->no_of_completed_calls = 0;
360                 sp->total_setup_time = 0;
361         g_hash_table_foreach(sp->hash_responses, (GHFunc)sip_reset_hash_responses, NULL);
362         g_hash_table_foreach(sp->hash_requests, (GHFunc)sip_reset_hash_requests, NULL);
363     }
364 }
365
366 /* Main entry point to SIP tap */
367 static int
368 sipstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
369 {
370     const sip_info_value_t *value=pri;
371     sipstat_t *sp = (sipstat_t *)psp;
372
373     /* Total number of packets, including continuation packets */
374     sp->packets++;
375
376     /* Update resent count if flag set */
377     if (value->resend)
378     {
379         sp->resent_packets++;
380     }
381
382         /* Calculate average setup time */
383         if (value->setup_time){
384                 sp->no_of_completed_calls++;
385                 /* Check if it's the first value */
386                 if ( sp->total_setup_time == 0 ){
387                         sp->average_setup_time = value->setup_time;
388                         sp->total_setup_time = value->setup_time;
389                         sp->max_setup_time = value->setup_time;
390                         sp->min_setup_time = value->setup_time;
391                 }else{
392                         sp->total_setup_time = sp->total_setup_time + value->setup_time;
393                         if (sp->max_setup_time < value->setup_time){
394                                 sp->max_setup_time = value->setup_time;
395                         }
396                         if (sp->min_setup_time > value->setup_time){
397                                 sp->min_setup_time = value->setup_time;
398                         }
399                         /* Calculate average */
400                         sp->average_setup_time = (guint32)(sp->total_setup_time / sp->no_of_completed_calls);
401                 }
402         }
403
404     /* Looking at both requests and responses */
405     if (value->response_code != 0)
406     {
407         /* Responses */
408         guint *key = g_malloc(sizeof(guint));
409         sip_response_code_t *sc;
410
411         /* Look up response code in hash table */
412         *key = value->response_code;
413         sc = g_hash_table_lookup(sp->hash_responses, key);
414         if (sc==NULL)
415         {
416             /* Non-standard status code ; we classify it as others
417              * in the relevant category
418              * (Informational,Success,Redirection,Client Error,Server Error,Global Failure)
419              */
420             int i = value->response_code;
421             if ((i<100) || (i>=700))
422             {
423                 /* Forget about crazy values */
424                 return 0;
425             }
426             else if (i<200)
427             {
428                 *key=199;       /* Hopefully, this status code will never be used */
429             }
430             else if (i<300)
431             {
432                 *key=299;
433             }
434             else if (i<400)
435             {
436                 *key=399;
437             }
438             else if (i<500)
439             {
440                 *key=499;
441             }
442             else if (i<600)
443             {
444                 *key=599;
445             }
446             else
447             {
448                 *key = 699;
449             }
450
451             /* Now look up this fallback code to get its text description */
452             sc = g_hash_table_lookup(sp->hash_responses, key);
453             if (sc==NULL)
454             {
455                 return 0;
456             }
457         }
458         sc->packets++;
459     }
460     else if (value->request_method)
461     {
462         /* Requests */
463         sip_request_method_t *sc;
464
465         /* Look up the request method in the table */
466         sc = g_hash_table_lookup(sp->hash_requests, value->request_method);
467         if (sc == NULL)
468         {
469             /* First of this type. Create structure and initialise */
470             sc=g_malloc(sizeof(sip_request_method_t));
471             sc->response = g_strdup(value->request_method);
472             sc->packets = 1;
473             sc->widget = NULL;
474             sc->sp = sp;
475             /* Insert it into request table */
476             g_hash_table_insert(sp->hash_requests, sc->response, sc);
477         }
478         else
479         {
480             /* Already existed, just update count for that method */
481             sc->packets++;
482         }
483         /* g_free(value->request_method); */
484     }
485     else
486     {
487         /* No request method set. Just ignore */
488         return 0;
489     }
490
491     return 1;
492 }
493
494 /* Redraw the whole stats window */
495 static void
496 sipstat_draw(void *psp)
497 {
498     gchar      string_buff[SUM_STR_MAX];
499     sipstat_t *sp=psp;
500
501     /* Set summary label */
502     g_snprintf(string_buff, sizeof(string_buff),
503                 "SIP stats (%d packets)", sp->packets);
504      gtk_label_set_text(GTK_LABEL(sp->packets_label), string_buff);
505
506     /* Set resend count label */
507     g_snprintf(string_buff, sizeof(string_buff),
508                 "(%d resent packets)", sp->resent_packets);
509      gtk_label_set_text(GTK_LABEL(sp->resent_label), string_buff);
510
511     /* Draw responses and requests from their tables */
512     g_hash_table_foreach(sp->hash_responses, (GHFunc)sip_draw_hash_responses, NULL);
513     g_hash_table_foreach(sp->hash_requests,  (GHFunc)sip_draw_hash_requests, NULL);
514
515     /* Set resend count label */
516     g_snprintf(string_buff, sizeof(string_buff),
517                 "Average setup time %d ms\n Min %d ms\n Max %d ms", sp->average_setup_time, sp->min_setup_time, sp->max_setup_time);
518      gtk_label_set_text(GTK_LABEL(sp->average_setup_time_label), string_buff);
519
520         gtk_widget_show_all(sp->win);
521 }
522
523
524 /* since the gtk2 implementation of tap is multithreaded we must protect
525  * remove_tap_listener() from modifying the list while draw_tap_listener()
526  * is running.  the other protected block is in main.c
527  *
528  * there should not be any other critical regions in gtk2
529  */
530 /* When window is destroyed, clean up */
531 static void
532 win_destroy_cb(GtkWindow *win _U_, gpointer data)
533 {
534     sipstat_t *sp=(sipstat_t *)data;
535
536     protect_thread_critical_region();
537     remove_tap_listener(sp);
538     unprotect_thread_critical_region();
539
540     g_hash_table_foreach(sp->hash_responses, (GHFunc)sip_free_hash, NULL);
541     g_hash_table_destroy(sp->hash_responses);
542     g_hash_table_foreach(sp->hash_requests, (GHFunc)sip_free_hash, NULL);
543     g_hash_table_destroy(sp->hash_requests);
544     g_free(sp->filter);
545     g_free(sp);
546 }
547
548
549 /* Create a new instance of gtk_sipstat. */
550 static void
551 gtk_sipstat_init(const char *optarg, void *userdata _U_)
552 {
553     sipstat_t *sp;
554     const char *filter = NULL;
555     GString     *error_string;
556     char *title = NULL;
557     GtkWidget  *main_vb, *separator,
558                *informational_fr, *success_fr, *redirection_fr,
559                *client_errors_fr, *server_errors_fr, *global_failures_fr,
560                *request_fr;
561     GtkWidget   *bt_close;
562     GtkWidget   *bbox;
563
564
565     if (strncmp (optarg, "sip,stat,", 9) == 0)
566     {
567         /* Skip those characters from filter to display */
568         filter=optarg + 9;
569     }
570     else
571     {
572         /* No filter */
573         filter = NULL;
574     }
575
576     /* Create sip stats window structure */
577     sp = g_malloc(sizeof(sipstat_t));
578         sp->win = dlg_window_new("sip-stat");  /* transient_for top_level */
579         gtk_window_set_destroy_with_parent (GTK_WINDOW(sp->win), TRUE);
580
581     /* Set title to include any filter given */
582     if (filter)
583     {
584         sp->filter = g_strdup(filter);
585         title = g_strdup_printf("SIP statistics with filter: %s", filter);
586     }
587     else
588     {
589         sp->filter = NULL;
590         title = g_strdup("SIP statistics");
591     }
592
593     gtk_window_set_title(GTK_WINDOW(sp->win), title);
594     g_free(title);
595
596
597     /* Create container for all widgets */
598     main_vb = gtk_vbox_new(FALSE, 12);
599     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 12);
600     gtk_container_add(GTK_CONTAINER(sp->win), main_vb);
601
602     /* Initialise & show number of packets */
603     sp->packets = 0;
604     sp->packets_label = gtk_label_new("SIP stats (0 SIP packets)");
605     gtk_container_add(GTK_CONTAINER(main_vb), sp->packets_label);
606
607     sp->resent_packets = 0;
608     sp->resent_label = gtk_label_new("(0 resent packets)");
609     gtk_container_add(GTK_CONTAINER(main_vb), sp->resent_label);
610     gtk_widget_show(sp->resent_label);
611
612
613     /* Informational response frame */
614     informational_fr = gtk_frame_new("Informational  SIP 1xx");
615     gtk_container_add(GTK_CONTAINER(main_vb), informational_fr);
616
617     /* Information table (within that frame) */
618     sp->informational_table = gtk_table_new(0, 2, FALSE);
619     gtk_container_add(GTK_CONTAINER(informational_fr), sp->informational_table);
620
621     /* Success table and frame */
622     success_fr = gtk_frame_new  ("Success         SIP 2xx");
623     gtk_container_add(GTK_CONTAINER(main_vb), success_fr);
624
625     sp->success_table = gtk_table_new(0, 2, FALSE);
626     gtk_container_add(GTK_CONTAINER(success_fr), sp->success_table);
627
628     /* Redirection table and frame */
629     redirection_fr = gtk_frame_new      ("Redirection     SIP 3xx");
630     gtk_container_add(GTK_CONTAINER(main_vb), redirection_fr);
631
632     sp->redirection_table = gtk_table_new(0, 2, FALSE);
633     gtk_container_add(GTK_CONTAINER(redirection_fr), sp->redirection_table);
634
635     /* Client Errors table and frame */
636     client_errors_fr = gtk_frame_new("Client errors  SIP 4xx");
637     gtk_container_add(GTK_CONTAINER(main_vb), client_errors_fr);
638
639     sp->client_error_table = gtk_table_new(0, 2, FALSE);
640     gtk_container_add(GTK_CONTAINER(client_errors_fr), sp->client_error_table);
641
642     /* Server Errors table and frame */
643     server_errors_fr = gtk_frame_new("Server errors  SIP 5xx");
644     gtk_container_add(GTK_CONTAINER(main_vb), server_errors_fr);
645
646     sp->server_errors_table = gtk_table_new(0, 2, FALSE);
647     gtk_container_add(GTK_CONTAINER(server_errors_fr), sp->server_errors_table);
648
649     /* Global Failures table and frame */
650     global_failures_fr = gtk_frame_new("Global failures  SIP 6xx");
651     gtk_container_add(GTK_CONTAINER(main_vb), global_failures_fr);
652
653     sp->global_failures_table = gtk_table_new(0, 2, FALSE);
654     gtk_container_add(GTK_CONTAINER(global_failures_fr), sp->global_failures_table);
655
656
657     /* Separator between requests and responses */
658     separator = gtk_hseparator_new();
659     gtk_container_add(GTK_CONTAINER(main_vb), separator);
660
661     /* Request table and frame */
662     request_fr = gtk_frame_new("List of request methods");
663     gtk_container_add(GTK_CONTAINER(main_vb), request_fr);
664     gtk_container_set_border_width(GTK_CONTAINER(request_fr), 0);
665
666     sp->request_box = gtk_vbox_new(FALSE, 10);
667     gtk_container_add(GTK_CONTAINER(request_fr), sp->request_box);
668
669     sp->average_setup_time = 0;
670         sp->max_setup_time =0;
671         sp->min_setup_time =0;
672     sp->average_setup_time_label = gtk_label_new("(Not calculated)");
673     gtk_container_add(GTK_CONTAINER(main_vb), sp->average_setup_time_label);
674     gtk_widget_show(sp->average_setup_time_label);
675
676
677     /* Register this tap listener now */
678     error_string = register_tap_listener("sip",
679                                          sp,
680                                          filter,
681                                          0,
682                                          sipstat_reset,
683                                          sipstat_packet,
684                                          sipstat_draw);
685     if (error_string)
686     {
687         /* Error.  We failed to attach to the tap. Clean up */
688         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
689         g_free(sp->filter);
690         g_free(sp);
691         g_string_free(error_string, TRUE);
692         return;
693     }
694
695         /* Button row. */
696     bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
697     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
698
699     bt_close = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
700     window_set_cancel_button(sp->win, bt_close, window_cancel_button_cb);
701
702     g_signal_connect(sp->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
703     g_signal_connect(sp->win, "destroy", G_CALLBACK(win_destroy_cb), sp);
704
705     /* Display up-to-date contents */
706     gtk_widget_show_all(sp->win);
707     window_present(sp->win);
708
709     sip_init_hash(sp);
710     cf_retap_packets(&cfile);
711     gdk_window_raise(sp->win->window);
712 }
713
714 static tap_param sip_stat_params[] = {
715         { PARAM_FILTER, "Filter", NULL }
716 };
717
718 static tap_param_dlg sip_stat_dlg = {
719         "SIP Packet Counter",
720         "sip,stat",
721         gtk_sipstat_init,
722         -1,
723         G_N_ELEMENTS(sip_stat_params),
724         sip_stat_params
725 };
726
727 /* Register this tap listener and add menu item. */
728 void
729 register_tap_listener_gtksipstat(void)
730 {
731     register_dfilter_stat(&sip_stat_dlg, "_SIP", REGISTER_STAT_GROUP_TELEPHONY);
732 }