1 /* rpc_service_response_time_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
13 #pragma warning(disable : 4267)
16 #include "rpc_service_response_time_dialog.h"
21 #include <epan/dissectors/packet-dcerpc.h>
22 #include <epan/dissectors/packet-rpc.h>
23 #include <epan/guid-utils.h>
24 #include <epan/srt_table.h>
26 #include <ui/qt/utils/qt_ui_utils.h>
29 #include <QHBoxLayout>
37 // - Don't assume that the user knows what programs+versions are in the
38 // capture. I.e. combine this dialog with the ONC-RPC Programs dialog,
39 // with two lists: programs on top, procedures on the bottom.
40 // - Allow the display of multiple programs and versions.
41 // - Expose the DCE-RPC UUIDs and ONC-RPC program numbers e.g. in an extra
43 // - Make the version in the command-line args optional?
47 dce_rpc_add_program(void *key_ptr
, void *value_ptr
, void *rsrtd_ptr
)
49 RpcServiceResponseTimeDialog
*rsrt_dlg
= dynamic_cast<RpcServiceResponseTimeDialog
*>((RpcServiceResponseTimeDialog
*)rsrtd_ptr
);
50 if (!rsrt_dlg
) return;
52 guid_key
*key
= (guid_key
*)key_ptr
;
53 dcerpc_uuid_value
*value
= (dcerpc_uuid_value
*)value_ptr
;
55 rsrt_dlg
->addDceRpcProgram(key
, value
);
59 dce_rpc_find_versions(void *key_ptr
, void *, void *rsrtd_ptr
)
61 RpcServiceResponseTimeDialog
*rsrt_dlg
= dynamic_cast<RpcServiceResponseTimeDialog
*>((RpcServiceResponseTimeDialog
*)rsrtd_ptr
);
62 if (!rsrt_dlg
) return;
64 guid_key
*key
= (guid_key
*)key_ptr
;
65 rsrt_dlg
->addDceRpcProgramVersion(key
);
69 onc_rpc_add_program(void *prog_ptr
, void *value_ptr
, void *rsrtd_ptr
)
71 RpcServiceResponseTimeDialog
*rsrt_dlg
= dynamic_cast<RpcServiceResponseTimeDialog
*>((RpcServiceResponseTimeDialog
*)rsrtd_ptr
);
72 if (!rsrt_dlg
) return;
74 uint32_t program
= GPOINTER_TO_UINT(prog_ptr
);
75 rpc_prog_info_value
*value
= (rpc_prog_info_value
*) value_ptr
;
77 rsrt_dlg
->addOncRpcProgram(program
, value
);
81 onc_rpc_find_versions(const char *, ftenum_t
, void *rpik_ptr
, void *, void *rsrtd_ptr
)
83 RpcServiceResponseTimeDialog
*rsrt_dlg
= dynamic_cast<RpcServiceResponseTimeDialog
*>((RpcServiceResponseTimeDialog
*)rsrtd_ptr
);
84 if (!rsrt_dlg
) return;
86 rpc_proc_info_key
*rpik
= (rpc_proc_info_key
*)rpik_ptr
;
88 rsrt_dlg
->addOncRpcProgramVersion(rpik
->prog
, rpik
->vers
);
92 onc_rpc_count_procedures(const char *, ftenum_t
, void *rpik_ptr
, void *, void *rsrtd_ptr
)
94 RpcServiceResponseTimeDialog
*rsrt_dlg
= dynamic_cast<RpcServiceResponseTimeDialog
*>((RpcServiceResponseTimeDialog
*)rsrtd_ptr
);
95 if (!rsrt_dlg
) return;
97 rpc_proc_info_key
*rpik
= (rpc_proc_info_key
*)rpik_ptr
;
99 rsrt_dlg
->updateOncRpcProcedureCount(rpik
->prog
, rpik
->vers
, rpik
->proc
);
104 RpcServiceResponseTimeDialog::RpcServiceResponseTimeDialog(QWidget
&parent
, CaptureFile
&cf
, struct register_srt
*srt
, RpcFamily dlg_type
, const QString filter
) :
105 ServiceResponseTimeDialog(parent
, cf
, srt
, filter
),
108 setRetapOnShow(false);
109 setHint(tr("<small><i>Select a program and version and enter a filter if desired, then press Apply.</i></small>"));
111 QHBoxLayout
*filter_layout
= filterLayout();
112 program_combo_
= new QComboBox(this);
113 version_combo_
= new QComboBox(this);
115 filter_layout
->insertStretch(0, 1);
116 filter_layout
->insertWidget(0, version_combo_
);
117 filter_layout
->insertWidget(0, new QLabel(tr("Version:")));
118 filter_layout
->insertWidget(0, program_combo_
);
119 filter_layout
->insertWidget(0, new QLabel(tr("Program:")));
121 if (dlg_type
== DceRpc
) {
122 setWindowSubtitle(tr("DCE-RPC Service Response Times"));
123 g_hash_table_foreach(dcerpc_uuids
, dce_rpc_add_program
, this);
124 // This is a loooooong list. The GTK+ UI addresses this by making
125 // the program combo a tree instead of a list. We might want to add a
126 // full-height list to the left of the stats tree instead.
127 QStringList programs
= dce_name_to_uuid_key_
.keys();
128 std::sort(programs
.begin(), programs
.end(), qStringCaseLessThan
);
129 connect(program_combo_
, SIGNAL(currentTextChanged(const QString
)),
130 this, SLOT(dceRpcProgramChanged(const QString
)));
131 program_combo_
->addItems(programs
);
133 setWindowSubtitle(tr("ONC-RPC Service Response Times"));
134 g_hash_table_foreach(rpc_progs
, onc_rpc_add_program
, this);
135 QStringList programs
= onc_name_to_program_
.keys();
136 std::sort(programs
.begin(), programs
.end(), qStringCaseLessThan
);
137 connect(program_combo_
, SIGNAL(currentTextChanged(const QString
)),
138 this, SLOT(oncRpcProgramChanged(const QString
)));
139 program_combo_
->addItems(programs
);
143 TapParameterDialog
*RpcServiceResponseTimeDialog::createDceRpcSrtDialog(QWidget
&parent
, const QString
, const QString opt_arg
, CaptureFile
&cf
)
146 bool have_args
= false;
147 QString program_name
;
151 // dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]
152 QStringList args_l
= QString(opt_arg
).split(',');
153 if (args_l
.length() > 1) {
154 // XXX Switch to QUuid.
155 unsigned d1
, d2
, d3
, d4_0
, d4_1
, d4_2
, d4_3
, d4_4
, d4_5
, d4_6
, d4_7
;
156 if (sscanf(args_l
[0].toUtf8().constData(),
157 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
159 &d4_0
, &d4_1
, &d4_2
, &d4_3
, &d4_4
, &d4_5
, &d4_6
, &d4_7
) == 11) {
163 uuid
.data4
[0] = d4_0
;
164 uuid
.data4
[1] = d4_1
;
165 uuid
.data4
[2] = d4_2
;
166 uuid
.data4
[3] = d4_3
;
167 uuid
.data4
[4] = d4_4
;
168 uuid
.data4
[5] = d4_5
;
169 uuid
.data4
[6] = d4_6
;
170 uuid
.data4
[7] = d4_7
;
172 program_name
= args_l
[0];
174 version
= args_l
[1].split('.')[0].toInt();
175 if (args_l
.length() > 2) {
176 filter
= QStringList(args_l
.mid(2)).join(",");
180 RpcServiceResponseTimeDialog
*dce_rpc_dlg
= new RpcServiceResponseTimeDialog(parent
, cf
, get_srt_table_by_name("dcerpc"), DceRpc
, filter
);
183 if (program_name
.isEmpty()) {
184 dce_rpc_dlg
->setDceRpcUuidAndVersion(&uuid
, version
);
186 dce_rpc_dlg
->setRpcNameAndVersion(program_name
, version
);
189 // Else the GTK+ UI throws an error.
194 TapParameterDialog
*RpcServiceResponseTimeDialog::createOncRpcSrtDialog(QWidget
&parent
, const QString
, const QString opt_arg
, CaptureFile
&cf
)
197 bool have_args
= false;
198 QString program_name
;
202 // rpc,srt,<program>,<version>[,<filter>
203 QStringList args_l
= QString(opt_arg
).split(',');
204 if (args_l
.length() > 1) {
206 program_num
= args_l
[0].toInt(&ok
);
208 program_name
= args_l
[0];
210 version
= args_l
[1].toInt();
211 if (args_l
.length() > 2) {
212 filter
= QStringList(args_l
.mid(2)).join(",");
217 RpcServiceResponseTimeDialog
*onc_rpc_dlg
= new RpcServiceResponseTimeDialog(parent
, cf
, get_srt_table_by_name("rpc"), OncRpc
, filter
);
220 if (program_name
.isEmpty()) {
221 onc_rpc_dlg
->setOncRpcProgramAndVersion(program_num
, version
);
223 onc_rpc_dlg
->setRpcNameAndVersion(program_name
, version
);
226 // Else the GTK+ UI throws an error.
231 void RpcServiceResponseTimeDialog::addDceRpcProgram(_guid_key
*key
, _dcerpc_uuid_value
*value
)
233 dce_name_to_uuid_key_
.insert(value
->name
, key
);
236 void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_guid_key
*key
)
238 if (guid_cmp(&(dce_name_to_uuid_key_
[program_combo_
->currentText()]->guid
), &(key
->guid
))) return;
240 versions_
<< key
->ver
;
241 std::sort(versions_
.begin(), versions_
.end());
244 void RpcServiceResponseTimeDialog::addOncRpcProgram(uint32_t program
, _rpc_prog_info_value
*value
)
246 onc_name_to_program_
.insert(value
->progname
, program
);
249 void RpcServiceResponseTimeDialog::addOncRpcProgramVersion(uint32_t program
, uint32_t version
)
251 if (onc_name_to_program_
[program_combo_
->currentText()] != program
) return;
253 if (versions_
.isEmpty()) {
254 versions_
<< version
;
257 while (version
< versions_
.first()) {
258 versions_
.prepend(versions_
.first() - 1);
260 while (version
> versions_
.last()) {
261 versions_
.append(versions_
.last() + 1);
265 void RpcServiceResponseTimeDialog::updateOncRpcProcedureCount(uint32_t program
, uint32_t version
, int procedure
)
267 if (onc_name_to_program_
[program_combo_
->currentText()] != program
) return;
268 if (version_combo_
->itemData(version_combo_
->currentIndex()).toUInt() != version
) return;
270 if (procedure
> onc_rpc_num_procedures_
) onc_rpc_num_procedures_
= procedure
;
273 void RpcServiceResponseTimeDialog::setDceRpcUuidAndVersion(_e_guid_t
*uuid
, int version
)
276 for (int pi
= 0; pi
< program_combo_
->count(); pi
++) {
277 if (guid_cmp(uuid
, &(dce_name_to_uuid_key_
[program_combo_
->itemText(pi
)]->guid
)) == 0) {
278 program_combo_
->setCurrentIndex(pi
);
280 for (int vi
= 0; vi
< version_combo_
->count(); vi
++) {
281 if (version
== (int) version_combo_
->itemData(vi
).toUInt()) {
282 version_combo_
->setCurrentIndex(vi
);
290 if (found
) fillTree();
293 void RpcServiceResponseTimeDialog::setOncRpcProgramAndVersion(int program
, int version
)
296 for (int pi
= 0; pi
< program_combo_
->count(); pi
++) {
297 if (program
== (int) onc_name_to_program_
[program_combo_
->itemText(pi
)]) {
298 program_combo_
->setCurrentIndex(pi
);
300 for (int vi
= 0; vi
< version_combo_
->count(); vi
++) {
301 if (version
== (int) version_combo_
->itemData(vi
).toUInt()) {
302 version_combo_
->setCurrentIndex(vi
);
310 if (found
) fillTree();
313 void RpcServiceResponseTimeDialog::setRpcNameAndVersion(const QString
&program_name
, int version
)
316 for (int pi
= 0; pi
< program_combo_
->count(); pi
++) {
317 if (program_name
.compare(program_combo_
->itemText(pi
), Qt::CaseInsensitive
) == 0) {
318 program_combo_
->setCurrentIndex(pi
);
320 for (int vi
= 0; vi
< version_combo_
->count(); vi
++) {
321 if (version
== (int) version_combo_
->itemData(vi
).toUInt()) {
322 version_combo_
->setCurrentIndex(vi
);
330 if (found
) fillTree();
333 void RpcServiceResponseTimeDialog::dceRpcProgramChanged(const QString
&program_name
)
337 if (!dce_name_to_uuid_key_
.contains(program_name
)) return;
339 g_hash_table_foreach(dcerpc_uuids
, dce_rpc_find_versions
, this);
344 void RpcServiceResponseTimeDialog::oncRpcProgramChanged(const QString
&program_name
)
348 if (!onc_name_to_program_
.contains(program_name
)) return;
350 dissector_table_foreach ("rpc.call", onc_rpc_find_versions
, this);
351 dissector_table_foreach ("rpc.reply", onc_rpc_find_versions
, this);
356 void RpcServiceResponseTimeDialog::clearVersionCombo()
358 version_combo_
->clear();
362 void RpcServiceResponseTimeDialog::fillVersionCombo()
364 foreach (unsigned version
, versions_
) {
365 version_combo_
->addItem(QString::number(version
), version
);
367 if (versions_
.count() > 0) {
368 // Select the highest-numbered version.
369 version_combo_
->setCurrentIndex(static_cast<int>(versions_
.count()) - 1);
373 void RpcServiceResponseTimeDialog::provideParameterData()
375 void *tap_data
= NULL
;
376 const QString program_name
= program_combo_
->currentText();
377 uint32_t max_procs
= 0;
382 if (!dce_name_to_uuid_key_
.contains(program_name
)) return;
384 guid_key
*dkey
= dce_name_to_uuid_key_
[program_name
];
385 uint16_t version
= (uint16_t) version_combo_
->itemData(version_combo_
->currentIndex()).toUInt();
386 const dcerpc_sub_dissector
*procs
= dcerpc_get_proto_sub_dissector(&(dkey
->guid
), version
);
389 dcerpcstat_tap_data_t
*dtap_data
= g_new0(dcerpcstat_tap_data_t
, 1);
390 dtap_data
->uuid
= dkey
->guid
;
391 dtap_data
->ver
= version
;
392 dtap_data
->prog
= dcerpc_get_proto_name(&dtap_data
->uuid
, dtap_data
->ver
);
394 for (int i
= 0; procs
[i
].name
; i
++) {
395 if (procs
[i
].num
> max_procs
) max_procs
= procs
[i
].num
;
397 dtap_data
->num_procedures
= max_procs
+ 1;
399 tap_data
= dtap_data
;
404 if (!onc_name_to_program_
.contains(program_name
)) return;
406 rpcstat_tap_data_t
*otap_data
= g_new0(rpcstat_tap_data_t
, 1);
407 otap_data
->program
= onc_name_to_program_
[program_name
];
408 otap_data
->prog
= rpc_prog_name(otap_data
->program
);
409 otap_data
->version
= (uint32_t) version_combo_
->itemData(version_combo_
->currentIndex()).toUInt();
411 onc_rpc_num_procedures_
= -1;
412 dissector_table_foreach ("rpc.call", onc_rpc_count_procedures
, this);
413 dissector_table_foreach ("rpc.reply", onc_rpc_count_procedures
, this);
414 otap_data
->num_procedures
= onc_rpc_num_procedures_
+ 1;
416 tap_data
= otap_data
;
421 set_srt_table_param_data(srt_
, tap_data
);