"gtk_window_set_default_size()" takes a GtkWindow *, not a GtkWidget *,
[obnox/wireshark/wip.git] / gtk / rpc_stat.c
1 /* rpc_stat.c
2  * rpc_stat   2002 Ronnie Sahlberg
3  *
4  * $Id: rpc_stat.c,v 1.11 2003/06/21 09:50:19 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 /* This module provides rpc call/reply SRT (Server Response Time) statistics 
26  * to ethereal.
27  *
28  * It serves as an example on how to use the tap api.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <gtk/gtk.h>
36 #include "menu.h"
37 #include "epan/packet_info.h"
38 #include "simple_dialog.h"
39 #include "tap.h"
40 #include "../register.h"
41 #include "packet-rpc.h"
42 #include "../globals.h"
43 #include "compat_macros.h"
44 #include "service_response_time_table.h"
45
46
47 /* used to keep track of the statistics for an entire program interface */
48 typedef struct _rpcstat_t {
49         GtkWidget *win;
50         srt_stat_table srt_table;
51         char *prog;
52         guint32 program;
53         guint32 version;
54         guint32 num_procedures;
55 } rpcstat_t;
56
57
58
59
60 static void
61 rpcstat_reset(rpcstat_t *rs)
62 {
63         reset_srt_table_data(&rs->srt_table);
64 }
65
66
67 static int
68 rpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, rpc_call_info_value *ri)
69 {
70         if(ri->proc>=rs->num_procedures){
71                 /* dont handle this since its outside of known table */
72                 return 0;
73         }
74         /* we are only interested in reply packets */
75         if(ri->request){
76                 return 0;
77         }
78         /* we are only interested in certain program/versions */
79         if( (ri->prog!=rs->program) || (ri->vers!=rs->version) ){
80                 return 0;
81         }
82
83         add_srt_table_data(&rs->srt_table, ri->proc, &ri->req_time, pinfo);
84
85         return 1;
86 }
87
88 static void
89 rpcstat_draw(rpcstat_t *rs)
90 {
91         draw_srt_table_data(&rs->srt_table);
92 }
93
94
95
96 static guint32 rpc_program=0;
97 static guint32 rpc_version=0;
98 static gint32 rpc_min_vers=-1;
99 static gint32 rpc_max_vers=-1;
100 static gint32 rpc_min_proc=-1;
101 static gint32 rpc_max_proc=-1;
102
103 static void *
104 rpcstat_find_procs(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
105 {
106         rpc_proc_info_key *k=(rpc_proc_info_key *)key;
107
108         if(k->prog!=rpc_program){
109                 return NULL;
110         }
111         if(k->vers!=rpc_version){
112                 return NULL;
113         }
114         if(rpc_min_proc==-1){
115                 rpc_min_proc=k->proc;
116                 rpc_max_proc=k->proc;
117         }
118         if((gint32)k->proc<rpc_min_proc){
119                 rpc_min_proc=k->proc;
120         }
121         if((gint32)k->proc>rpc_max_proc){
122                 rpc_max_proc=k->proc;
123         }
124
125         return NULL;
126 }
127
128 static void *
129 rpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
130 {
131         rpc_proc_info_key *k=(rpc_proc_info_key *)key;
132
133         if(k->prog!=rpc_program){
134                 return NULL;
135         }
136         if(rpc_min_vers==-1){
137                 rpc_min_vers=k->vers;
138                 rpc_max_vers=k->vers;
139         }
140         if((gint32)k->vers<rpc_min_vers){
141                 rpc_min_vers=k->vers;
142         }
143         if((gint32)k->vers>rpc_max_vers){
144                 rpc_max_vers=k->vers;
145         }
146
147         return NULL;
148 }
149
150 /* since the gtk2 implementation of tap is multithreaded we must protect
151  * remove_tap_listener() from modifying the list while draw_tap_listener()
152  * is running.  the other protected block is in main.c
153  *
154  * there should not be any other critical regions in gtk2
155  */
156 void protect_thread_critical_region(void);
157 void unprotect_thread_critical_region(void);
158 static void
159 win_destroy_cb(GtkWindow *win _U_, gpointer data)
160 {
161         rpcstat_t *rs=(rpcstat_t *)data;
162
163         protect_thread_critical_region();
164         remove_tap_listener(rs);
165         unprotect_thread_critical_region();
166
167         free_srt_table_data(&rs->srt_table);
168         g_free(rs);
169 }
170
171 /* When called, this function will create a new instance of gtk2-rpcstat.
172  */
173 static void
174 gtk_rpcstat_init(char *optarg)
175 {
176         rpcstat_t *rs;
177         guint32 i;
178         char title_string[60];
179         char filter_string[256];
180         GtkWidget *vbox;
181         GtkWidget *stat_label;
182         GtkWidget *filter_label;
183         int program, version, pos;
184         char *filter=NULL;
185         GString *error_string;
186
187         pos=0;
188         if(sscanf(optarg,"rpc,srt,%d,%d,%n",&program,&version,&pos)==2){
189                 if(pos){
190                         filter=optarg+pos;
191                 } else {
192                         filter=NULL;
193                 }
194         } else {
195                 fprintf(stderr, "ethereal: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
196                 exit(1);
197         }
198
199         rpc_program=program;
200         rpc_version=version;
201         rs=g_malloc(sizeof(rpcstat_t));
202         rs->prog=rpc_prog_name(rpc_program);
203         rs->program=rpc_program;
204         rs->version=rpc_version;
205
206         rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
207         gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
208         sprintf(title_string,"ONC-RPC Service Response Time statistics for %s version %d", rs->prog, rs->version);
209         gtk_window_set_title(GTK_WINDOW(rs->win), title_string);
210         SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
211
212         vbox=gtk_vbox_new(FALSE, 0);
213         gtk_container_add(GTK_CONTAINER(rs->win), vbox);
214         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
215         gtk_widget_show(vbox);
216
217         stat_label=gtk_label_new(title_string);
218         gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
219         gtk_widget_show(stat_label);
220
221         snprintf(filter_string,255,"Filter:%s",filter?filter:"");
222         filter_label=gtk_label_new(filter_string);
223         gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
224         gtk_widget_show(filter_label);
225
226
227         rpc_min_proc=-1;
228         rpc_max_proc=-1;
229         g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
230         rs->num_procedures=rpc_max_proc+1;
231
232         init_srt_table(&rs->srt_table, rpc_max_proc+1, vbox);
233
234         for(i=0;i<rs->num_procedures;i++){
235                 init_srt_table_row(&rs->srt_table, i, rpc_proc_name(rpc_program, rpc_version, i));
236         }
237
238
239         error_string=register_tap_listener("rpc", rs, filter, (void*)rpcstat_reset, (void*)rpcstat_packet, (void*)rpcstat_draw);
240         if(error_string){
241                 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
242                 g_string_free(error_string, TRUE);
243                 free_srt_table_data(&rs->srt_table);
244                 g_free(rs);
245                 return;
246         }
247
248
249         gtk_widget_show_all(rs->win);
250         redissect_packets(&cfile);
251 }
252
253
254
255
256 static GtkWidget *dlg=NULL, *dlg_box;
257 static GtkWidget *prog_box;
258 static GtkWidget *prog_label, *prog_opt, *prog_menu;
259 static GtkWidget *vers_label, *vers_opt, *vers_menu;
260 static GtkWidget *filter_box;
261 static GtkWidget *filter_label, *filter_entry;
262 static GtkWidget *start_button;
263
264
265 static void
266 rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
267 {
268         char *filter;
269         char str[256];
270
271         filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
272         if(filter[0]==0){
273                 sprintf(str, "rpc,srt,%d,%d", rpc_program, rpc_version);
274                 filter="";
275         } else {
276                 sprintf(str, "rpc,srt,%d,%d,%s", rpc_program, rpc_version, filter);
277         }
278         gtk_rpcstat_init(str);
279 }
280
281
282 static void
283 rpcstat_version_select(GtkWidget *item _U_, gpointer key)
284 {
285         int vers=(int)key;
286
287         rpc_version=vers;
288 }
289
290
291
292 static void
293 rpcstat_program_select(GtkWidget *item _U_, gpointer key)
294 {
295         rpc_prog_info_key *k=(rpc_prog_info_key *)key;
296         int i;
297
298         rpc_program=k->prog;
299
300         /* change version menu */
301         rpc_version=0;
302         gtk_object_destroy(GTK_OBJECT(vers_menu));
303         vers_menu=gtk_menu_new();
304         rpc_min_vers=-1;
305         rpc_max_vers=-1;
306         g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
307         rpc_version=rpc_min_vers;
308         for(i=rpc_min_vers;i<=rpc_max_vers;i++){
309                 GtkWidget *menu_item;
310                 char vs[5];
311                 sprintf(vs,"%d",i);
312                 menu_item=gtk_menu_item_new_with_label(vs);
313                 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
314                                i);
315
316                 gtk_widget_show(menu_item);
317                 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
318         }
319         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
320 }
321
322 static void *
323 rpcstat_list_programs(gpointer *key, gpointer *value, gpointer *user_data _U_)
324 {
325         rpc_prog_info_key *k=(rpc_prog_info_key *)key;
326         rpc_prog_info_value *v=(rpc_prog_info_value *)value;
327         GtkWidget *menu_item;
328
329         menu_item=gtk_menu_item_new_with_label(v->progname);
330         SIGNAL_CONNECT(menu_item, "activate", rpcstat_program_select, k);
331
332         gtk_widget_show(menu_item);
333         gtk_menu_append(GTK_MENU(prog_menu), menu_item);
334
335         if(!rpc_program){
336                 rpc_program=k->prog;
337         }
338
339         return NULL;
340 }
341
342 static void
343 dlg_destroy_cb(void)
344 {
345         dlg=NULL;
346 }
347
348 static void
349 gtk_rpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
350 {
351         int i;
352
353         /* if the window is already open, bring it to front */
354         if(dlg){
355                 gdk_window_raise(dlg->window);
356                 return;
357         }
358
359         dlg=gtk_window_new(GTK_WINDOW_TOPLEVEL);
360         gtk_window_set_title(GTK_WINDOW(dlg), "ONC-RPC Service Response Time statistics");
361         SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
362         dlg_box=gtk_vbox_new(FALSE, 0);
363         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
364         gtk_widget_show(dlg_box);
365
366
367         prog_box=gtk_hbox_new(FALSE, 10);
368         /* Program label */
369         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
370         prog_label=gtk_label_new("Program:");
371         gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
372         gtk_widget_show(prog_label);
373
374         /* Program menu */
375         prog_opt=gtk_option_menu_new();
376         prog_menu=gtk_menu_new();
377         g_hash_table_foreach(rpc_progs, (GHFunc)rpcstat_list_programs, NULL);
378         gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
379         gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
380         gtk_widget_show(prog_opt);
381
382         /* Version label */
383         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
384         vers_label=gtk_label_new("Version:");
385         gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
386         gtk_widget_show(vers_label);
387
388         /* Version menu */
389         vers_opt=gtk_option_menu_new();
390         vers_menu=gtk_menu_new();
391         rpc_min_vers=-1;
392         rpc_max_vers=-1;
393         g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
394         rpc_version=rpc_min_vers;
395         for(i=rpc_min_vers;i<=rpc_max_vers;i++){
396                 GtkWidget *menu_item;
397                 char vs[5];
398                 sprintf(vs,"%d",i);
399                 menu_item=gtk_menu_item_new_with_label(vs);
400                 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
401                                i);
402
403                 gtk_widget_show(menu_item);
404                 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
405         }
406
407         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
408         gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
409         gtk_widget_show(vers_opt);
410
411         gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
412         gtk_widget_show(prog_box);
413
414
415         /* filter box */
416         filter_box=gtk_hbox_new(FALSE, 10);
417         /* Filter label */
418         gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10);
419         filter_label=gtk_label_new("Filter:");
420         gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
421         gtk_widget_show(filter_label);
422
423         filter_entry=gtk_entry_new_with_max_length(250);
424         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0);
425         gtk_widget_show(filter_entry);
426         
427         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
428         gtk_widget_show(filter_box);
429
430
431         /* the start button */
432         start_button=gtk_button_new_with_label("Create Stat");
433         SIGNAL_CONNECT_OBJECT(start_button, "clicked",
434                               rpcstat_start_button_clicked, NULL);
435         gtk_box_pack_start(GTK_BOX(dlg_box), start_button, TRUE, TRUE, 0);
436         gtk_widget_show(start_button);
437
438         gtk_widget_show_all(dlg);
439 }
440
441
442 void
443 register_tap_listener_gtkrpcstat(void)
444 {
445         register_ethereal_tap("rpc,srt,", gtk_rpcstat_init);
446 }
447
448 void
449 register_tap_menu_gtkrpcstat(void)
450 {
451         register_tap_menu_item("Service Response Time/ONC-RPC", gtk_rpcstat_cb);
452 }