2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.25 2003/10/10 11:11:37 sahlberg 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 statistics to ethereal,
26 * and displays them graphically.
27 * It is only used by ethereal and not tethereal
29 * 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"
45 #include "../register.h"
46 #include "packet-dcerpc.h"
47 #include "../globals.h"
48 #include "compat_macros.h"
49 #include "service_response_time_table.h"
52 extern GtkWidget *main_display_filter_widget;
54 /* used to keep track of the statistics for an entire program interface */
55 typedef struct _rpcstat_t {
57 srt_stat_table srt_table;
66 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
68 if( (uuid1->Data1!=uuid2->Data1)
69 ||(uuid1->Data2!=uuid2->Data2)
70 ||(uuid1->Data3!=uuid2->Data3)
71 ||(uuid1->Data4[0]!=uuid2->Data4[0])
72 ||(uuid1->Data4[1]!=uuid2->Data4[1])
73 ||(uuid1->Data4[2]!=uuid2->Data4[2])
74 ||(uuid1->Data4[3]!=uuid2->Data4[3])
75 ||(uuid1->Data4[4]!=uuid2->Data4[4])
76 ||(uuid1->Data4[5]!=uuid2->Data4[5])
77 ||(uuid1->Data4[6]!=uuid2->Data4[6])
78 ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
85 dcerpcstat_set_title(rpcstat_t *rs)
89 title = g_strdup_printf("DCE-RPC Service Response Time statistics for %s version %d.%d: %s",
90 rs->prog, rs->ver&0xff, rs->ver>>8, cf_get_display_name(&cfile));
91 gtk_window_set_title(GTK_WINDOW(rs->win), title);
96 dcerpcstat_reset(rpcstat_t *rs)
98 reset_srt_table_data(&rs->srt_table);
99 dcerpcstat_set_title(rs);
104 dcerpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, dcerpc_info *ri)
109 if(!ri->call_data->req_frame){
110 /* we have not seen the request so we dont know the delta*/
113 if(ri->call_data->opnum>=rs->num_procedures){
114 /* dont handle this since its outside of known table */
118 /* we are only interested in reply packets */
123 /* we are only interested in certain program/versions */
124 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
125 ||(ri->call_data->ver!=rs->ver)){
130 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
137 dcerpcstat_draw(rpcstat_t *rs)
139 draw_srt_table_data(&rs->srt_table);
143 /* since the gtk2 implementation of tap is multithreaded we must protect
144 * remove_tap_listener() from modifying the list while draw_tap_listener()
145 * is running. the other protected block is in main.c
147 * there should not be any other critical regions in gtk2
149 void protect_thread_critical_region(void);
150 void unprotect_thread_critical_region(void);
152 win_destroy_cb(GtkWindow *win _U_, gpointer data)
154 rpcstat_t *rs=(rpcstat_t *)data;
156 protect_thread_critical_region();
157 remove_tap_listener(rs);
158 unprotect_thread_critical_region();
160 free_srt_table_data(&rs->srt_table);
166 /* When called, this function will create a new instance of gtk-dcerpcstat.
169 gtk_dcerpcstat_init(char *optarg)
172 guint32 i, max_procs;
173 char title_string[256];
174 char filter_string[256];
176 GtkWidget *stat_label;
177 GtkWidget *filter_label;
178 dcerpc_sub_dissector *procs;
180 int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
184 GString *error_string;
187 if(sscanf(optarg,"dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d,%n", &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)==13){
205 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
210 rs=g_malloc(sizeof(rpcstat_t));
211 rs->prog=dcerpc_get_proto_name(&uuid, (minor<<8)|(major&0xff) );
212 hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, (minor<<8)|(major&0xff) );
215 fprintf(stderr,"ethereal: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%d.%d not supported\n",uuid.Data1,uuid.Data2,uuid.Data3,uuid.Data4[0],uuid.Data4[1],uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],uuid.Data4[5],uuid.Data4[6],uuid.Data4[7],major,minor);
218 procs=dcerpc_get_proto_sub_dissector(&uuid, (minor<<8)|(major&0xff) );
220 rs->ver=(minor<<8)|(major&0xff);
222 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
223 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
224 dcerpcstat_set_title(rs);
225 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
227 vbox=gtk_vbox_new(FALSE, 0);
228 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
229 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
230 gtk_widget_show(vbox);
232 stat_label=gtk_label_new(title_string);
233 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
234 gtk_widget_show(stat_label);
236 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
237 filter_label=gtk_label_new(filter_string);
238 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
239 gtk_widget_show(filter_label);
241 for(i=0,max_procs=0;procs[i].name;i++){
242 if(procs[i].num>max_procs){
243 max_procs=procs[i].num;
246 rs->num_procedures=max_procs+1;
248 /* We must display TOP LEVEL Widget before calling init_srt_table() */
249 gtk_widget_show(rs->win);
252 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
254 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
257 for(i=0;i<(max_procs+1);i++){
262 for(j=0;procs[j].name;j++){
264 proc_name=procs[j].name;
268 init_srt_table_row(&rs->srt_table, i, proc_name);
272 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
274 /* error, we failed to attach to the tap. clean up */
275 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
276 g_string_free(error_string, TRUE);
277 free_srt_table_data(&rs->srt_table);
283 gtk_widget_show_all(rs->win);
284 redissect_packets(&cfile);
289 static e_uuid_t *dcerpc_uuid_program=NULL;
290 static guint16 dcerpc_version;
291 static GtkWidget *dlg=NULL;
292 static GtkWidget *prog_menu;
293 static GtkWidget *vers_opt, *vers_menu;
294 static GtkWidget *filter_entry;
295 static dcerpc_uuid_key *current_uuid_key=NULL;
296 static dcerpc_uuid_value *current_uuid_value=NULL;
297 static dcerpc_uuid_key *new_uuid_key=NULL;
298 static dcerpc_uuid_value *new_uuid_value=NULL;
302 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
307 str = g_string_new("dcerpc,srt");
308 g_string_sprintfa(str,
309 ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d",
310 dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
311 dcerpc_uuid_program->Data3,
312 dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
313 dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
314 dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
315 dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
316 dcerpc_version&0xff, dcerpc_version>>8);
317 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
319 g_string_sprintfa(str, ",%s", filter);
322 gtk_dcerpcstat_init(str->str);
323 g_string_free(str, TRUE);
328 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
339 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
341 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
342 GtkWidget *menu_item;
345 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
349 sprintf(vs,"%d.%d",k->ver&0xff,k->ver>>8);
350 menu_item=gtk_menu_item_new_with_label(vs);
351 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
353 gtk_widget_show(menu_item);
354 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
356 if(dcerpc_version==0xffff){
357 dcerpc_version=k->ver;
365 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
367 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
369 dcerpc_uuid_program=&k->uuid;
371 /* change version menu */
372 dcerpc_version=0xffff;
373 gtk_object_destroy(GTK_OBJECT(vers_menu));
374 vers_menu=gtk_menu_new();
375 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
376 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
381 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
383 GtkWidget *program_menu_item;
385 program_menu_item=gtk_menu_item_new_with_label(v->name);
386 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
388 gtk_widget_show(program_menu_item);
389 gtk_menu_append(GTK_MENU(prog_menu), program_menu_item);
391 if(!dcerpc_uuid_program){
392 dcerpc_uuid_program=&k->uuid;
399 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
401 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
402 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
404 /* first time called, just set new_uuid to this one */
405 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
411 /* if we havent got a current one yet, just check the new
412 and scan for the first one alphabetically */
413 if(current_uuid_key==NULL){
414 if(strcmp(new_uuid_value->name, v->name)>0){
422 /* searching for the next one we are only interested in those
423 that sorts alphabetically after the current one */
424 if(strcmp(current_uuid_value->name, v->name)>=0){
425 /* this one doesnt so just skip it */
429 /* is it the first potential new entry? */
430 if(new_uuid_key==NULL){
436 /* does it sort before the current new one? */
437 if(strcmp(new_uuid_value->name, v->name)>0){
455 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
457 gtk_widget_destroy(GTK_WIDGET(parent_w));
462 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
465 GtkWidget *prog_box, *prog_label, *prog_opt;
466 GtkWidget *vers_label;
467 GtkWidget *filter_box, *filter_label;
468 GtkWidget *bbox, *start_button, *cancel_button;
471 /* if the window is already open, bring it to front and
472 un-minimize it, as necessary */
474 reactivate_window(dlg);
478 dlg=dlg_window_new("Ethereal: Compute DCE-RPC SRT statistics");
479 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
481 dlg_box=gtk_vbox_new(FALSE, 10);
482 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
483 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
484 gtk_widget_show(dlg_box);
487 prog_box=gtk_hbox_new(FALSE, 3);
490 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
491 prog_label=gtk_label_new("Program:");
492 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
493 gtk_widget_show(prog_label);
496 prog_opt=gtk_option_menu_new();
497 prog_menu=gtk_menu_new();
498 current_uuid_key=NULL;
499 current_uuid_value=NULL;
503 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
505 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
507 current_uuid_key=new_uuid_key;
508 current_uuid_value=new_uuid_value;
509 } while(new_uuid_key!=NULL);
511 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
512 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
513 gtk_widget_show(prog_opt);
516 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
517 vers_label=gtk_label_new("Version:");
518 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
519 gtk_widget_show(vers_label);
522 vers_opt=gtk_option_menu_new();
523 vers_menu=gtk_menu_new();
524 dcerpc_version=0xffff;
525 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
526 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
527 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
528 gtk_widget_show(vers_opt);
530 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
531 gtk_widget_show(prog_box);
534 filter_box=gtk_hbox_new(FALSE, 3);
537 filter_label=gtk_label_new("Filter:");
538 gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
539 gtk_widget_show(filter_label);
542 filter_entry=gtk_entry_new();
543 gtk_widget_set_usize(filter_entry, 300, -2);
544 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
545 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
547 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
549 gtk_widget_show(filter_entry);
551 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
552 gtk_widget_show(filter_box);
555 bbox=gtk_hbutton_box_new();
556 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
557 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
558 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
559 gtk_widget_show(bbox);
561 /* the start button */
562 start_button=gtk_button_new_with_label("Create Stat");
563 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
564 dcerpcstat_start_button_clicked, NULL);
565 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
566 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
567 gtk_widget_grab_default(start_button);
568 gtk_widget_show(start_button);
570 #if GTK_MAJOR_VERSION < 2
571 cancel_button=gtk_button_new_with_label("Cancel");
573 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
575 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
576 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
577 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
578 gtk_widget_show(cancel_button);
580 /* Catch the "activate" signal on the filter text entry, so that
581 if the user types Return there, we act as if the "Create Stat"
582 button had been selected, as happens if Return is typed if some
583 widget that *doesn't* handle the Return key has the input
585 dlg_set_activate(filter_entry, start_button);
587 /* Catch the "key_press_event" signal in the window, so that we can
588 catch the ESC key being pressed and act as if the "Cancel" button
589 had been selected. */
590 dlg_set_cancel(dlg, cancel_button);
592 /* Give the initial focus to the "Filter" entry box. */
593 gtk_widget_grab_focus(filter_entry);
595 gtk_widget_show_all(dlg);
599 register_tap_listener_gtkdcerpcstat(void)
601 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
605 register_tap_menu_gtkdcerpcstat(void)
607 register_tap_menu_item("Statistics/Service Response Time/DCE-RPC...",
608 gtk_dcerpcstat_cb, NULL, NULL);