2 * rpc_stat 2002 Ronnie Sahlberg
4 * $Id: rpc_stat.c,v 1.24 2003/10/27 01:20:16 sharpe Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
25 /* This module provides rpc call/reply SRT (Server Response Time) statistics
28 * It serves as an example on how to use the tap api.
36 #include "epan/packet_info.h"
37 #include "epan/epan.h"
39 #include "simple_dialog.h"
40 #include "dlg_utils.h"
42 #include "../register.h"
43 #include "packet-rpc.h"
44 #include "../globals.h"
45 #include "filter_prefs.h"
46 #include "compat_macros.h"
47 #include "service_response_time_table.h"
49 extern GtkWidget *main_display_filter_widget;
51 /* used to keep track of the statistics for an entire program interface */
52 typedef struct _rpcstat_t {
54 srt_stat_table srt_table;
58 guint32 num_procedures;
62 rpcstat_gen_title(rpcstat_t *rs)
66 title = g_strdup_printf("ONC-RPC Service Response Time statistics for %s version %d: %s",
67 rs->prog, rs->version, cf_get_display_name(&cfile));
72 rpcstat_set_title(rpcstat_t *rs)
76 title = rpcstat_gen_title(rs);
77 gtk_window_set_title(GTK_WINDOW(rs->win), title);
82 rpcstat_reset(rpcstat_t *rs)
84 reset_srt_table_data(&rs->srt_table);
85 rpcstat_set_title(rs);
90 rpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, rpc_call_info_value *ri)
92 if(ri->proc>=rs->num_procedures){
93 /* dont handle this since its outside of known table */
96 /* we are only interested in reply packets */
100 /* we are only interested in certain program/versions */
101 if( (ri->prog!=rs->program) || (ri->vers!=rs->version) ){
105 add_srt_table_data(&rs->srt_table, ri->proc, &ri->req_time, pinfo);
111 rpcstat_draw(rpcstat_t *rs)
113 draw_srt_table_data(&rs->srt_table);
118 static guint32 rpc_program=0;
119 static guint32 rpc_version=0;
120 static gint32 rpc_min_vers=-1;
121 static gint32 rpc_max_vers=-1;
122 static gint32 rpc_min_proc=-1;
123 static gint32 rpc_max_proc=-1;
126 rpcstat_find_procs(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
128 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
130 if(k->prog!=rpc_program){
133 if(k->vers!=rpc_version){
136 if(rpc_min_proc==-1){
137 rpc_min_proc=k->proc;
138 rpc_max_proc=k->proc;
140 if((gint32)k->proc<rpc_min_proc){
141 rpc_min_proc=k->proc;
143 if((gint32)k->proc>rpc_max_proc){
144 rpc_max_proc=k->proc;
151 rpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
153 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
155 if(k->prog!=rpc_program){
158 if(rpc_min_vers==-1){
159 rpc_min_vers=k->vers;
160 rpc_max_vers=k->vers;
162 if((gint32)k->vers<rpc_min_vers){
163 rpc_min_vers=k->vers;
165 if((gint32)k->vers>rpc_max_vers){
166 rpc_max_vers=k->vers;
172 /* since the gtk2 implementation of tap is multithreaded we must protect
173 * remove_tap_listener() from modifying the list while draw_tap_listener()
174 * is running. the other protected block is in main.c
176 * there should not be any other critical regions in gtk2
178 void protect_thread_critical_region(void);
179 void unprotect_thread_critical_region(void);
181 win_destroy_cb(GtkWindow *win _U_, gpointer data)
183 rpcstat_t *rs=(rpcstat_t *)data;
185 protect_thread_critical_region();
186 remove_tap_listener(rs);
187 unprotect_thread_critical_region();
189 free_srt_table_data(&rs->srt_table);
193 /* When called, this function will create a new instance of gtk2-rpcstat.
196 gtk_rpcstat_init(char *optarg)
201 char filter_string[256];
203 GtkWidget *stat_label;
204 GtkWidget *filter_label;
205 int program, version, pos;
207 GString *error_string;
209 header_field_info *hfi;
212 if(sscanf(optarg,"rpc,srt,%d,%d,%n",&program,&version,&pos)==2){
219 fprintf(stderr, "ethereal: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
225 rs=g_malloc(sizeof(rpcstat_t));
226 rs->prog=rpc_prog_name(rpc_program);
227 rs->program=rpc_program;
228 rs->version=rpc_version;
229 hf_index=rpc_prog_hf(rpc_program, rpc_version);
230 hfi=proto_registrar_get_nth(hf_index);
232 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
233 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
234 rpcstat_set_title(rs);
235 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
237 vbox=gtk_vbox_new(FALSE, 0);
238 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
239 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
240 gtk_widget_show(vbox);
242 title_string = rpcstat_gen_title(rs);
243 stat_label=gtk_label_new(title_string);
244 g_free(title_string);
245 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
246 gtk_widget_show(stat_label);
248 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
249 filter_label=gtk_label_new(filter_string);
250 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
251 gtk_widget_show(filter_label);
255 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
256 rs->num_procedures=rpc_max_proc+1;
258 /* We must display TOP LEVEL Widget before calling init_srt_table() */
259 gtk_widget_show(rs->win);
261 init_srt_table(&rs->srt_table, rpc_max_proc+1, vbox, hfi->abbrev);
263 for(i=0;i<rs->num_procedures;i++){
264 init_srt_table_row(&rs->srt_table, i, rpc_proc_name(rpc_program, rpc_version, i));
268 error_string=register_tap_listener("rpc", rs, filter, (void*)rpcstat_reset, (void*)rpcstat_packet, (void*)rpcstat_draw);
270 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
271 g_string_free(error_string, TRUE);
272 free_srt_table_data(&rs->srt_table);
278 gtk_widget_show_all(rs->win);
279 redissect_packets(&cfile);
285 static GtkWidget *dlg=NULL;
286 static GtkWidget *prog_menu;
287 static GtkWidget *vers_opt, *vers_menu;
288 static GtkWidget *filter_entry;
292 rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
297 str = g_string_new("rpc,srt");
298 g_string_sprintfa(str, ",%d,%d", rpc_program, rpc_version);
299 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
301 g_string_sprintfa(str, ",%s", filter);
304 gtk_rpcstat_init(str->str);
305 g_string_free(str, TRUE);
310 rpcstat_version_select(GtkWidget *item _U_, gpointer key)
320 rpcstat_program_select(GtkWidget *item _U_, gpointer key)
322 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
327 /* change version menu */
329 gtk_object_destroy(GTK_OBJECT(vers_menu));
330 vers_menu=gtk_menu_new();
333 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
334 rpc_version=rpc_min_vers;
335 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
336 GtkWidget *menu_item;
339 menu_item=gtk_menu_item_new_with_label(vs);
340 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
343 gtk_widget_show(menu_item);
344 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
346 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
350 rpcstat_list_programs(gpointer *key, gpointer *value, gpointer *user_data _U_)
352 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
353 rpc_prog_info_value *v=(rpc_prog_info_value *)value;
354 GtkWidget *menu_item;
356 menu_item=gtk_menu_item_new_with_label(v->progname);
357 SIGNAL_CONNECT(menu_item, "activate", rpcstat_program_select, k);
359 gtk_widget_show(menu_item);
360 gtk_menu_append(GTK_MENU(prog_menu), menu_item);
376 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
378 gtk_widget_destroy(GTK_WIDGET(parent_w));
382 gtk_rpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
385 GtkWidget *prog_box, *prog_label, *prog_opt;
386 GtkWidget *vers_label;
387 GtkWidget *filter_box, *filter_bt;
388 GtkWidget *bbox, *start_button, *cancel_button;
391 static construct_args_t args = {
392 "Service Response Time Statistics Filter",
397 /* if the window is already open, bring it to front */
399 gdk_window_raise(dlg->window);
403 dlg=dlg_window_new("Ethereal: Compute ONC-RPC SRT statistics");
404 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
406 dlg_box=gtk_vbox_new(FALSE, 10);
407 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
408 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
409 gtk_widget_show(dlg_box);
412 prog_box=gtk_hbox_new(FALSE, 10);
415 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
416 prog_label=gtk_label_new("Program:");
417 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
418 gtk_widget_show(prog_label);
421 prog_opt=gtk_option_menu_new();
422 prog_menu=gtk_menu_new();
423 g_hash_table_foreach(rpc_progs, (GHFunc)rpcstat_list_programs, NULL);
424 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
425 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
426 gtk_widget_show(prog_opt);
429 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
430 vers_label=gtk_label_new("Version:");
431 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
432 gtk_widget_show(vers_label);
435 vers_opt=gtk_option_menu_new();
436 vers_menu=gtk_menu_new();
439 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
440 rpc_version=rpc_min_vers;
441 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
442 GtkWidget *menu_item;
445 menu_item=gtk_menu_item_new_with_label(vs);
446 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
449 gtk_widget_show(menu_item);
450 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
452 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
453 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
454 gtk_widget_show(vers_opt);
456 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
457 gtk_widget_show(prog_box);
460 filter_box=gtk_hbox_new(FALSE, 3);
463 filter_bt=gtk_button_new_with_label("Filter:");
464 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
465 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
466 gtk_widget_show(filter_bt);
469 filter_entry=gtk_entry_new();
470 gtk_widget_set_usize(filter_entry, 300, -2);
472 /* filter prefs dialog */
473 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_entry);
474 /* filter prefs dialog */
476 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
477 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
479 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
481 gtk_widget_show(filter_entry);
483 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
484 gtk_widget_show(filter_box);
487 bbox=gtk_hbutton_box_new();
488 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
489 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
490 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
491 gtk_widget_show(bbox);
493 /* the start button */
494 start_button=gtk_button_new_with_label("Create Stat");
495 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
496 rpcstat_start_button_clicked, NULL);
497 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
498 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
499 gtk_widget_grab_default(start_button);
500 gtk_widget_show(start_button);
502 #if GTK_MAJOR_VERSION < 2
503 cancel_button=gtk_button_new_with_label("Cancel");
505 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
507 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
508 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
509 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
510 gtk_widget_show(cancel_button);
512 /* Catch the "activate" signal on the filter text entry, so that
513 if the user types Return there, we act as if the "Create Stat"
514 button had been selected, as happens if Return is typed if some
515 widget that *doesn't* handle the Return key has the input
517 dlg_set_activate(filter_entry, start_button);
519 /* Catch the "key_press_event" signal in the window, so that we can
520 catch the ESC key being pressed and act as if the "Cancel" button
521 had been selected. */
522 dlg_set_cancel(dlg, cancel_button);
524 /* Give the initial focus to the "Filter" entry box. */
525 gtk_widget_grab_focus(filter_entry);
527 gtk_widget_show_all(dlg);
532 register_tap_listener_gtkrpcstat(void)
534 register_ethereal_tap("rpc,srt,", gtk_rpcstat_init);
538 register_tap_menu_gtkrpcstat(void)
540 register_tap_menu_item("Statistics/Service Response Time/ONC-RPC...",
541 gtk_rpcstat_cb, NULL, NULL);