summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-08-11 11:48:07 -0700
committerGerald Combs <gerald@wireshark.org>2015-08-12 20:17:35 +0000
commit5c80f08648ed14ecc03c20d8c52f25d71b03dd26 (patch)
treef931bbc8b684f15b692aa1fd009324310dd058df
parent412f5b3716bce91d1b26a82012e5c28a611d91da (diff)
downloadwireshark-5c80f08648ed14ecc03c20d8c52f25d71b03dd26.tar.gz
Add DCE-RPC and ONC-RPC service response time dialogs.
Add RpcServiceResponseTimeDialog, which handles DCE-RPC and ONC-RPC service response time statistics. Try to make it as lightweight as possible, since we might want to pull this into the RPC dissectors similar to the other SRT statistics. Allow program names on the command line in place of numbers or UUIDs. Make matches case-insensitive. E.g. the following are equivalent: -z rpc,srt,100003,3 -z rpc,srt,nfs,3 -z rpc,srt,NFS,3 as are the following: -z dcerpc,srt,f5cc5a18-4264-101a-8c59-08002b2f8426,56 -z dcerpc,srt,nspi,56 -z dcerpc,srt,NSPI,56 Change-Id: Ie451c64bf6fbc776f27d81e3bc248435c5cbc9e4 Reviewed-on: https://code.wireshark.org/review/9981 Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
-rw-r--r--doc/wireshark.pod.template18
-rw-r--r--epan/dissectors/packet-dcerpc.h3
-rw-r--r--epan/dissectors/packet-rpc.h14
-rw-r--r--epan/guid-utils.h2
-rw-r--r--epan/stat_tap_ui.h2
-rw-r--r--ui/gtk/dcerpc_stat.c21
-rw-r--r--ui/qt/CMakeLists.txt2
-rw-r--r--ui/qt/Makefile.common4
-rw-r--r--ui/qt/Wireshark.pro2
-rw-r--r--ui/qt/main_window_slots.cpp1
-rw-r--r--ui/qt/qt_ui_utils.cpp6
-rw-r--r--ui/qt/qt_ui_utils.h12
-rw-r--r--ui/qt/rpc_service_response_time_dialog.cpp436
-rw-r--r--ui/qt/rpc_service_response_time_dialog.h96
-rw-r--r--ui/qt/service_response_time_dialog.cpp16
-rw-r--r--ui/qt/service_response_time_dialog.h6
-rw-r--r--ui/qt/tap_parameter_dialog.cpp19
-rw-r--r--ui/qt/tap_parameter_dialog.h7
-rw-r--r--ui/qt/tap_parameter_dialog.ui10
19 files changed, 633 insertions, 44 deletions
diff --git a/doc/wireshark.pod.template b/doc/wireshark.pod.template
index 360692d9ba..55fcf7260c 100644
--- a/doc/wireshark.pod.template
+++ b/doc/wireshark.pod.template
@@ -683,12 +683,13 @@ the total number of packets.
These tables can also be generated at runtime by selecting the appropriate
conversation type from the menu "Tools/Statistics/Conversation List/".
-=item B<-z> dcerpc,srt,I<uuid>,I<major>.I<minor>[,I<filter>]
+=item B<-z> dcerpc,srt,I<name-or-uuid>,I<major>.I<minor>[,I<filter>]
-Collect call/reply SRT (Service Response Time) data for DCERPC interface I<uuid>,
-version I<major>.I<minor>.
+Collect call/reply SRT (Service Response Time) data for DCERPC interface
+I<name> or I<uuid>, version I<major>.I<minor>.
Data collected is the number of calls for each procedure, MinSRT, MaxSRT
and AvgSRT.
+Interface I<name> and I<uuid> are case-insensitive.
Example: S<B<-z dcerpc,srt,12345778-1234-abcd-ef00-0123456789ac,1.0>> will collect data for the CIFS SAMR Interface.
@@ -841,10 +842,13 @@ Collect call/reply SRT data for all known ONC-RPC programs/versions.
Data collected is the number of calls for each protocol/version, MinSRT,
MaxSRT and AvgSRT.
-=item B<-z> rpc,srt,I<program>,I<version>[,<filter>]
+=item B<-z> rpc,srt,I<name-or-number>,I<version>[,<filter>]
-Collect call/reply SRT (Service Response Time) data for I<program>/I<version>. Data collected
-is the number of calls for each procedure, MinSRT, MaxSRT and AvgSRT.
+Collect call/reply SRT (Service Response Time) data for program
+I<name>/I<version> or I<number>/I<version>.
+Data collected is the number of calls for each procedure, MinSRT, MaxSRT and
+AvgSRT.
+Program I<name> is case-insensitive.
Example: B<-z rpc,srt,100003,3> will collect data for NFS v3.
@@ -853,7 +857,7 @@ This option can be used multiple times on the command line.
If the optional I<filter> is provided, the stats will only be calculated
on those calls that match that filter.
-Example: S<B<-z rpc,srt,100003,3,nfs.fh.hash==0x12345678>> will collect NFS v3
+Example: S<B<-z rpc,srt,nfs,3,nfs.fh.hash==0x12345678>> will collect NFS v3
SRT statistics for a specific file.
=item B<-z> scsi,srt,I<cmdset>[,<filter>]
diff --git a/epan/dissectors/packet-dcerpc.h b/epan/dissectors/packet-dcerpc.h
index c9222bfb9c..0cb723f6c6 100644
--- a/epan/dissectors/packet-dcerpc.h
+++ b/epan/dissectors/packet-dcerpc.h
@@ -407,6 +407,9 @@ WS_DLL_PUBLIC void decode_dcerpc_add_show_list(decode_add_show_list_func func, g
/* the registered subdissectors. With MSVC and a
* libwireshark.dll, we need a special declaration.
*/
+/* Key: dcerpc_uuid_key *
+ * Value: dcerpc_uuid_value *
+ */
WS_DLL_PUBLIC GHashTable *dcerpc_uuids;
typedef struct _dcerpc_uuid_key {
diff --git a/epan/dissectors/packet-rpc.h b/epan/dissectors/packet-rpc.h
index d633bd3a20..b72112d991 100644
--- a/epan/dissectors/packet-rpc.h
+++ b/epan/dissectors/packet-rpc.h
@@ -29,6 +29,10 @@
#include <epan/conversation.h>
#include "ws_symbol_export.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#define RPC_CALL 0
#define RPC_REPLY 1
@@ -203,12 +207,15 @@ typedef struct _rpc_prog_info_value {
int proto_id;
int ett;
const char* progname;
- GArray *procedure_hfs;
+ GArray *procedure_hfs; /* int */
} rpc_prog_info_value;
/* rpc_progs is also used in tap. With MSVC and a
* libwireshark.dll, we need a special declaration.
*/
+/* Key: Program number (guint32)
+ * Value: rpc_prog_info_value *
+ */
WS_DLL_PUBLIC GHashTable *rpc_progs;
typedef struct _rpc_proc_info_key {
@@ -225,5 +232,8 @@ typedef struct rpcstat_tap_data
int num_procedures;
} rpcstat_tap_data_t;
-#endif /* packet-rpc.h */
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* packet-rpc.h */
diff --git a/epan/guid-utils.h b/epan/guid-utils.h
index 6441b361df..0294efbe5d 100644
--- a/epan/guid-utils.h
+++ b/epan/guid-utils.h
@@ -60,6 +60,6 @@ WS_DLL_PUBLIC const gchar* guids_resolve_guid_to_str(const e_guid_t *guid);
/* (if you need hex string only, use guid_to_str instead) */
#define guids_resolve_uuid_to_str(uuid) guids_resolve_guid_to_str((e_guid_t *) (uuid))
-extern int guid_cmp(const e_guid_t *g1, const e_guid_t *g2);
+WS_DLL_PUBLIC int guid_cmp(const e_guid_t *g1, const e_guid_t *g2);
#endif /* __GUID_UTILS_H__ */
diff --git a/epan/stat_tap_ui.h b/epan/stat_tap_ui.h
index 437bcbcda4..243a10df86 100644
--- a/epan/stat_tap_ui.h
+++ b/epan/stat_tap_ui.h
@@ -42,7 +42,7 @@ typedef enum {
PARAM_UINT, /* Unused? */
PARAM_STRING, /* Unused? */
PARAM_ENUM, /* SCSI SRT */
- PARAM_UUID, /* Unused? */
+ PARAM_UUID, /* DCE-RPC. Unused? */
PARAM_FILTER
} param_type;
diff --git a/ui/gtk/dcerpc_stat.c b/ui/gtk/dcerpc_stat.c
index c8b2bda843..db13782aec 100644
--- a/ui/gtk/dcerpc_stat.c
+++ b/ui/gtk/dcerpc_stat.c
@@ -65,25 +65,6 @@ typedef struct _dcerpcstat_t {
} dcerpcstat_t;
-static gboolean
-uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
-{
- if( (uuid1->data1 != uuid2->data1)
- ||(uuid1->data2 != uuid2->data2)
- ||(uuid1->data3 != uuid2->data3)
- ||(uuid1->data4[0] != uuid2->data4[0])
- ||(uuid1->data4[1] != uuid2->data4[1])
- ||(uuid1->data4[2] != uuid2->data4[2])
- ||(uuid1->data4[3] != uuid2->data4[3])
- ||(uuid1->data4[4] != uuid2->data4[4])
- ||(uuid1->data4[5] != uuid2->data4[5])
- ||(uuid1->data4[6] != uuid2->data4[6])
- ||(uuid1->data4[7] != uuid2->data4[7]) ){
- return FALSE;
- }
- return TRUE;
-}
-
static char *
dcerpcstat_gen_title(dcerpcstat_t *rs)
{
@@ -363,7 +344,7 @@ dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer user_data)
GtkWidget *vers_combo_box = (GtkWidget *)user_data;
char vs[5];
- if(!uuid_equal(&(k->uuid), dcerpc_uuid_program)){
+ if(guid_cmp(&(k->uuid), dcerpc_uuid_program)){
return;
}
g_snprintf(vs, sizeof(vs), "%u", k->ver);
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 8d4bd77c0a..18d048d176 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -104,6 +104,7 @@ set(WIRESHARK_QT_HEADERS
related_packet_delegate.h
resolved_addresses_dialog.h
response_time_delay_dialog.h
+ rpc_service_response_time_dialog.h
rtp_analysis_dialog.h
rtp_stream_dialog.h
sctp_all_assocs_dialog.h
@@ -235,6 +236,7 @@ set(WIRESHARK_QT_SRC
related_packet_delegate.cpp
resolved_addresses_dialog.cpp
response_time_delay_dialog.cpp
+ rpc_service_response_time_dialog.cpp
rtp_analysis_dialog.cpp
rtp_stream_dialog.cpp
sctp_all_assocs_dialog.cpp
diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common
index e6cdf9463c..6ef2a70982 100644
--- a/ui/qt/Makefile.common
+++ b/ui/qt/Makefile.common
@@ -220,7 +220,7 @@ MOC_HDRS = \
remote_settings_dialog.h \
resolved_addresses_dialog.h \
response_time_delay_dialog.h \
- search_frame.h \
+ rpc_service_response_time_dialog.h \
rtp_analysis_dialog.h \
rtp_stream_dialog.h \
sctp_all_assocs_dialog.h \
@@ -229,6 +229,7 @@ MOC_HDRS = \
sctp_graph_dialog.h \
sctp_graph_arwnd_dialog.h \
sctp_graph_byte_dialog.h \
+ search_frame.h \
sequence_diagram.h \
sequence_dialog.h \
service_response_time_dialog.h \
@@ -462,6 +463,7 @@ WIRESHARK_QT_SRC = \
remote_settings_dialog.cpp \
resolved_addresses_dialog.cpp \
response_time_delay_dialog.cpp \
+ rpc_service_response_time_dialog.cpp \
rtp_analysis_dialog.cpp \
rtp_stream_dialog.cpp \
sctp_all_assocs_dialog.cpp \
diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro
index 1a899cff80..5358fbb3ea 100644
--- a/ui/qt/Wireshark.pro
+++ b/ui/qt/Wireshark.pro
@@ -628,6 +628,7 @@ HEADERS += \
recent_file_status.h \
related_packet_delegate.h \
response_time_delay_dialog.h \
+ rpc_service_response_time_dialog.h \
sequence_diagram.h \
sequence_dialog.h \
simple_dialog.h \
@@ -728,6 +729,7 @@ SOURCES += \
remote_settings_dialog.cpp \
response_time_delay_dialog.cpp \
resolved_addresses_dialog.cpp \
+ rpc_service_response_time_dialog.cpp \
rtp_analysis_dialog.cpp \
rtp_stream_dialog.cpp \
sctp_all_assocs_dialog.cpp \
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index d1aca488b3..25316dfdcb 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -115,6 +115,7 @@
#include "protocol_hierarchy_dialog.h"
#include "qt_ui_utils.h"
#include "resolved_addresses_dialog.h"
+#include "rpc_service_response_time_dialog.h"
#include "rtp_stream_dialog.h"
#include "rtp_analysis_dialog.h"
#include "sctp_all_assocs_dialog.h"
diff --git a/ui/qt/qt_ui_utils.cpp b/ui/qt/qt_ui_utils.cpp
index 58c55042e5..18be1b58ef 100644
--- a/ui/qt/qt_ui_utils.cpp
+++ b/ui/qt/qt_ui_utils.cpp
@@ -38,6 +38,7 @@
#include <QAction>
#include <QDateTime>
#include <QFontDatabase>
+#include <QUuid>
/* Make the format_size_flags_e enum usable in C++ */
format_size_flags_e operator|(format_size_flags_e lhs, format_size_flags_e rhs) {
@@ -187,6 +188,11 @@ bool qActionLessThan(const QAction * a1, const QAction * a2) {
return a1->text().compare(a2->text()) < 0;
}
+bool qStringCaseLessThan(const QString &s1, const QString &s2)
+{
+ return s1.compare(s2, Qt::CaseInsensitive) < 0;
+}
+
/*
* Editor modelines
*
diff --git a/ui/qt/qt_ui_utils.h b/ui/qt/qt_ui_utils.h
index b92c612b30..c94e1f1900 100644
--- a/ui/qt/qt_ui_utils.h
+++ b/ui/qt/qt_ui_utils.h
@@ -35,8 +35,8 @@
#include <QString>
-class QFont;
class QAction;
+class QFont;
#ifdef __cplusplus
extern "C" {
@@ -175,7 +175,15 @@ void smooth_font_size(QFont &font);
* @param a1 First action
* @param a2 Second action
*/
-bool qActionLessThan(const QAction * a1, const QAction * a2);
+bool qActionLessThan(const QAction *a1, const QAction *a2);
+
+/**
+ * Compare two QStrings, ignoring case. Useful for passing to std::sort.
+ *
+ * @param s1 First string
+ * @param s2 Second string
+ */
+bool qStringCaseLessThan(const QString &s1, const QString &s2);
#endif /* __QT_UI_UTILS__H__ */
diff --git a/ui/qt/rpc_service_response_time_dialog.cpp b/ui/qt/rpc_service_response_time_dialog.cpp
new file mode 100644
index 0000000000..39b07efc6a
--- /dev/null
+++ b/ui/qt/rpc_service_response_time_dialog.cpp
@@ -0,0 +1,436 @@
+/* rpc_service_response_time_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rpc_service_response_time_dialog.h"
+
+#include <stdio.h>
+
+#include <epan/dissectors/packet-dcerpc.h>
+#include <epan/dissectors/packet-rpc.h>
+#include <epan/guid-utils.h>
+#include <epan/srt_table.h>
+
+#include "qt_ui_utils.h"
+
+#include <QComboBox>
+#include <QHBoxLayout>
+#include <QLabel>
+
+// To do:
+// - Don't assume that the user knows what programs+versions are in the
+// capture. I.e. combine this dialog with the ONC-RPC Programs dialog,
+// with two lists: programs on top, procedures on the bottom.
+// - Allow the display of multiple programs and versions.
+// - Expose the DCE-RPC UUIDs and ONC-RPC program numbers e.g. in an extra
+// column.
+// - Make the version in the command-line args optional?
+
+extern "C" {
+static void
+dce_rpc_add_program(gpointer key_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
+{
+ RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
+ if (!rsrt_dlg) return;
+
+ dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
+ dcerpc_uuid_value *value = (dcerpc_uuid_value *)value_ptr;
+
+ rsrt_dlg->addDceRpcProgram(key, value);
+}
+
+static void
+dce_rpc_find_versions(gpointer key_ptr, gpointer, gpointer rsrtd_ptr)
+{
+ RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
+ if (!rsrt_dlg) return;
+
+ dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
+ rsrt_dlg->addDceRpcProgramVersion(key);
+}
+
+static void
+onc_rpc_add_program(gpointer prog_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
+{
+ RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
+ if (!rsrt_dlg) return;
+
+ guint32 program = GPOINTER_TO_UINT(prog_ptr);
+ rpc_prog_info_value *value = (rpc_prog_info_value *) value_ptr;
+
+ rsrt_dlg->addOncRpcProgram(program, value);
+}
+
+static void
+onc_rpc_find_versions(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
+{
+ RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
+ if (!rsrt_dlg) return;
+
+ rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
+
+ rsrt_dlg->addOncRpcProgramVersion(rpik->prog, rpik->vers);
+}
+
+static void
+onc_rpc_count_procedures(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
+{
+ RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
+ if (!rsrt_dlg) return;
+
+ rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
+
+ rsrt_dlg->updateOncRpcProcedureCount(rpik->prog, rpik->vers, rpik->proc);
+}
+
+} // extern "C"
+
+RpcServiceResponseTimeDialog::RpcServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, struct register_srt *srt, RpcFamily dlg_type, const QString filter) :
+ ServiceResponseTimeDialog(parent, cf, srt, filter),
+ dlg_type_(dlg_type)
+{
+ setRetapOnShow(false);
+ setHint(tr("<small><i>Select a program and version and enter a filter if desired, then press Apply.</i></small>"));
+
+ QHBoxLayout *filter_layout = filterLayout();
+ program_combo_ = new QComboBox(this);
+ version_combo_ = new QComboBox(this);
+
+ filter_layout->insertStretch(0, 1);
+ filter_layout->insertWidget(0, version_combo_);
+ filter_layout->insertWidget(0, new QLabel(tr("Version:")));
+ filter_layout->insertWidget(0, program_combo_);
+ filter_layout->insertWidget(0, new QLabel(tr("Program:")));
+
+ if (dlg_type == DceRpc) {
+ setWindowSubtitle(tr("DCE-RPC Service Response Times"));
+ g_hash_table_foreach(dcerpc_uuids, dce_rpc_add_program, this);
+ // This is a loooooong list. The GTK+ UI addresses this by making
+ // the program combo a tree instead of a list. We might want to add a
+ // full-height list to the left of the stats tree instead.
+ QStringList programs = dce_name_to_uuid_key_.keys();
+ std::sort(programs.begin(), programs.end(), qStringCaseLessThan);
+ connect(program_combo_, SIGNAL(currentIndexChanged(QString)),
+ this, SLOT(dceRpcProgramChanged(QString)));
+ program_combo_->addItems(programs);
+ } else {
+ setWindowSubtitle(tr("ONC-RPC Service Response Times"));
+ g_hash_table_foreach(rpc_progs, onc_rpc_add_program, this);
+ QStringList programs = onc_name_to_program_.keys();
+ std::sort(programs.begin(), programs.end(), qStringCaseLessThan);
+ connect(program_combo_, SIGNAL(currentIndexChanged(QString)),
+ this, SLOT(oncRpcProgramChanged(QString)));
+ program_combo_->addItems(programs);
+ }
+}
+
+TapParameterDialog *RpcServiceResponseTimeDialog::createDceRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
+{
+ QString filter;
+ bool have_args = false;
+ QString program_name;
+ e_guid_t uuid;
+ int version;
+
+ // dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]
+ QStringList args_l = QString(opt_arg).split(',');
+ if (args_l.length() > 1) {
+ // Alas, QUuid requires Qt 4.8.
+ unsigned d1, d2, d3, d4_0, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7;
+ if(sscanf(args_l[0].toUtf8().constData(),
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ &d1, &d2, &d3,
+ &d4_0, &d4_1, &d4_2, &d4_3, &d4_4, &d4_5, &d4_6, &d4_7) == 11) {
+ uuid.data1 = d1;
+ uuid.data2 = d2;
+ uuid.data3 = d3;
+ uuid.data4[0] = d4_0;
+ uuid.data4[1] = d4_1;
+ uuid.data4[2] = d4_2;
+ uuid.data4[3] = d4_3;
+ uuid.data4[4] = d4_4;
+ uuid.data4[5] = d4_5;
+ uuid.data4[6] = d4_6;
+ uuid.data4[7] = d4_7;
+ } else {
+ program_name = args_l[0];
+ }
+ version = args_l[1].split('.')[0].toInt();
+ if (args_l.length() > 2) {
+ filter = QStringList(args_l.mid(2)).join(",");
+ }
+ have_args = true;
+ }
+ RpcServiceResponseTimeDialog *dce_rpc_dlg = new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("dcerpc"), DceRpc, filter);
+
+ if (have_args) {
+ if (program_name.isEmpty()) {
+ dce_rpc_dlg->setDceRpcUuidAndVersion(&uuid, version);
+ } else {
+ dce_rpc_dlg->setRpcNameAndVersion(program_name, version);
+ }
+ }
+ // Else the GTK+ UI throws an error.
+
+ return dce_rpc_dlg;
+}
+
+TapParameterDialog *RpcServiceResponseTimeDialog::createOncRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
+{
+ QString filter;
+ bool have_args = false;
+ QString program_name;
+ int program_num;
+ int version;
+
+ // rpc,srt,<program>,<version>[,<filter>
+ QStringList args_l = QString(opt_arg).split(',');
+ if (args_l.length() > 1) {
+ bool ok = false;
+ program_num = args_l[0].toInt(&ok);
+ if (!ok) {
+ program_name = args_l[0];
+ }
+ version = args_l[1].toInt();
+ if (args_l.length() > 2) {
+ filter = QStringList(args_l.mid(2)).join(",");
+ }
+ have_args = true;
+ }
+
+ RpcServiceResponseTimeDialog *onc_rpc_dlg = new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("rpc"), OncRpc, filter);
+
+ if (have_args) {
+ if (program_name.isEmpty()) {
+ onc_rpc_dlg->setOncRpcProgramAndVersion(program_num, version);
+ } else {
+ onc_rpc_dlg->setRpcNameAndVersion(program_name, version);
+ }
+ }
+ // Else the GTK+ UI throws an error.
+
+ return onc_rpc_dlg;
+}
+
+void RpcServiceResponseTimeDialog::addDceRpcProgram(_dcerpc_uuid_key *key, _dcerpc_uuid_value *value)
+{
+ dce_name_to_uuid_key_.insert(value->name, key);
+}
+
+void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_dcerpc_uuid_key *key)
+{
+ if (guid_cmp(&(dce_name_to_uuid_key_[program_combo_->currentText()]->uuid), &(key->uuid))) return;
+
+ versions_ << key->ver;
+ std::sort(versions_.begin(), versions_.end());
+}
+
+void RpcServiceResponseTimeDialog::addOncRpcProgram(guint32 program, _rpc_prog_info_value *value)
+{
+ onc_name_to_program_.insert(value->progname, program);
+}
+
+void RpcServiceResponseTimeDialog::addOncRpcProgramVersion(guint32 program, guint32 version)
+{
+ if (onc_name_to_program_[program_combo_->currentText()] != program) return;
+
+ if (versions_.isEmpty()) {
+ versions_ << version;
+ return;
+ }
+ while (version < versions_.first()) {
+ versions_.prepend(versions_.first() - 1);
+ }
+ while (version > versions_.last()) {
+ versions_.append(versions_.last() + 1);
+ }
+}
+
+void RpcServiceResponseTimeDialog::updateOncRpcProcedureCount(guint32 program, guint32 version, int procedure)
+{
+ if (onc_name_to_program_[program_combo_->currentText()] != program) return;
+ if (version_combo_->itemData(version_combo_->currentIndex()).toUInt() != version) return;
+
+ if (procedure > onc_rpc_num_procedures_) onc_rpc_num_procedures_ = procedure;
+}
+
+void RpcServiceResponseTimeDialog::setDceRpcUuidAndVersion(_e_guid_t *uuid, int version)
+{
+ bool found = false;
+ for (int pi = 0; pi < program_combo_->count(); pi++) {
+ if (guid_cmp(uuid, &(dce_name_to_uuid_key_[program_combo_->itemText(pi)]->uuid)) == 0) {
+ program_combo_->setCurrentIndex(pi);
+
+ for (int vi = 0; vi < version_combo_->count(); vi++) {
+ if (version == (int) version_combo_->itemData(vi).toUInt()) {
+ version_combo_->setCurrentIndex(vi);
+ found = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (found) fillTree();
+}
+
+void RpcServiceResponseTimeDialog::setOncRpcProgramAndVersion(int program, int version)
+{
+ bool found = false;
+ for (int pi = 0; pi < program_combo_->count(); pi++) {
+ if (program == (int) onc_name_to_program_[program_combo_->itemText(pi)]) {
+ program_combo_->setCurrentIndex(pi);
+
+ for (int vi = 0; vi < version_combo_->count(); vi++) {
+ if (version == (int) version_combo_->itemData(vi).toUInt()) {
+ version_combo_->setCurrentIndex(vi);
+ found = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (found) fillTree();
+}
+
+void RpcServiceResponseTimeDialog::setRpcNameAndVersion(const QString &program_name, int version)
+{
+ bool found = false;
+ for (int pi = 0; pi < program_combo_->count(); pi++) {
+ if (program_name.compare(program_combo_->itemText(pi), Qt::CaseInsensitive) == 0) {
+ program_combo_->setCurrentIndex(pi);
+
+ for (int vi = 0; vi < version_combo_->count(); vi++) {
+ if (version == (int) version_combo_->itemData(vi).toUInt()) {
+ version_combo_->setCurrentIndex(vi);
+ found = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (found) fillTree();
+}
+
+void RpcServiceResponseTimeDialog::dceRpcProgramChanged(const QString &program_name)
+{
+ clearVersionCombo();
+
+ if (!dce_name_to_uuid_key_.contains(program_name)) return;
+
+ g_hash_table_foreach(dcerpc_uuids, dce_rpc_find_versions, this);
+
+ fillVersionCombo();
+}
+
+void RpcServiceResponseTimeDialog::oncRpcProgramChanged(const QString &program_name)
+{
+ clearVersionCombo();
+
+ if (!onc_name_to_program_.contains(program_name)) return;
+
+ dissector_table_foreach ("rpc.call", onc_rpc_find_versions, this);
+ dissector_table_foreach ("rpc.reply", onc_rpc_find_versions, this);
+
+ fillVersionCombo();
+}
+
+void RpcServiceResponseTimeDialog::clearVersionCombo()
+{
+ version_combo_->clear();
+ versions_.clear();
+}
+
+void RpcServiceResponseTimeDialog::fillVersionCombo()
+{
+ foreach (unsigned version, versions_) {
+ version_combo_->addItem(QString::number(version), version);
+ }
+ if (versions_.count() > 0) {
+ // Select the highest-numbered version.
+ version_combo_->setCurrentIndex(versions_.count() - 1);
+ }
+}
+
+void RpcServiceResponseTimeDialog::fillTree()
+{
+ void *tap_data = NULL;
+ const QString program_name = program_combo_->currentText();
+ guint32 max_procs = 0;
+
+ switch (dlg_type_) {
+ case DceRpc:
+ {
+ if (!dce_name_to_uuid_key_.contains(program_name)) return;
+
+ dcerpc_uuid_key *dkey = dce_name_to_uuid_key_[program_name];
+ dcerpcstat_tap_data_t *dtap_data = g_new0(dcerpcstat_tap_data_t, 1);
+ dtap_data->uuid = dkey->uuid;
+ dtap_data->prog = program_name.toUtf8().constData();
+ dtap_data->ver = (guint16) version_combo_->itemData(version_combo_->currentIndex()).toUInt();
+
+ dcerpc_sub_dissector *procs = dcerpc_get_proto_sub_dissector(&(dkey->uuid), dtap_data->ver);
+ for (int i = 0; procs[i].name; i++) {
+ if (procs[i].num > max_procs) max_procs = procs[i].num;
+ }
+ dtap_data->num_procedures = max_procs + 1;
+
+ tap_data = dtap_data;
+ break;
+ }
+ case OncRpc:
+ {
+ if (!onc_name_to_program_.contains(program_name)) return;
+
+ rpcstat_tap_data_t *otap_data = g_new0(rpcstat_tap_data_t, 1);
+ otap_data->prog = program_name.toUtf8().constData();
+ otap_data->program = onc_name_to_program_[program_name];
+ otap_data->version = (guint32) version_combo_->itemData(version_combo_->currentIndex()).toUInt();
+
+ onc_rpc_num_procedures_ = -1;
+ dissector_table_foreach ("rpc.call", onc_rpc_count_procedures, this);
+ dissector_table_foreach ("rpc.reply", onc_rpc_count_procedures, this);
+ otap_data->num_procedures = onc_rpc_num_procedures_ + 1;
+
+ tap_data = otap_data;
+ break;
+ }
+ }
+
+ set_srt_table_param_data(srt_, tap_data);
+
+ ServiceResponseTimeDialog::fillTree();
+ g_free(tap_data);
+}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/rpc_service_response_time_dialog.h b/ui/qt/rpc_service_response_time_dialog.h
new file mode 100644
index 0000000000..0814bd68c9
--- /dev/null
+++ b/ui/qt/rpc_service_response_time_dialog.h
@@ -0,0 +1,96 @@
+/* rpc_service_response_time_dialog.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __RPC_SERVICE_RESPONSE_TIME_DIALOG_H__
+#define __RPC_SERVICE_RESPONSE_TIME_DIALOG_H__
+
+#include "service_response_time_dialog.h"
+
+class QComboBox;
+
+struct _dcerpc_uuid_key;
+struct _dcerpc_uuid_value;
+struct _e_guid_t;
+struct _rpc_prog_info_value;
+
+class RpcServiceResponseTimeDialog : public ServiceResponseTimeDialog
+{
+ Q_OBJECT
+
+public:
+ enum RpcFamily {
+ DceRpc,
+ OncRpc
+ };
+
+ RpcServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, struct register_srt *srt, RpcFamily dlg_type, const QString filter);
+ static TapParameterDialog *createDceRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf);
+ static TapParameterDialog *createOncRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf);
+
+ void addDceRpcProgram(_dcerpc_uuid_key *key, struct _dcerpc_uuid_value *value);
+ void addDceRpcProgramVersion(_dcerpc_uuid_key *key);
+ void addOncRpcProgram(guint32 program, struct _rpc_prog_info_value *value);
+ void addOncRpcProgramVersion(guint32 program, guint32 version);
+ void updateOncRpcProcedureCount(guint32 program, guint32 version, int procedure);
+
+ void setDceRpcUuidAndVersion(struct _e_guid_t *uuid, int version);
+ void setOncRpcProgramAndVersion(int program, int version);
+ void setRpcNameAndVersion(const QString &program_name, int version);
+
+public slots:
+ void dceRpcProgramChanged(const QString &program_name);
+ void oncRpcProgramChanged(const QString &program_name);
+
+protected:
+ virtual void fillTree();
+
+private:
+ RpcFamily dlg_type_;
+ QComboBox *program_combo_;
+ QComboBox *version_combo_;
+ QList<unsigned> versions_;
+
+ // DCE-RPC
+ QMap<QString, struct _dcerpc_uuid_key *> dce_name_to_uuid_key_;
+
+ // ONC-RPC
+ QMap<QString, guint32> onc_name_to_program_;
+ int onc_rpc_num_procedures_;
+
+ void clearVersionCombo();
+ void fillVersionCombo();
+
+};
+
+#endif // __RPC_SERVICE_RESPONSE_TIME_DIALOG_H__
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/ui/qt/service_response_time_dialog.cpp b/ui/qt/service_response_time_dialog.cpp
index 407f1ad62b..80381acb57 100644
--- a/ui/qt/service_response_time_dialog.cpp
+++ b/ui/qt/service_response_time_dialog.cpp
@@ -27,6 +27,7 @@
#include <ui/service_response_time.h>
+#include "rpc_service_response_time_dialog.h"
#include "wireshark_application.h"
#include <QMessageBox>
@@ -55,12 +56,17 @@ void register_service_response_tables(gpointer data, gpointer)
register_srt_t *srt = (register_srt_t*)data;
const char* short_name = proto_get_protocol_short_name(find_protocol_by_id(get_srt_proto_id(srt)));
const char *cfg_abbr = srt_table_get_tap_string(srt);
+ tpdCreator tpd_creator = ServiceResponseTimeDialog::createSrtDialog;
/* XXX - These dissectors haven't been converted over to due to an "interactive input dialog" for their
tap data. Let those specific dialogs register for themselves */
- if ((strcmp(short_name, "RPC") == 0) ||
- (strcmp(short_name, "DCERPC") == 0))
- return;
+ if (strcmp(short_name, "DCERPC") == 0) {
+ short_name = "DCE-RPC";
+ tpd_creator = RpcServiceResponseTimeDialog::createDceRpcSrtDialog;
+ } else if (strcmp(short_name, "RPC") == 0) {
+ short_name = "ONC-RPC";
+ tpd_creator = RpcServiceResponseTimeDialog::createOncRpcSrtDialog;
+ }
cfg_str_to_srt_[cfg_abbr] = srt;
TapParameterDialog::registerDialog(
@@ -68,7 +74,7 @@ void register_service_response_tables(gpointer data, gpointer)
cfg_abbr,
REGISTER_STAT_GROUP_RESPONSE_TIME,
srt_init,
- ServiceResponseTimeDialog::createSrtDialog);
+ tpd_creator);
}
enum {
@@ -312,6 +318,7 @@ void ServiceResponseTimeDialog::fillTree()
QMessageBox::critical(this, tr("Failed to attach to tap \"%1\"").arg(get_srt_tap_listener_name(srt_)),
error_string->str);
g_string_free(error_string, TRUE);
+ g_array_free(srt_data.srt_array, TRUE);
reject();
}
@@ -330,6 +337,7 @@ void ServiceResponseTimeDialog::fillTree()
statsTreeWidget()->setSortingEnabled(true);
remove_tap_listener(&srt_data);
+ g_array_free(srt_data.srt_array, TRUE);
}
QList<QVariant> ServiceResponseTimeDialog::treeItemData(QTreeWidgetItem *ti) const
diff --git a/ui/qt/service_response_time_dialog.h b/ui/qt/service_response_time_dialog.h
index 77289cef20..09bd7dbabc 100644
--- a/ui/qt/service_response_time_dialog.h
+++ b/ui/qt/service_response_time_dialog.h
@@ -38,6 +38,8 @@ public:
static TapParameterDialog *createSrtDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf);
protected:
+ struct register_srt *srt_;
+
/** Add a service response time table.
*
* In the GTK+ UI "tables" are separate, tabbed widgets. In the Qt UI they are
@@ -47,15 +49,13 @@ protected:
*/
// gtk:service_response_table.h:init_srt_table
void addSrtTable(const struct _srt_stat_table *srt_table);
+ virtual void fillTree();
private:
- struct register_srt *srt_;
-
// Callbacks for register_tap_listener
static void tapReset(void *srtd_ptr);
static void tapDraw(void *srtd_ptr);
- virtual void fillTree();
virtual QList<QVariant> treeItemData(QTreeWidgetItem *ti) const;
virtual const QString filterExpression();
diff --git a/ui/qt/tap_parameter_dialog.cpp b/ui/qt/tap_parameter_dialog.cpp
index 5e727e7268..dc44201fd9 100644
--- a/ui/qt/tap_parameter_dialog.cpp
+++ b/ui/qt/tap_parameter_dialog.cpp
@@ -75,13 +75,17 @@ const QString TapParameterDialog::action_name_ = "TapParameterAction";
TapParameterDialog::TapParameterDialog(QWidget &parent, CaptureFile &cf, int help_topic) :
WiresharkDialog(parent, cf),
ui(new Ui::TapParameterDialog),
- help_topic_(help_topic)
+ help_topic_(help_topic),
+ retap_on_show_(true)
{
ui->setupUi(this);
// XXX Use recent settings instead
resize(parent.width() * 2 / 3, parent.height() * 3 / 4);
+ // Only show a hint label if a subclass provides a hint.
+ ui->hintLabel->hide();
+
ctx_menu_.addAction(ui->actionCopyToClipboard);
ctx_menu_.addAction(ui->actionSaveAs);
@@ -137,6 +141,11 @@ QTreeWidget *TapParameterDialog::statsTreeWidget()
return ui->statsTreeWidget;
}
+QHBoxLayout *TapParameterDialog::filterLayout()
+{
+ return ui->filterLayout;
+}
+
const char *TapParameterDialog::displayFilter()
{
return ui->displayFilterLineEdit->text().toUtf8().constData();
@@ -149,6 +158,12 @@ void TapParameterDialog::setDisplayFilter(const QString &filter)
ui->displayFilterLineEdit->setText(filter);
}
+void TapParameterDialog::setHint(const QString &hint)
+{
+ ui->hintLabel->setText(hint);
+ ui->hintLabel->show();
+}
+
void TapParameterDialog::filterActionTriggered()
{
FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
@@ -394,7 +409,7 @@ void TapParameterDialog::showEvent(QShowEvent *)
QString filter = ui->displayFilterLineEdit->text();
emit updateFilter(filter, true);
}
- fillTree();
+ if (retap_on_show_) fillTree();
}
void TapParameterDialog::contextMenuEvent(QContextMenuEvent *event)
diff --git a/ui/qt/tap_parameter_dialog.h b/ui/qt/tap_parameter_dialog.h
index f9af3391bd..51613db31a 100644
--- a/ui/qt/tap_parameter_dialog.h
+++ b/ui/qt/tap_parameter_dialog.h
@@ -34,6 +34,7 @@
#include "filter_action.h"
#include "wireshark_dialog.h"
+class QHBoxLayout;
class QTreeWidget;
class QTreeWidgetItem;
@@ -59,6 +60,8 @@ public:
// Needed by static member functions in subclasses. Should we just make
// "ui" available instead?
QTreeWidget *statsTreeWidget();
+ QHBoxLayout *filterLayout();
+
void drawTreeItems();
signals:
@@ -75,6 +78,9 @@ protected:
void contextMenuEvent(QContextMenuEvent *event);
const char *displayFilter();
void setDisplayFilter(const QString &filter);
+ void setHint(const QString &hint);
+ // Retap packets on showEvent. RPC stats need to disable this.
+ void setRetapOnShow(bool retap = false) { retap_on_show_ = retap; }
protected slots:
void filterActionTriggered();
@@ -83,6 +89,7 @@ private:
Ui::TapParameterDialog *ui;
int help_topic_;
static const QString action_name_;
+ bool retap_on_show_;
// Called by the constructor. The subclass should tap packets here.
virtual void fillTree() = 0;
diff --git a/ui/qt/tap_parameter_dialog.ui b/ui/qt/tap_parameter_dialog.ui
index 887770ebf2..c7c624fc1c 100644
--- a/ui/qt/tap_parameter_dialog.ui
+++ b/ui/qt/tap_parameter_dialog.ui
@@ -24,7 +24,14 @@
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <widget class="QLabel" name="hintLabel">
+ <property name="text">
+ <string>&lt;small&gt;&lt;i&gt;A hint.&lt;/i&gt;&lt;/small&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="filterLayout" stretch="0,2,0">
<item>
<widget class="QLabel" name="label">
<property name="text">
@@ -88,6 +95,7 @@
<header>display_filter_edit.h</header>
</customwidget>
</customwidgets>
+ <resources/>
<connections>
<connection>
<sender>buttonBox</sender>