2 * rpc_stat 2002 Ronnie Sahlberg
4 * $Id: rpc_stat.c,v 1.34 2004/01/21 21:19:34 ulfl 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.
38 #include "epan/packet_info.h"
39 #include "epan/epan.h"
41 #include "simple_dialog.h"
42 #include "dlg_utils.h"
44 #include "../register.h"
45 #include "packet-rpc.h"
46 #include "../globals.h"
47 #include "filter_prefs.h"
48 #include "compat_macros.h"
49 #include "service_response_time_table.h"
51 extern GtkWidget *main_display_filter_widget;
53 /* used to keep track of the statistics for an entire program interface */
54 typedef struct _rpcstat_t {
56 srt_stat_table srt_table;
60 guint32 num_procedures;
64 rpcstat_gen_title(rpcstat_t *rs)
68 title = g_strdup_printf("ONC-RPC Service Response Time statistics for %s version %d: %s",
69 rs->prog, rs->version, cf_get_display_name(&cfile));
74 rpcstat_set_title(rpcstat_t *rs)
78 title = rpcstat_gen_title(rs);
79 gtk_window_set_title(GTK_WINDOW(rs->win), title);
84 rpcstat_reset(rpcstat_t *rs)
86 reset_srt_table_data(&rs->srt_table);
87 rpcstat_set_title(rs);
92 rpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, rpc_call_info_value *ri)
94 if(ri->proc>=rs->num_procedures){
95 /* dont handle this since its outside of known table */
98 /* we are only interested in reply packets */
102 /* we are only interested in certain program/versions */
103 if( (ri->prog!=rs->program) || (ri->vers!=rs->version) ){
107 add_srt_table_data(&rs->srt_table, ri->proc, &ri->req_time, pinfo);
113 rpcstat_draw(rpcstat_t *rs)
115 draw_srt_table_data(&rs->srt_table);
120 static guint32 rpc_program=0;
121 static guint32 rpc_version=0;
122 static gint32 rpc_min_vers=-1;
123 static gint32 rpc_max_vers=-1;
124 static gint32 rpc_min_proc=-1;
125 static gint32 rpc_max_proc=-1;
128 rpcstat_find_procs(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
130 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
132 if(k->prog!=rpc_program){
135 if(k->vers!=rpc_version){
138 if(rpc_min_proc==-1){
139 rpc_min_proc=k->proc;
140 rpc_max_proc=k->proc;
142 if((gint32)k->proc<rpc_min_proc){
143 rpc_min_proc=k->proc;
145 if((gint32)k->proc>rpc_max_proc){
146 rpc_max_proc=k->proc;
153 rpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
155 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
157 if(k->prog!=rpc_program){
160 if(rpc_min_vers==-1){
161 rpc_min_vers=k->vers;
162 rpc_max_vers=k->vers;
164 if((gint32)k->vers<rpc_min_vers){
165 rpc_min_vers=k->vers;
167 if((gint32)k->vers>rpc_max_vers){
168 rpc_max_vers=k->vers;
174 /* since the gtk2 implementation of tap is multithreaded we must protect
175 * remove_tap_listener() from modifying the list while draw_tap_listener()
176 * is running. the other protected block is in main.c
178 * there should not be any other critical regions in gtk2
180 void protect_thread_critical_region(void);
181 void unprotect_thread_critical_region(void);
183 win_destroy_cb(GtkWindow *win _U_, gpointer data)
185 rpcstat_t *rs=(rpcstat_t *)data;
187 protect_thread_critical_region();
188 remove_tap_listener(rs);
189 unprotect_thread_critical_region();
191 free_srt_table_data(&rs->srt_table);
195 /* When called, this function will create a new instance of gtk2-rpcstat.
198 gtk_rpcstat_init(char *optarg)
203 char filter_string[256];
205 GtkWidget *stat_label;
206 GtkWidget *filter_label;
207 int program, version, pos;
209 GString *error_string;
211 header_field_info *hfi;
214 if(sscanf(optarg,"rpc,srt,%d,%d,%n",&program,&version,&pos)==2){
221 fprintf(stderr, "ethereal: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
227 rs=g_malloc(sizeof(rpcstat_t));
228 rs->prog=rpc_prog_name(rpc_program);
229 rs->program=rpc_program;
230 rs->version=rpc_version;
231 hf_index=rpc_prog_hf(rpc_program, rpc_version);
232 hfi=proto_registrar_get_nth(hf_index);
234 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
235 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
236 rpcstat_set_title(rs);
237 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
239 vbox=gtk_vbox_new(FALSE, 0);
240 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
241 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
242 gtk_widget_show(vbox);
244 title_string = rpcstat_gen_title(rs);
245 stat_label=gtk_label_new(title_string);
246 g_free(title_string);
247 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
248 gtk_widget_show(stat_label);
250 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
251 filter_label=gtk_label_new(filter_string);
252 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
253 gtk_widget_show(filter_label);
257 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
258 rs->num_procedures=rpc_max_proc+1;
260 /* We must display TOP LEVEL Widget before calling init_srt_table() */
261 gtk_widget_show(rs->win);
263 init_srt_table(&rs->srt_table, rpc_max_proc+1, vbox, hfi->abbrev);
265 for(i=0;i<rs->num_procedures;i++){
266 init_srt_table_row(&rs->srt_table, i, rpc_proc_name(rpc_program, rpc_version, i));
270 error_string=register_tap_listener("rpc", rs, filter, (void*)rpcstat_reset, (void*)rpcstat_packet, (void*)rpcstat_draw);
272 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
273 g_string_free(error_string, TRUE);
274 free_srt_table_data(&rs->srt_table);
280 gtk_widget_show_all(rs->win);
281 retap_packets(&cfile);
287 static GtkWidget *dlg=NULL;
288 static GtkWidget *prog_menu;
289 static GtkWidget *vers_opt, *vers_menu;
290 static GtkWidget *filter_entry;
294 rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
299 str = g_string_new("rpc,srt");
300 g_string_sprintfa(str, ",%d,%d", rpc_program, rpc_version);
301 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
303 g_string_sprintfa(str, ",%s", filter);
306 gtk_rpcstat_init(str->str);
307 g_string_free(str, TRUE);
312 rpcstat_version_select(GtkWidget *item _U_, gpointer key)
322 rpcstat_program_select(GtkWidget *item _U_, gpointer key)
324 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
329 /* change version menu */
331 gtk_object_destroy(GTK_OBJECT(vers_menu));
332 vers_menu=gtk_menu_new();
335 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
336 rpc_version=rpc_min_vers;
337 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
338 GtkWidget *menu_item;
341 menu_item=gtk_menu_item_new_with_label(vs);
342 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
345 gtk_widget_show(menu_item);
346 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
348 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
352 rpcstat_list_programs(gpointer *key, gpointer *value, gpointer *user_data _U_)
354 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
355 rpc_prog_info_value *v=(rpc_prog_info_value *)value;
356 GtkWidget *menu_item;
358 menu_item=gtk_menu_item_new_with_label(v->progname);
359 SIGNAL_CONNECT(menu_item, "activate", rpcstat_program_select, k);
361 gtk_widget_show(menu_item);
362 gtk_menu_append(GTK_MENU(prog_menu), menu_item);
378 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
380 gtk_widget_destroy(GTK_WIDGET(parent_w));
384 gtk_rpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
387 GtkWidget *prog_box, *prog_label, *prog_opt;
388 GtkWidget *vers_label;
389 GtkWidget *filter_box, *filter_bt;
390 GtkWidget *bbox, *start_button, *cancel_button;
393 static construct_args_t args = {
394 "Service Response Time Statistics Filter",
399 /* if the window is already open, bring it to front */
401 gdk_window_raise(dlg->window);
405 dlg=dlg_window_new("Ethereal: Compute ONC-RPC SRT statistics");
406 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
408 dlg_box=gtk_vbox_new(FALSE, 10);
409 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
410 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
411 gtk_widget_show(dlg_box);
414 prog_box=gtk_hbox_new(FALSE, 10);
417 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
418 prog_label=gtk_label_new("Program:");
419 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
420 gtk_widget_show(prog_label);
423 prog_opt=gtk_option_menu_new();
424 prog_menu=gtk_menu_new();
425 g_hash_table_foreach(rpc_progs, (GHFunc)rpcstat_list_programs, NULL);
426 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
427 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
428 gtk_widget_show(prog_opt);
431 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
432 vers_label=gtk_label_new("Version:");
433 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
434 gtk_widget_show(vers_label);
437 vers_opt=gtk_option_menu_new();
438 vers_menu=gtk_menu_new();
441 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
442 rpc_version=rpc_min_vers;
443 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
444 GtkWidget *menu_item;
447 menu_item=gtk_menu_item_new_with_label(vs);
448 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
451 gtk_widget_show(menu_item);
452 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
454 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
455 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
456 gtk_widget_show(vers_opt);
458 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
459 gtk_widget_show(prog_box);
462 filter_box=gtk_hbox_new(FALSE, 3);
465 filter_bt=BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
466 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
467 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
468 gtk_widget_show(filter_bt);
471 filter_entry=gtk_entry_new();
472 WIDGET_SET_SIZE(filter_entry, 300, -2);
474 /* filter prefs dialog */
475 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_entry);
476 /* filter prefs dialog */
478 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
479 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
481 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
483 gtk_widget_show(filter_entry);
485 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
486 gtk_widget_show(filter_box);
489 bbox = dlg_button_row_new(ETHEREAL_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
490 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
491 gtk_widget_show(bbox);
493 start_button = OBJECT_GET_DATA(bbox, ETHEREAL_STOCK_CREATE_STAT);
494 gtk_widget_grab_default(start_button );
495 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
496 rpcstat_start_button_clicked, NULL);
498 cancel_button = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
499 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
501 /* Catch the "activate" signal on the filter text entry, so that
502 if the user types Return there, we act as if the "Create Stat"
503 button had been selected, as happens if Return is typed if some
504 widget that *doesn't* handle the Return key has the input
506 dlg_set_activate(filter_entry, start_button);
508 /* Catch the "key_press_event" signal in the window, so that we can
509 catch the ESC key being pressed and act as if the "Cancel" button
510 had been selected. */
511 dlg_set_cancel(dlg, cancel_button);
513 /* Give the initial focus to the "Filter" entry box. */
514 gtk_widget_grab_focus(filter_entry);
516 gtk_widget_show_all(dlg);
521 register_tap_listener_gtkrpcstat(void)
523 register_ethereal_tap("rpc,srt,", gtk_rpcstat_init);
527 register_tap_menu_gtkrpcstat(void)
529 register_tap_menu_item("_Statistics/Service Response Time/ONC-RPC...",
530 gtk_rpcstat_cb, NULL, NULL, NULL);