2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.17 2003/09/05 20:00:02 guy 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.
39 #include "epan/packet_info.h"
40 #include "epan/filesystem.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]) ){
86 dcerpcstat_reset(rpcstat_t *rs)
88 char title_string[256];
89 reset_srt_table_data(&rs->srt_table);
91 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));
92 gtk_window_set_title(GTK_WINDOW(rs->win), title_string);
97 dcerpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, dcerpc_info *ri)
102 if(!ri->call_data->req_frame){
103 /* we have not seen the request so we dont know the delta*/
106 if(ri->call_data->opnum>=rs->num_procedures){
107 /* dont handle this since its outside of known table */
111 /* we are only interested in reply packets */
116 /* we are only interested in certain program/versions */
117 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
118 ||(ri->call_data->ver!=rs->ver)){
123 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
130 dcerpcstat_draw(rpcstat_t *rs)
132 draw_srt_table_data(&rs->srt_table);
136 /* since the gtk2 implementation of tap is multithreaded we must protect
137 * remove_tap_listener() from modifying the list while draw_tap_listener()
138 * is running. the other protected block is in main.c
140 * there should not be any other critical regions in gtk2
142 void protect_thread_critical_region(void);
143 void unprotect_thread_critical_region(void);
145 win_destroy_cb(GtkWindow *win _U_, gpointer data)
147 rpcstat_t *rs=(rpcstat_t *)data;
149 protect_thread_critical_region();
150 remove_tap_listener(rs);
151 unprotect_thread_critical_region();
153 free_srt_table_data(&rs->srt_table);
159 /* When called, this function will create a new instance of gtk-dcerpcstat.
162 gtk_dcerpcstat_init(char *optarg)
165 guint32 i, max_procs;
166 char title_string[256];
167 char filter_string[256];
169 GtkWidget *stat_label;
170 GtkWidget *filter_label;
171 dcerpc_sub_dissector *procs;
173 int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
177 GString *error_string;
179 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){
197 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
202 rs=g_malloc(sizeof(rpcstat_t));
203 rs->prog=dcerpc_get_proto_name(&uuid, (minor<<8)|(major&0xff) );
206 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);
209 procs=dcerpc_get_proto_sub_dissector(&uuid, (minor<<8)|(major&0xff) );
211 rs->ver=(minor<<8)|(major&0xff);
213 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
214 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
215 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));
216 gtk_window_set_title(GTK_WINDOW(rs->win), title_string);
217 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
219 vbox=gtk_vbox_new(FALSE, 0);
220 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
221 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
222 gtk_widget_show(vbox);
224 stat_label=gtk_label_new(title_string);
225 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
226 gtk_widget_show(stat_label);
228 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
229 filter_label=gtk_label_new(filter_string);
230 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
231 gtk_widget_show(filter_label);
233 for(i=0,max_procs=0;procs[i].name;i++){
234 if(procs[i].num>max_procs){
235 max_procs=procs[i].num;
238 rs->num_procedures=max_procs+1;
240 /* We must display TOP LEVEL Widget before calling init_srt_table() */
241 gtk_widget_show(rs->win);
243 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
245 for(i=0;i<(max_procs+1);i++){
250 for(j=0;procs[j].name;j++){
252 proc_name=procs[j].name;
256 init_srt_table_row(&rs->srt_table, i, proc_name);
260 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
262 /* error, we failed to attach to the tap. clean up */
263 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
264 g_string_free(error_string, TRUE);
265 free_srt_table_data(&rs->srt_table);
271 gtk_widget_show_all(rs->win);
272 redissect_packets(&cfile);
277 static e_uuid_t *dcerpc_uuid_program=NULL;
278 static guint16 dcerpc_version;
279 static GtkWidget *dlg=NULL, *dlg_box;
280 static GtkWidget *prog_box;
281 static GtkWidget *prog_label, *prog_opt, *prog_menu;
282 static GtkWidget *vers_label, *vers_opt, *vers_menu;
283 static GtkWidget *filter_box;
284 static GtkWidget *filter_label, *filter_entry;
285 static GtkWidget *start_button;
286 static dcerpc_uuid_key *current_uuid_key=NULL;
287 static dcerpc_uuid_value *current_uuid_value=NULL;
288 static dcerpc_uuid_key *new_uuid_key=NULL;
289 static dcerpc_uuid_value *new_uuid_value=NULL;
293 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
298 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
300 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);
303 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);
306 gtk_dcerpcstat_init(str);
311 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
322 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
324 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
325 GtkWidget *menu_item;
328 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
332 sprintf(vs,"%d.%d",k->ver&0xff,k->ver>>8);
333 menu_item=gtk_menu_item_new_with_label(vs);
334 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
336 gtk_widget_show(menu_item);
337 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
339 if(dcerpc_version==0xffff){
340 dcerpc_version=k->ver;
348 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
350 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
352 dcerpc_uuid_program=&k->uuid;
354 /* change version menu */
355 dcerpc_version=0xffff;
356 gtk_object_destroy(GTK_OBJECT(vers_menu));
357 vers_menu=gtk_menu_new();
358 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
359 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
364 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
366 GtkWidget *program_menu_item;
368 program_menu_item=gtk_menu_item_new_with_label(v->name);
369 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
371 gtk_widget_show(program_menu_item);
372 gtk_menu_append(GTK_MENU(prog_menu), program_menu_item);
374 if(!dcerpc_uuid_program){
375 dcerpc_uuid_program=&k->uuid;
382 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
384 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
385 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
387 /* first time called, just set new_uuid to this one */
388 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
394 /* if we havent got a current one yet, just check the new
395 and scan for the first one alphabetically */
396 if(current_uuid_key==NULL){
397 if(strcmp(new_uuid_value->name, v->name)>0){
405 /* searching for the next one we are only interested in those
406 that sorts alphabetically after the current one */
407 if(strcmp(current_uuid_value->name, v->name)>=0){
408 /* this one doesnt so just skip it */
412 /* is it the first potential new entry? */
413 if(new_uuid_key==NULL){
419 /* does it sort before the current new one? */
420 if(strcmp(new_uuid_value->name, v->name)>0){
438 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
440 gtk_widget_destroy(GTK_WIDGET(parent_w));
445 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
447 GtkWidget *bbox, *cancel_button;
450 /* if the window is already open, bring it to front and
451 un-minimize it, as necessary */
453 reactivate_window(dlg);
457 dlg=dlg_window_new("Ethereal: DCE-RPC SRT Statistics");
458 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
459 dlg_box=gtk_vbox_new(FALSE, 0);
460 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
461 gtk_widget_show(dlg_box);
464 prog_box=gtk_hbox_new(FALSE, 10);
466 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
467 prog_label=gtk_label_new("Program:");
468 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
469 gtk_widget_show(prog_label);
472 prog_opt=gtk_option_menu_new();
473 prog_menu=gtk_menu_new();
474 current_uuid_key=NULL;
475 current_uuid_value=NULL;
479 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
481 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
483 current_uuid_key=new_uuid_key;
484 current_uuid_value=new_uuid_value;
485 } while(new_uuid_key!=NULL);
488 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
489 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
490 gtk_widget_show(prog_opt);
493 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
494 vers_label=gtk_label_new("Version:");
495 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
496 gtk_widget_show(vers_label);
499 vers_opt=gtk_option_menu_new();
500 vers_menu=gtk_menu_new();
501 dcerpc_version=0xffff;
502 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
503 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
504 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
505 gtk_widget_show(vers_opt);
507 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
508 gtk_widget_show(prog_box);
512 filter_box=gtk_hbox_new(FALSE, 10);
514 gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10);
515 filter_label=gtk_label_new("Filter:");
516 gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
517 gtk_widget_show(filter_label);
519 filter_entry=gtk_entry_new_with_max_length(250);
520 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0);
521 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
523 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
525 gtk_widget_show(filter_entry);
527 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
528 gtk_widget_show(filter_box);
531 bbox=gtk_hbutton_box_new();
532 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
533 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
534 gtk_container_add(GTK_CONTAINER(dlg_box), bbox);
535 gtk_widget_show(bbox);
537 /* the start button */
538 start_button=gtk_button_new_with_label("Create Stat");
539 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
540 dcerpcstat_start_button_clicked, NULL);
541 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
542 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
543 gtk_widget_grab_default(start_button);
544 gtk_widget_show(start_button);
546 #if GTK_MAJOR_VERSION < 2
547 cancel_button=gtk_button_new_with_label("Cancel");
549 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
551 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
552 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
553 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
554 gtk_widget_show(cancel_button);
556 /* Catch the "activate" signal on the filter text entry, so that
557 if the user types Return there, we act as if the "Create Stat"
558 button had been selected, as happens if Return is typed if some
559 widget that *doesn't* handle the Return key has the input
561 dlg_set_activate(filter_entry, start_button);
563 /* Catch the "key_press_event" signal in the window, so that we can
564 catch the ESC key being pressed and act as if the "Cancel" button
565 had been selected. */
566 dlg_set_cancel(dlg, cancel_button);
568 /* Give the initial focus to the "Filter" entry box. */
569 gtk_widget_grab_focus(filter_entry);
571 gtk_widget_show_all(dlg);
575 register_tap_listener_gtkdcerpcstat(void)
577 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
581 register_tap_menu_gtkdcerpcstat(void)
583 register_tap_menu_item("Service Response Time/DCE-RPC", gtk_dcerpcstat_cb);