CMake: Add /WX
[metze/wireshark/wip.git] / ui / qt / rpc_service_response_time_dialog.cpp
1 /* rpc_service_response_time_dialog.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
23 #ifdef _MSC_VER
24 #pragma warning(push)
25 #pragma warning(disable : 4267)
26 #endif
27
28 #include "rpc_service_response_time_dialog.h"
29
30 #include <algorithm>
31 #include <stdio.h>
32
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>
37
38 #include "qt_ui_utils.h"
39
40 #include <QComboBox>
41 #include <QHBoxLayout>
42 #include <QLabel>
43
44 #ifdef _MSC_VER
45 #pragma warning(pop)
46 #endif
47
48 // To do:
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
54 //   column.
55 // - Make the version in the command-line args optional?
56
57 extern "C" {
58 static void
59 dce_rpc_add_program(gpointer key_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
60 {
61     RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
62     if (!rsrt_dlg) return;
63
64     dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
65     dcerpc_uuid_value *value = (dcerpc_uuid_value *)value_ptr;
66
67     rsrt_dlg->addDceRpcProgram(key, value);
68 }
69
70 static void
71 dce_rpc_find_versions(gpointer key_ptr, gpointer, gpointer rsrtd_ptr)
72 {
73     RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
74     if (!rsrt_dlg) return;
75
76     dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
77     rsrt_dlg->addDceRpcProgramVersion(key);
78 }
79
80 static void
81 onc_rpc_add_program(gpointer prog_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
82 {
83     RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
84     if (!rsrt_dlg) return;
85
86     guint32 program = GPOINTER_TO_UINT(prog_ptr);
87     rpc_prog_info_value *value = (rpc_prog_info_value *) value_ptr;
88
89     rsrt_dlg->addOncRpcProgram(program, value);
90 }
91
92 static void
93 onc_rpc_find_versions(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
94 {
95     RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
96     if (!rsrt_dlg) return;
97
98     rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
99
100     rsrt_dlg->addOncRpcProgramVersion(rpik->prog, rpik->vers);
101 }
102
103 static void
104 onc_rpc_count_procedures(const gchar *, ftenum_t , gpointer rpik_ptr, gpointer, gpointer rsrtd_ptr)
105 {
106     RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
107     if (!rsrt_dlg) return;
108
109     rpc_proc_info_key *rpik = (rpc_proc_info_key *)rpik_ptr;
110
111     rsrt_dlg->updateOncRpcProcedureCount(rpik->prog, rpik->vers, rpik->proc);
112 }
113
114 } // extern "C"
115
116 RpcServiceResponseTimeDialog::RpcServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, struct register_srt *srt, RpcFamily dlg_type, const QString filter) :
117     ServiceResponseTimeDialog(parent, cf, srt, filter),
118     dlg_type_(dlg_type)
119 {
120     setRetapOnShow(false);
121     setHint(tr("<small><i>Select a program and version and enter a filter if desired, then press Apply.</i></small>"));
122
123     QHBoxLayout *filter_layout = filterLayout();
124     program_combo_ = new QComboBox(this);
125     version_combo_ = new QComboBox(this);
126
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:")));
132
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);
144     } else {
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);
152     }
153 }
154
155 TapParameterDialog *RpcServiceResponseTimeDialog::createDceRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
156 {
157     QString filter;
158     bool have_args = false;
159     QString program_name;
160     e_guid_t uuid;
161     int version = 0;
162
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",
170                   &d1, &d2, &d3,
171                   &d4_0, &d4_1, &d4_2, &d4_3, &d4_4, &d4_5, &d4_6, &d4_7) == 11) {
172                   uuid.data1 = d1;
173                   uuid.data2 = d2;
174                   uuid.data3 = d3;
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;
183         } else {
184             program_name = args_l[0];
185         }
186         version = args_l[1].split('.')[0].toInt();
187         if (args_l.length() > 2) {
188             filter = QStringList(args_l.mid(2)).join(",");
189         }
190         have_args = true;
191     }
192     RpcServiceResponseTimeDialog *dce_rpc_dlg = new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("dcerpc"), DceRpc, filter);
193
194     if (have_args) {
195         if (program_name.isEmpty()) {
196             dce_rpc_dlg->setDceRpcUuidAndVersion(&uuid, version);
197         } else {
198             dce_rpc_dlg->setRpcNameAndVersion(program_name, version);
199         }
200     }
201     // Else the GTK+ UI throws an error.
202
203     return dce_rpc_dlg;
204 }
205
206 TapParameterDialog *RpcServiceResponseTimeDialog::createOncRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf)
207 {
208     QString filter;
209     bool have_args = false;
210     QString program_name;
211     int program_num = 0;
212     int version = 0;
213
214     // rpc,srt,<program>,<version>[,<filter>
215     QStringList args_l = QString(opt_arg).split(',');
216     if (args_l.length() > 1) {
217         bool ok = false;
218         program_num = args_l[0].toInt(&ok);
219         if (!ok) {
220             program_name = args_l[0];
221         }
222         version = args_l[1].toInt();
223         if (args_l.length() > 2) {
224             filter = QStringList(args_l.mid(2)).join(",");
225         }
226         have_args = true;
227     }
228
229     RpcServiceResponseTimeDialog *onc_rpc_dlg =  new RpcServiceResponseTimeDialog(parent, cf, get_srt_table_by_name("rpc"), OncRpc, filter);
230
231     if (have_args) {
232         if (program_name.isEmpty()) {
233             onc_rpc_dlg->setOncRpcProgramAndVersion(program_num, version);
234         } else {
235             onc_rpc_dlg->setRpcNameAndVersion(program_name, version);
236         }
237     }
238     // Else the GTK+ UI throws an error.
239
240     return onc_rpc_dlg;
241 }
242
243 void RpcServiceResponseTimeDialog::addDceRpcProgram(_dcerpc_uuid_key *key, _dcerpc_uuid_value *value)
244 {
245     dce_name_to_uuid_key_.insert(value->name, key);
246 }
247
248 void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_dcerpc_uuid_key *key)
249 {
250     if (guid_cmp(&(dce_name_to_uuid_key_[program_combo_->currentText()]->uuid), &(key->uuid))) return;
251
252     versions_ << key->ver;
253     std::sort(versions_.begin(), versions_.end());
254 }
255
256 void RpcServiceResponseTimeDialog::addOncRpcProgram(guint32 program, _rpc_prog_info_value *value)
257 {
258     onc_name_to_program_.insert(value->progname, program);
259 }
260
261 void RpcServiceResponseTimeDialog::addOncRpcProgramVersion(guint32 program, guint32 version)
262 {
263     if (onc_name_to_program_[program_combo_->currentText()] != program) return;
264
265     if (versions_.isEmpty()) {
266         versions_ << version;
267         return;
268     }
269     while (version < versions_.first()) {
270         versions_.prepend(versions_.first() - 1);
271     }
272     while (version > versions_.last()) {
273         versions_.append(versions_.last() + 1);
274     }
275 }
276
277 void RpcServiceResponseTimeDialog::updateOncRpcProcedureCount(guint32 program, guint32 version, int procedure)
278 {
279     if (onc_name_to_program_[program_combo_->currentText()] != program) return;
280     if (version_combo_->itemData(version_combo_->currentIndex()).toUInt() != version) return;
281
282     if (procedure > onc_rpc_num_procedures_) onc_rpc_num_procedures_ = procedure;
283 }
284
285 void RpcServiceResponseTimeDialog::setDceRpcUuidAndVersion(_e_guid_t *uuid, int version)
286 {
287     bool found = false;
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);
291
292             for (int vi = 0; vi < version_combo_->count(); vi++) {
293                 if (version == (int) version_combo_->itemData(vi).toUInt()) {
294                     version_combo_->setCurrentIndex(vi);
295                     found = true;
296                     break;
297                 }
298             }
299             break;
300         }
301     }
302     if (found) fillTree();
303 }
304
305 void RpcServiceResponseTimeDialog::setOncRpcProgramAndVersion(int program, int version)
306 {
307     bool found = false;
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);
311
312             for (int vi = 0; vi < version_combo_->count(); vi++) {
313                 if (version == (int) version_combo_->itemData(vi).toUInt()) {
314                     version_combo_->setCurrentIndex(vi);
315                     found = true;
316                     break;
317                 }
318             }
319             break;
320         }
321     }
322     if (found) fillTree();
323 }
324
325 void RpcServiceResponseTimeDialog::setRpcNameAndVersion(const QString &program_name, int version)
326 {
327     bool found = false;
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);
331
332             for (int vi = 0; vi < version_combo_->count(); vi++) {
333                 if (version == (int) version_combo_->itemData(vi).toUInt()) {
334                     version_combo_->setCurrentIndex(vi);
335                     found = true;
336                     break;
337                 }
338             }
339             break;
340         }
341     }
342     if (found) fillTree();
343 }
344
345 void RpcServiceResponseTimeDialog::dceRpcProgramChanged(const QString &program_name)
346 {
347     clearVersionCombo();
348
349     if (!dce_name_to_uuid_key_.contains(program_name)) return;
350
351     g_hash_table_foreach(dcerpc_uuids, dce_rpc_find_versions, this);
352
353     fillVersionCombo();
354 }
355
356 void RpcServiceResponseTimeDialog::oncRpcProgramChanged(const QString &program_name)
357 {
358     clearVersionCombo();
359
360     if (!onc_name_to_program_.contains(program_name)) return;
361
362     dissector_table_foreach ("rpc.call", onc_rpc_find_versions, this);
363     dissector_table_foreach ("rpc.reply", onc_rpc_find_versions, this);
364
365     fillVersionCombo();
366 }
367
368 void RpcServiceResponseTimeDialog::clearVersionCombo()
369 {
370     version_combo_->clear();
371     versions_.clear();
372 }
373
374 void RpcServiceResponseTimeDialog::fillVersionCombo()
375 {
376     foreach (unsigned version, versions_) {
377         version_combo_->addItem(QString::number(version), version);
378     }
379     if (versions_.count() > 0) {
380         // Select the highest-numbered version.
381         version_combo_->setCurrentIndex(versions_.count() - 1);
382     }
383 }
384
385 void RpcServiceResponseTimeDialog::fillTree()
386 {
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;
391
392     switch (dlg_type_) {
393     case DceRpc:
394     {
395         if (!dce_name_to_uuid_key_.contains(program_name)) return;
396
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();
402
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;
406         }
407         dtap_data->num_procedures = max_procs + 1;
408
409         tap_data = dtap_data;
410         break;
411     }
412     case OncRpc:
413     {
414         if (!onc_name_to_program_.contains(program_name)) return;
415
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();
420
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;
425
426         tap_data = otap_data;
427         break;
428     }
429     }
430
431     set_srt_table_param_data(srt_, tap_data);
432
433     ServiceResponseTimeDialog::fillTree();
434     g_free(program_name_cptr);
435     g_free(tap_data);
436 }
437
438 /*
439  * Editor modelines
440  *
441  * Local Variables:
442  * c-basic-offset: 4
443  * tab-width: 8
444  * indent-tabs-mode: nil
445  * End:
446  *
447  * ex: set shiftwidth=4 tabstop=8 expandtab:
448  * :indentSize=4:tabSize=8:noTabs=true:
449  */