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 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
25 #pragma warning(disable : 4267)
28 #include "rpc_service_response_time_dialog.h"
33 #include <epan/dissectors/packet-dcerpc.h>
34 #include <epan/dissectors/packet-rpc.h>
35 #include <epan/guid-utils.h>
36 #include <epan/srt_table.h>
38 #include "qt_ui_utils.h"
41 #include <QHBoxLayout>
49 // - Don't assume that the user knows what programs+versions are in the
50 // capture. I.e. combine this dialog with the ONC-RPC Programs dialog,
51 // with two lists: programs on top, procedures on the bottom.
52 // - Allow the display of multiple programs and versions.
53 // - Expose the DCE-RPC UUIDs and ONC-RPC program numbers e.g. in an extra
55 // - Make the version in the command-line args optional?
59 dce_rpc_add_program(gpointer key_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
61 RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
62 if (!rsrt_dlg) return;
64 dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
65 dcerpc_uuid_value *value = (dcerpc_uuid_value *)value_ptr;
67 rsrt_dlg->addDceRpcProgram(key, value);
71 dce_rpc_find_versions(gpointer key_ptr, gpointer, gpointer rsrtd_ptr)
73 RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
74 if (!rsrt_dlg) return;
76 dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
77 rsrt_dlg->addDceRpcProgramVersion(key);
81 onc_rpc_add_program(gpointer prog_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
83 RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
84 if (!rsrt_dlg) return;
86 guint32 program = GPOINTER_TO_UINT(prog_ptr);
87 rpc_prog_info_value *value = (rpc_prog_info_value *) value_ptr;
89 rsrt_dlg->addOncRpcProgram(program, value);
93 onc_rpc_find_versions(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
95 RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
96 if (!rsrt_dlg) return;
98 rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
100 rsrt_dlg->addOncRpcProgramVersion(rpik->prog, rpik->vers);
104 onc_rpc_count_procedures(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
106 RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
107 if (!rsrt_dlg) return;
109 rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
111 rsrt_dlg->updateOncRpcProcedureCount(rpik->prog, rpik->vers, rpik->proc);
116 RpcServiceResponseTimeDialog::RpcServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, struct register_srt *srt, RpcFamily dlg_type, const QString filter) :
117 ServiceResponseTimeDialog(parent, cf, srt, filter),
120 setRetapOnShow(false);
121 setHint(tr("<small><i>Select a program and version and enter a filter if desired, then press Apply.</i></small>"));
123 QHBoxLayout *filter_layout = filterLayout();
124 program_combo_ = new QComboBox(this);
125 version_combo_ = new QComboBox(this);
127 filter_layout->insertStretch(0, 1);
128 filter_layout->insertWidget(0, version_combo_);
129 filter_layout->insertWidget(0, new QLabel(tr("Version:")));
130 filter_layout->insertWidget(0, program_combo_);
131 filter_layout->insertWidget(0, new QLabel(tr("Program:")));
133 if (dlg_type == DceRpc) {
134 setWindowSubtitle(tr("DCE-RPC Service Response Times"));
135 g_hash_table_foreach(dcerpc_uuids, dce_rpc_add_program, this);
136 // This is a loooooong list. The GTK+ UI addresses this by making
137 // the program combo a tree instead of a list. We might want to add a
138 // full-height list to the left of the stats tree instead.
139 QStringList programs = dce_name_to_uuid_key_.keys();
140 std::sort(programs.begin(), programs.end(), qStringCaseLessThan);
141 connect(program_combo_, SIGNAL(currentIndexChanged(QString)),
142 this, SLOT(dceRpcProgramChanged(QString)));
143 program_combo_->addItems(programs);
145 setWindowSubtitle(tr("ONC-RPC Service Response Times"));
146 g_hash_table_foreach(rpc_progs, onc_rpc_add_program, this);
147 QStringList programs = onc_name_to_program_.keys();
148 std::sort(programs.begin(), programs.end(), qStringCaseLessThan);
149 connect(program_combo_, SIGNAL(currentIndexChanged(QString)),
150 this, SLOT(oncRpcProgramChanged(QString)));
151 program_combo_->addItems(programs);
155 TapParameterDialog *RpcServiceResponseTimeDialog::createDceRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
158 bool have_args = false;
159 QString program_name;
163 // dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]
164 QStringList args_l = QString(opt_arg).split(',');
165 if (args_l.length() > 1) {
166 // Alas, QUuid requires Qt 4.8.
167 unsigned d1, d2, d3, d4_0, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7;
168 if(sscanf(args_l[0].toUtf8().constData(),
169 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
171 &d4_0, &d4_1, &d4_2, &d4_3, &d4_4, &d4_5, &d4_6, &d4_7) == 11) {
175 uuid.data4[0] = d4_0;
176 uuid.data4[1] = d4_1;
177 uuid.data4[2] = d4_2;
178 uuid.data4[3] = d4_3;
179 uuid.data4[4] = d4_4;
180 uuid.data4[5] = d4_5;
181 uuid.data4[6] = d4_6;
182 uuid.data4[7] = d4_7;
184 program_name = args_l[0];
186 version = args_l[1].split('.')[0].toInt();
187 if (args_l.length() > 2) {
188 filter = QStringList(args_l.mid(2)).join(",");
192 RpcServiceResponseTimeDialog *dce_rpc_dlg = new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("dcerpc"), DceRpc, filter);
195 if (program_name.isEmpty()) {
196 dce_rpc_dlg->setDceRpcUuidAndVersion(&uuid, version);
198 dce_rpc_dlg->setRpcNameAndVersion(program_name, version);
201 // Else the GTK+ UI throws an error.
206 TapParameterDialog *RpcServiceResponseTimeDialog::createOncRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
209 bool have_args = false;
210 QString program_name;
214 // rpc,srt,<program>,<version>[,<filter>
215 QStringList args_l = QString(opt_arg).split(',');
216 if (args_l.length() > 1) {
218 program_num = args_l[0].toInt(&ok);
220 program_name = args_l[0];
222 version = args_l[1].toInt();
223 if (args_l.length() > 2) {
224 filter = QStringList(args_l.mid(2)).join(",");
229 RpcServiceResponseTimeDialog *onc_rpc_dlg = new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("rpc"), OncRpc, filter);
232 if (program_name.isEmpty()) {
233 onc_rpc_dlg->setOncRpcProgramAndVersion(program_num, version);
235 onc_rpc_dlg->setRpcNameAndVersion(program_name, version);
238 // Else the GTK+ UI throws an error.
243 void RpcServiceResponseTimeDialog::addDceRpcProgram(_dcerpc_uuid_key *key, _dcerpc_uuid_value *value)
245 dce_name_to_uuid_key_.insert(value->name, key);
248 void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_dcerpc_uuid_key *key)
250 if (guid_cmp(&(dce_name_to_uuid_key_[program_combo_->currentText()]->uuid), &(key->uuid))) return;
252 versions_ << key->ver;
253 std::sort(versions_.begin(), versions_.end());
256 void RpcServiceResponseTimeDialog::addOncRpcProgram(guint32 program, _rpc_prog_info_value *value)
258 onc_name_to_program_.insert(value->progname, program);
261 void RpcServiceResponseTimeDialog::addOncRpcProgramVersion(guint32 program, guint32 version)
263 if (onc_name_to_program_[program_combo_->currentText()] != program) return;
265 if (versions_.isEmpty()) {
266 versions_ << version;
269 while (version < versions_.first()) {
270 versions_.prepend(versions_.first() - 1);
272 while (version > versions_.last()) {
273 versions_.append(versions_.last() + 1);
277 void RpcServiceResponseTimeDialog::updateOncRpcProcedureCount(guint32 program, guint32 version, int procedure)
279 if (onc_name_to_program_[program_combo_->currentText()] != program) return;
280 if (version_combo_->itemData(version_combo_->currentIndex()).toUInt() != version) return;
282 if (procedure > onc_rpc_num_procedures_) onc_rpc_num_procedures_ = procedure;
285 void RpcServiceResponseTimeDialog::setDceRpcUuidAndVersion(_e_guid_t *uuid, int version)
288 for (int pi = 0; pi < program_combo_->count(); pi++) {
289 if (guid_cmp(uuid, &(dce_name_to_uuid_key_[program_combo_->itemText(pi)]->uuid)) == 0) {
290 program_combo_->setCurrentIndex(pi);
292 for (int vi = 0; vi < version_combo_->count(); vi++) {
293 if (version == (int) version_combo_->itemData(vi).toUInt()) {
294 version_combo_->setCurrentIndex(vi);
302 if (found) fillTree();
305 void RpcServiceResponseTimeDialog::setOncRpcProgramAndVersion(int program, int version)
308 for (int pi = 0; pi < program_combo_->count(); pi++) {
309 if (program == (int) onc_name_to_program_[program_combo_->itemText(pi)]) {
310 program_combo_->setCurrentIndex(pi);
312 for (int vi = 0; vi < version_combo_->count(); vi++) {
313 if (version == (int) version_combo_->itemData(vi).toUInt()) {
314 version_combo_->setCurrentIndex(vi);
322 if (found) fillTree();
325 void RpcServiceResponseTimeDialog::setRpcNameAndVersion(const QString &program_name, int version)
328 for (int pi = 0; pi < program_combo_->count(); pi++) {
329 if (program_name.compare(program_combo_->itemText(pi), Qt::CaseInsensitive) == 0) {
330 program_combo_->setCurrentIndex(pi);
332 for (int vi = 0; vi < version_combo_->count(); vi++) {
333 if (version == (int) version_combo_->itemData(vi).toUInt()) {
334 version_combo_->setCurrentIndex(vi);
342 if (found) fillTree();
345 void RpcServiceResponseTimeDialog::dceRpcProgramChanged(const QString &program_name)
349 if (!dce_name_to_uuid_key_.contains(program_name)) return;
351 g_hash_table_foreach(dcerpc_uuids, dce_rpc_find_versions, this);
356 void RpcServiceResponseTimeDialog::oncRpcProgramChanged(const QString &program_name)
360 if (!onc_name_to_program_.contains(program_name)) return;
362 dissector_table_foreach ("rpc.call", onc_rpc_find_versions, this);
363 dissector_table_foreach ("rpc.reply", onc_rpc_find_versions, this);
368 void RpcServiceResponseTimeDialog::clearVersionCombo()
370 version_combo_->clear();
374 void RpcServiceResponseTimeDialog::fillVersionCombo()
376 foreach (unsigned version, versions_) {
377 version_combo_->addItem(QString::number(version), version);
379 if (versions_.count() > 0) {
380 // Select the highest-numbered version.
381 version_combo_->setCurrentIndex(versions_.count() - 1);
385 void RpcServiceResponseTimeDialog::fillTree()
387 void *tap_data = NULL;
388 const QString program_name = program_combo_->currentText();
389 gchar *program_name_cptr = qstring_strdup(program_name);
390 guint32 max_procs = 0;
395 if (!dce_name_to_uuid_key_.contains(program_name)) return;
397 dcerpc_uuid_key *dkey = dce_name_to_uuid_key_[program_name];
398 dcerpcstat_tap_data_t *dtap_data = g_new0(dcerpcstat_tap_data_t, 1);
399 dtap_data->uuid = dkey->uuid;
400 dtap_data->prog = program_name_cptr;
401 dtap_data->ver = (guint16) version_combo_->itemData(version_combo_->currentIndex()).toUInt();
403 dcerpc_sub_dissector *procs = dcerpc_get_proto_sub_dissector(&(dkey->uuid), dtap_data->ver);
404 for (int i = 0; procs[i].name; i++) {
405 if (procs[i].num > max_procs) max_procs = procs[i].num;
407 dtap_data->num_procedures = max_procs + 1;
409 tap_data = dtap_data;
414 if (!onc_name_to_program_.contains(program_name)) return;
416 rpcstat_tap_data_t *otap_data = g_new0(rpcstat_tap_data_t, 1);
417 otap_data->prog = program_name_cptr;
418 otap_data->program = onc_name_to_program_[program_name];
419 otap_data->version = (guint32) version_combo_->itemData(version_combo_->currentIndex()).toUInt();
421 onc_rpc_num_procedures_ = -1;
422 dissector_table_foreach ("rpc.call", onc_rpc_count_procedures, this);
423 dissector_table_foreach ("rpc.reply", onc_rpc_count_procedures, this);
424 otap_data->num_procedures = onc_rpc_num_procedures_ + 1;
426 tap_data = otap_data;
431 set_srt_table_param_data(srt_, tap_data);
433 ServiceResponseTimeDialog::fillTree();
434 g_free(program_name_cptr);
444 * indent-tabs-mode: nil
447 * ex: set shiftwidth=4 tabstop=8 expandtab:
448 * :indentSize=4:tabSize=8:noTabs=true: