2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.15 2003/09/05 00:48:58 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/filesystem.h"
40 #include "simple_dialog.h"
41 #include "dlg_utils.h"
44 #include "../register.h"
45 #include "packet-dcerpc.h"
46 #include "../globals.h"
47 #include "compat_macros.h"
48 #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;
65 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
67 if( (uuid1->Data1!=uuid2->Data1)
68 ||(uuid1->Data2!=uuid2->Data2)
69 ||(uuid1->Data3!=uuid2->Data3)
70 ||(uuid1->Data4[0]!=uuid2->Data4[0])
71 ||(uuid1->Data4[1]!=uuid2->Data4[1])
72 ||(uuid1->Data4[2]!=uuid2->Data4[2])
73 ||(uuid1->Data4[3]!=uuid2->Data4[3])
74 ||(uuid1->Data4[4]!=uuid2->Data4[4])
75 ||(uuid1->Data4[5]!=uuid2->Data4[5])
76 ||(uuid1->Data4[6]!=uuid2->Data4[6])
77 ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
85 dcerpcstat_reset(rpcstat_t *rs)
87 char title_string[256];
88 reset_srt_table_data(&rs->srt_table);
90 snprintf(title_string, 255, "DCE-RPC Service Response Time statistics for %s version %d.%d : %s", rs->prog, rs->ver&0xff, rs->ver>>8, get_basename(cfile.filename));
91 gtk_window_set_title(GTK_WINDOW(rs->win), title_string);
96 dcerpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, dcerpc_info *ri)
101 if(!ri->call_data->req_frame){
102 /* we have not seen the request so we dont know the delta*/
105 if(ri->call_data->opnum>=rs->num_procedures){
106 /* dont handle this since its outside of known table */
110 /* we are only interested in reply packets */
115 /* we are only interested in certain program/versions */
116 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
117 ||(ri->call_data->ver!=rs->ver)){
122 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
129 dcerpcstat_draw(rpcstat_t *rs)
131 draw_srt_table_data(&rs->srt_table);
135 /* since the gtk2 implementation of tap is multithreaded we must protect
136 * remove_tap_listener() from modifying the list while draw_tap_listener()
137 * is running. the other protected block is in main.c
139 * there should not be any other critical regions in gtk2
141 void protect_thread_critical_region(void);
142 void unprotect_thread_critical_region(void);
144 win_destroy_cb(GtkWindow *win _U_, gpointer data)
146 rpcstat_t *rs=(rpcstat_t *)data;
148 protect_thread_critical_region();
149 remove_tap_listener(rs);
150 unprotect_thread_critical_region();
152 free_srt_table_data(&rs->srt_table);
158 /* When called, this function will create a new instance of gtk-dcerpcstat.
161 gtk_dcerpcstat_init(char *optarg)
164 guint32 i, max_procs;
165 char title_string[256];
166 char filter_string[256];
168 GtkWidget *stat_label;
169 GtkWidget *filter_label;
170 dcerpc_sub_dissector *procs;
172 int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
176 GString *error_string;
178 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){
196 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
201 rs=g_malloc(sizeof(rpcstat_t));
202 rs->prog=dcerpc_get_proto_name(&uuid, (minor<<8)|(major&0xff) );
205 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);
208 procs=dcerpc_get_proto_sub_dissector(&uuid, (minor<<8)|(major&0xff) );
210 rs->ver=(minor<<8)|(major&0xff);
212 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
213 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
214 snprintf(title_string, 255, "DCE-RPC Service Response Time statistics for %s version %d.%d : %s", rs->prog, rs->ver&0xff, rs->ver>>8, get_basename(cfile.filename));
215 gtk_window_set_title(GTK_WINDOW(rs->win), title_string);
216 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
218 vbox=gtk_vbox_new(FALSE, 0);
219 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
220 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
221 gtk_widget_show(vbox);
223 stat_label=gtk_label_new(title_string);
224 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
225 gtk_widget_show(stat_label);
227 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
228 filter_label=gtk_label_new(filter_string);
229 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
230 gtk_widget_show(filter_label);
232 for(i=0,max_procs=0;procs[i].name;i++){
233 if(procs[i].num>max_procs){
234 max_procs=procs[i].num;
237 rs->num_procedures=max_procs+1;
239 /* We must display TOP LEVEL Widget before calling init_srt_table() */
240 gtk_widget_show(rs->win);
242 init_srt_table(&rs->srt_table, max_procs+1, vbox);
244 for(i=0;i<(max_procs+1);i++){
249 for(j=0;procs[j].name;j++){
251 proc_name=procs[j].name;
255 init_srt_table_row(&rs->srt_table, i, proc_name);
259 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
261 /* error, we failed to attach to the tap. clean up */
262 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
263 g_string_free(error_string, TRUE);
264 free_srt_table_data(&rs->srt_table);
270 gtk_widget_show_all(rs->win);
271 redissect_packets(&cfile);
276 static e_uuid_t *dcerpc_uuid_program=NULL;
277 static guint16 dcerpc_version;
278 static GtkWidget *dlg=NULL, *dlg_box;
279 static GtkWidget *prog_box;
280 static GtkWidget *prog_label, *prog_opt, *prog_menu;
281 static GtkWidget *vers_label, *vers_opt, *vers_menu;
282 static GtkWidget *filter_box;
283 static GtkWidget *filter_label, *filter_entry;
284 static GtkWidget *start_button;
285 static dcerpc_uuid_key *current_uuid_key=NULL;
286 static dcerpc_uuid_value *current_uuid_value=NULL;
287 static dcerpc_uuid_key *new_uuid_key=NULL;
288 static dcerpc_uuid_value *new_uuid_value=NULL;
292 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
297 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
299 sprintf(str, "dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d",dcerpc_uuid_program->Data1,dcerpc_uuid_program->Data2,dcerpc_uuid_program->Data3,dcerpc_uuid_program->Data4[0],dcerpc_uuid_program->Data4[1],dcerpc_uuid_program->Data4[2],dcerpc_uuid_program->Data4[3],dcerpc_uuid_program->Data4[4],dcerpc_uuid_program->Data4[5],dcerpc_uuid_program->Data4[6],dcerpc_uuid_program->Data4[7],dcerpc_version&0xff,dcerpc_version>>8);
302 sprintf(str, "dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d,%s",dcerpc_uuid_program->Data1,dcerpc_uuid_program->Data2,dcerpc_uuid_program->Data3,dcerpc_uuid_program->Data4[0],dcerpc_uuid_program->Data4[1],dcerpc_uuid_program->Data4[2],dcerpc_uuid_program->Data4[3],dcerpc_uuid_program->Data4[4],dcerpc_uuid_program->Data4[5],dcerpc_uuid_program->Data4[6],dcerpc_uuid_program->Data4[7],dcerpc_version&0xff,dcerpc_version>>8, filter);
305 gtk_dcerpcstat_init(str);
310 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
321 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
323 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
324 GtkWidget *menu_item;
327 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
331 sprintf(vs,"%d.%d",k->ver&0xff,k->ver>>8);
332 menu_item=gtk_menu_item_new_with_label(vs);
333 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
335 gtk_widget_show(menu_item);
336 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
338 if(dcerpc_version==0xffff){
339 dcerpc_version=k->ver;
347 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
349 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
351 dcerpc_uuid_program=&k->uuid;
353 /* change version menu */
354 dcerpc_version=0xffff;
355 gtk_object_destroy(GTK_OBJECT(vers_menu));
356 vers_menu=gtk_menu_new();
357 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
358 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
363 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
365 GtkWidget *program_menu_item;
367 program_menu_item=gtk_menu_item_new_with_label(v->name);
368 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
370 gtk_widget_show(program_menu_item);
371 gtk_menu_append(GTK_MENU(prog_menu), program_menu_item);
373 if(!dcerpc_uuid_program){
374 dcerpc_uuid_program=&k->uuid;
381 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
383 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
384 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
386 /* first time called, just set new_uuid to this one */
387 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
393 /* if we havent got a current one yet, just check the new
394 and scan for the first one alphabetically */
395 if(current_uuid_key==NULL){
396 if(strcmp(new_uuid_value->name, v->name)>0){
404 /* searching for the next one we are only interested in those
405 that sorts alphabetically after the current one */
406 if(strcmp(current_uuid_value->name, v->name)>=0){
407 /* this one doesnt so just skip it */
411 /* is it the first potential new entry? */
412 if(new_uuid_key==NULL){
418 /* does it sort before the current new one? */
419 if(strcmp(new_uuid_value->name, v->name)>0){
437 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
439 gtk_widget_destroy(GTK_WIDGET(parent_w));
444 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
446 GtkWidget *bbox, *cancel_button;
449 /* if the window is already open, bring it to front and
450 un-minimize it, as necessary */
452 reactivate_window(dlg);
456 dlg=dlg_window_new("Ethereal: DCE-RPC SRT Statistics");
457 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
458 dlg_box=gtk_vbox_new(FALSE, 0);
459 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
460 gtk_widget_show(dlg_box);
463 prog_box=gtk_hbox_new(FALSE, 10);
465 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
466 prog_label=gtk_label_new("Program:");
467 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
468 gtk_widget_show(prog_label);
471 prog_opt=gtk_option_menu_new();
472 prog_menu=gtk_menu_new();
473 current_uuid_key=NULL;
474 current_uuid_value=NULL;
478 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
480 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
482 current_uuid_key=new_uuid_key;
483 current_uuid_value=new_uuid_value;
484 } while(new_uuid_key!=NULL);
487 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
488 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
489 gtk_widget_show(prog_opt);
492 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
493 vers_label=gtk_label_new("Version:");
494 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
495 gtk_widget_show(vers_label);
498 vers_opt=gtk_option_menu_new();
499 vers_menu=gtk_menu_new();
500 dcerpc_version=0xffff;
501 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
502 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
503 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
504 gtk_widget_show(vers_opt);
506 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
507 gtk_widget_show(prog_box);
511 filter_box=gtk_hbox_new(FALSE, 10);
513 gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10);
514 filter_label=gtk_label_new("Filter:");
515 gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
516 gtk_widget_show(filter_label);
518 filter_entry=gtk_entry_new_with_max_length(250);
519 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0);
520 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
522 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
524 gtk_widget_show(filter_entry);
526 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
527 gtk_widget_show(filter_box);
530 bbox=gtk_hbutton_box_new();
531 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
532 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
533 gtk_container_add(GTK_CONTAINER(dlg_box), bbox);
534 gtk_widget_show(bbox);
536 /* the start button */
537 start_button=gtk_button_new_with_label("Create Stat");
538 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
539 dcerpcstat_start_button_clicked, NULL);
540 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
541 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
542 gtk_widget_grab_default(start_button);
543 gtk_widget_show(start_button);
545 #if GTK_MAJOR_VERSION < 2
546 cancel_button=gtk_button_new_with_label("Cancel");
548 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
550 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
551 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
552 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
553 gtk_widget_show(cancel_button);
555 /* Catch the "activate" signal on the filter text entry, so that
556 if the user types Return there, we act as if the "Create Stat"
557 button had been selected, as happens if Return is typed if some
558 widget that *doesn't* handle the Return key has the input
560 dlg_set_activate(filter_entry, start_button);
562 /* Catch the "key_press_event" signal in the window, so that we can
563 catch the ESC key being pressed and act as if the "Cancel" button
564 had been selected. */
565 dlg_set_cancel(dlg, cancel_button);
567 /* Give the initial focus to the "Filter" entry box. */
568 gtk_widget_grab_focus(filter_entry);
570 gtk_widget_show_all(dlg);
574 register_tap_listener_gtkdcerpcstat(void)
576 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
580 register_tap_menu_gtkdcerpcstat(void)
582 register_tap_menu_item("Service Response Time/DCE-RPC", gtk_dcerpcstat_cb);