Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / ui / qt / multicast_statistics_dialog.cpp
blob22fb372cd46f98f7a4d2e3856858f9d5c76a6645
1 /* multicast_statistics_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
8 */
10 #include "multicast_statistics_dialog.h"
12 #include <QFormLayout>
13 #include <QLabel>
14 #include <QPushButton>
15 #include <QTreeWidget>
17 #include <ui/qt/utils/qt_ui_utils.h>
18 #include <ui/qt/widgets/syntax_line_edit.h>
19 #include "ui/simple_dialog.h"
20 #include <file.h>
22 #include "main_application.h"
24 enum {
25 col_src_addr_,
26 col_src_port_,
27 col_dst_addr_,
28 col_dst_port_,
29 col_packets_,
30 col_packets_s_,
31 col_avg_bw_,
32 col_max_bw_,
33 col_max_burst_,
34 col_burst_alarms_,
35 col_max_buffers_,
36 col_buffer_alarms_
39 enum {
40 mcast_table_type_ = 1000
43 class MulticastStatTreeWidgetItem : public QTreeWidgetItem
45 public:
46 MulticastStatTreeWidgetItem(QTreeWidget *parent) :
47 QTreeWidgetItem (parent, mcast_table_type_)
49 clear_address(&src_addr_);
50 clear_address(&dst_addr_);
51 src_port_ = 0;
52 dst_port_ = 0;
53 num_packets_ = 0;
54 avg_pps_ = 0;
55 avg_bw_ = 0;
56 max_bw_ = 0;
57 top_burst_size_ = 0;
58 num_bursts_ = 0;
59 top_buff_usage_ = 0;
60 num_buff_alarms_ = 0;
63 ~MulticastStatTreeWidgetItem()
65 // This probably doesn't outlive the stream_info, so perhaps we
66 // could shallow copy the addresses.
67 free_address_wmem(NULL, &src_addr_);
68 free_address_wmem(NULL, &dst_addr_);
71 void updateStreamInfo(const mcast_stream_info_t *stream_info) {
72 copy_address_wmem(NULL, &src_addr_, &stream_info->src_addr);
73 src_port_ = stream_info->src_port;
74 copy_address_wmem(NULL, &dst_addr_, &stream_info->dest_addr);
75 dst_port_ = stream_info->dest_port;
76 num_packets_ = stream_info->npackets;
77 avg_pps_ = stream_info->apackets;
78 avg_bw_ = stream_info->average_bw;
79 max_bw_ = stream_info->element.maxbw;
80 top_burst_size_ = stream_info->element.topburstsize;
81 num_bursts_ = stream_info->element.numbursts;
82 top_buff_usage_ = stream_info->element.topbuffusage;
83 num_buff_alarms_ = stream_info->element.numbuffalarms;
85 draw();
88 void draw() {
89 setText(col_src_addr_, address_to_qstring(&src_addr_));
90 setText(col_src_port_, QString::number(src_port_));
91 setText(col_dst_addr_, address_to_qstring(&dst_addr_));
92 setText(col_dst_port_, QString::number(dst_port_));
93 setText(col_packets_, QString::number(num_packets_));
94 setText(col_packets_s_, QString::number(avg_pps_, 'f', 2));
95 setText(col_avg_bw_, bits_s_to_qstring(avg_bw_));
96 setText(col_max_bw_, bits_s_to_qstring(max_bw_));
97 setText(col_max_burst_, QStringLiteral("%1 / %2ms").arg(top_burst_size_).arg(mcast_stream_burstint));
98 setText(col_burst_alarms_, QString::number(num_bursts_));
99 setText(col_max_buffers_, bits_s_to_qstring(top_buff_usage_));
100 setText(col_buffer_alarms_, QString::number(num_buff_alarms_));
103 bool operator< (const QTreeWidgetItem &other) const
105 if (other.type() != mcast_table_type_) return QTreeWidgetItem::operator< (other);
106 const MulticastStatTreeWidgetItem *other_row = static_cast<const MulticastStatTreeWidgetItem *>(&other);
108 switch (treeWidget()->sortColumn()) {
109 case col_src_addr_:
110 return cmp_address(&src_addr_, &other_row->src_addr_) < 0;
111 case col_src_port_:
112 return src_port_ < other_row->src_port_;
113 case col_dst_addr_:
114 return cmp_address(&dst_addr_, &other_row->dst_addr_) < 0;
115 case col_dst_port_:
116 return dst_port_ < other_row->dst_port_;
117 case col_packets_:
118 return num_packets_ < other_row->num_packets_;
119 case col_packets_s_:
120 return avg_pps_ < other_row->avg_pps_;
121 case col_avg_bw_:
122 return avg_bw_ < other_row->avg_bw_;
123 case col_max_bw_:
124 return max_bw_ < other_row->max_bw_;
125 case col_max_burst_:
126 return top_burst_size_ < other_row->top_burst_size_;
127 case col_burst_alarms_:
128 return num_bursts_ < other_row->num_bursts_;
129 case col_max_buffers_:
130 return top_buff_usage_ < other_row->top_buff_usage_;
131 case col_buffer_alarms_:
132 return num_buff_alarms_ < other_row->num_buff_alarms_;
133 default:
134 break;
137 return QTreeWidgetItem::operator< (other);
139 QList<QVariant> rowData() {
140 return QList<QVariant>()
141 << address_to_qstring(&src_addr_) << src_port_
142 << address_to_qstring(&dst_addr_) << dst_port_
143 << num_packets_ << avg_pps_
144 << avg_bw_ << max_bw_
145 << top_burst_size_ << num_bursts_
146 << top_buff_usage_ << num_buff_alarms_;
148 const QString filterExpression() {
149 QString ip_version;
151 if (src_addr_.type == AT_IPv6) ip_version = "v6";
153 const QString filter_expr = QStringLiteral("(ip%1.src==%2 && udp.srcport==%3 && ip%1.dst==%4 && udp.dstport==%5)")
154 .arg(ip_version)
155 .arg(address_to_qstring(&src_addr_))
156 .arg(src_port_)
157 .arg(address_to_qstring(&dst_addr_))
158 .arg(dst_port_);
159 return filter_expr;
162 private:
163 address src_addr_;
164 uint16_t src_port_;
165 address dst_addr_;
166 uint16_t dst_port_;
167 unsigned num_packets_;
168 double avg_pps_;
169 double avg_bw_;
170 double max_bw_;
171 int top_burst_size_;
172 int num_bursts_;
173 int top_buff_usage_;
174 int num_buff_alarms_;
177 MulticastStatisticsDialog::MulticastStatisticsDialog(QWidget &parent, CaptureFile &cf, const char *filter) :
178 TapParameterDialog(parent, cf)
180 setWindowSubtitle(tr("UDP Multicast Streams"));
181 loadGeometry(parent.width() * 4 / 5, parent.height() * 3 / 4, "MulticastStatisticsDialog");
183 tapinfo_ = new mcaststream_tapinfo_t();
184 tapinfo_->user_data = this;
185 tapinfo_->tap_reset = tapReset;
186 tapinfo_->tap_draw = tapDraw;
188 QStringList header_names = QStringList()
189 << tr("Source Address") << tr("Source Port")
190 << tr("Destination Address") << tr("Destination Port")
191 << tr("Packets") << tr("Packets/s")
192 << tr("Avg BW (bps)") << tr("Max BW (bps)")
193 << tr("Max Burst") << tr("Burst Alarms")
194 << tr("Max Buffers (B)") << tr("Buffer Alarms");
196 statsTreeWidget()->setHeaderLabels(header_names);
198 for (int col = 0; col < statsTreeWidget()->columnCount(); col++) {
199 if (col == col_src_addr_ || col == col_dst_addr_) continue;
200 statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
203 burst_measurement_interval_le_ = new SyntaxLineEdit(this);
204 burst_alarm_threshold_le_ = new SyntaxLineEdit(this);
205 buffer_alarm_threshold_le_ = new SyntaxLineEdit(this);
206 stream_empty_speed_le_ = new SyntaxLineEdit(this);
207 total_empty_speed_le_ = new SyntaxLineEdit(this);
209 int filter_layout_idx = verticalLayout()->indexOf(filterLayout()->widget());
210 QGridLayout *param_grid = new QGridLayout();
211 int one_em = fontMetrics().height();
212 verticalLayout()->insertLayout(filter_layout_idx, param_grid);
214 // Label | LineEdit | | Label | LineEdit | | Label | LineEdit
215 // 0 1 2 3 4 5 6 7
216 param_grid->setColumnMinimumWidth(2, one_em * 2);
217 param_grid->setColumnStretch(2, 1);
218 param_grid->setColumnMinimumWidth(5, one_em * 2);
219 param_grid->setColumnStretch(5, 1);
220 param_grid->addWidget(new QLabel(tr("Burst measurement interval (ms):")), 0, 0, Qt::AlignRight);
221 param_grid->addWidget(burst_measurement_interval_le_, 0, 1);
222 param_grid->addWidget(new QLabel(tr("Burst alarm threshold (packets):")), 0, 3, Qt::AlignRight);
223 param_grid->addWidget(burst_alarm_threshold_le_, 0, 4);
224 param_grid->addWidget(new QLabel(tr("Buffer alarm threshold (B):")), 0, 6, Qt::AlignRight);
225 param_grid->addWidget(buffer_alarm_threshold_le_, 0, 7);
227 param_grid->addWidget(new QLabel(tr("Stream empty speed (Kb/s):")), 1, 0, Qt::AlignRight);
228 param_grid->addWidget(stream_empty_speed_le_, 1, 1);
229 param_grid->addWidget(new QLabel(tr("Total empty speed (Kb/s):")), 1, 3, Qt::AlignRight);
230 param_grid->addWidget(total_empty_speed_le_, 1, 4);
232 burst_measurement_interval_le_->setText(QString::number(mcast_stream_burstint));
233 burst_alarm_threshold_le_->setText(QString::number(mcast_stream_trigger));
234 buffer_alarm_threshold_le_->setText(QString::number(mcast_stream_bufferalarm));
235 stream_empty_speed_le_->setText(QString::number(mcast_stream_emptyspeed));
236 total_empty_speed_le_->setText(QString::number(mcast_stream_cumulemptyspeed));
238 line_edits_ = QList<QWidget *>()
239 << burst_measurement_interval_le_ << burst_alarm_threshold_le_
240 << buffer_alarm_threshold_le_ << stream_empty_speed_le_
241 << total_empty_speed_le_;
243 foreach (QWidget *w, line_edits_) {
244 QLineEdit *line_edit = qobject_cast<QLineEdit *>(w);
245 line_edit->setMinimumWidth(one_em * 5);
246 connect(line_edit, &QLineEdit::textEdited, this, &MulticastStatisticsDialog::updateWidgets);
249 addFilterActions();
251 if (filter) {
252 setDisplayFilter(filter);
255 connect(this, &MulticastStatisticsDialog::updateFilter,
256 this, &MulticastStatisticsDialog::updateMulticastParameters);
258 /* Register the tap listener */
259 GString * error_string = register_tap_listener_mcast_stream(tapinfo_);
260 if (error_string != NULL) {
261 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
262 "%s", error_string->str);
263 g_string_free(error_string, TRUE);
264 exit(1);
267 updateWidgets();
270 MulticastStatisticsDialog::~MulticastStatisticsDialog()
272 /* Remove the stream tap listener */
273 remove_tap_listener_mcast_stream(tapinfo_);
275 /* Clean up memory used by stream tap */
276 mcaststream_reset(tapinfo_);
278 delete tapinfo_;
281 void MulticastStatisticsDialog::tapReset(mcaststream_tapinfo_t *tapinfo)
283 MulticastStatisticsDialog *ms_dlg = dynamic_cast<MulticastStatisticsDialog *>((MulticastStatisticsDialog*)tapinfo->user_data);
284 if (!ms_dlg || !ms_dlg->statsTreeWidget()) return;
286 ms_dlg->statsTreeWidget()->clear();
289 void MulticastStatisticsDialog::tapDraw(mcaststream_tapinfo_t *tapinfo)
291 MulticastStatisticsDialog *ms_dlg = dynamic_cast<MulticastStatisticsDialog *>((MulticastStatisticsDialog*)tapinfo->user_data);
292 if (!ms_dlg || !ms_dlg->statsTreeWidget()) return;
294 //Clear the tree because the list always starts from the beginning
295 ms_dlg->statsTreeWidget()->clear();
297 // Add missing rows and update stats
298 int cur_row = 0;
299 for (GList *cur = g_list_first(tapinfo->strinfo_list); cur; cur = gxx_list_next(cur)) {
300 mcast_stream_info_t *stream_info = gxx_list_data(mcast_stream_info_t *, cur);
301 if (!stream_info) continue;
303 MulticastStatTreeWidgetItem *ms_ti;
304 QTreeWidgetItem *ti = ms_dlg->statsTreeWidget()->topLevelItem(cur_row);
305 if (!ti) {
306 ms_ti = new MulticastStatTreeWidgetItem(ms_dlg->statsTreeWidget());
307 for (int col = 0; col < ms_dlg->statsTreeWidget()->columnCount(); col++) {
308 if (col == col_src_addr_ || col == col_dst_addr_) continue;
309 ms_ti->setTextAlignment(col, Qt::AlignRight);
311 } else {
312 ms_ti = static_cast<MulticastStatTreeWidgetItem *>(ti);
315 ms_ti->updateStreamInfo(stream_info);
316 cur_row++;
320 QList<QVariant> MulticastStatisticsDialog::treeItemData(QTreeWidgetItem *ti) const
322 MulticastStatTreeWidgetItem *ms_ti = dynamic_cast<MulticastStatTreeWidgetItem*>(ti);
323 if (ms_ti) {
324 return ms_ti->rowData();
326 else {
327 return QList<QVariant>();
331 const QString MulticastStatisticsDialog::filterExpression()
333 QString filter_expr;
334 if (statsTreeWidget()->selectedItems().count() > 0) {
335 QTreeWidgetItem *ti = statsTreeWidget()->selectedItems()[0];
337 MulticastStatTreeWidgetItem *ms_ti = static_cast<MulticastStatTreeWidgetItem *>(ti);
338 filter_expr = ms_ti->filterExpression();
340 return filter_expr;
343 void MulticastStatisticsDialog::updateWidgets()
345 QString hint;
346 bool enable_apply = true;
347 bool enable_edits = cap_file_.isValid();
348 bool ok = false;
349 int param;
351 param = burst_measurement_interval_le_->text().toUInt(&ok);
352 if (!ok || param < 1 || param > 1000) {
353 hint += tr("The burst interval must be between 1 and 1000. ");
354 enable_apply = false;
355 burst_measurement_interval_le_->setSyntaxState(SyntaxLineEdit::Invalid);
356 } else {
357 burst_measurement_interval_le_->setSyntaxState(SyntaxLineEdit::Valid);
360 param = burst_alarm_threshold_le_->text().toInt(&ok);
361 if (!ok || param < 1) {
362 hint += tr("The burst alarm threshold isn't valid. ");
363 enable_apply = false;
364 burst_alarm_threshold_le_->setSyntaxState(SyntaxLineEdit::Invalid);
365 } else {
366 burst_alarm_threshold_le_->setSyntaxState(SyntaxLineEdit::Valid);
369 param = buffer_alarm_threshold_le_->text().toInt(&ok);
370 if (!ok || param < 1) {
371 hint += tr("The buffer alarm threshold isn't valid. ");
372 enable_apply = false;
373 buffer_alarm_threshold_le_->setSyntaxState(SyntaxLineEdit::Invalid);
374 } else {
375 buffer_alarm_threshold_le_->setSyntaxState(SyntaxLineEdit::Valid);
378 param = stream_empty_speed_le_->text().toInt(&ok);
379 if (!ok || param < 1 || param > 10000000) {
380 hint += tr("The stream empty speed should be between 1 and 10000000. ");
381 enable_apply = false;
382 stream_empty_speed_le_->setSyntaxState(SyntaxLineEdit::Invalid);
383 } else {
384 stream_empty_speed_le_->setSyntaxState(SyntaxLineEdit::Valid);
387 param = total_empty_speed_le_->text().toInt(&ok);
388 if (!ok || param < 1 || param > 10000000) {
389 hint += tr("The total empty speed should be between 1 and 10000000. ");
390 enable_apply = false;
391 total_empty_speed_le_->setSyntaxState(SyntaxLineEdit::Invalid);
392 } else {
393 total_empty_speed_le_->setSyntaxState(SyntaxLineEdit::Valid);
396 foreach (QWidget *line_edit, line_edits_) {
397 line_edit->setEnabled(enable_edits);
400 applyFilterButton()->setEnabled(enable_apply);
402 if (hint.isEmpty() && tapinfo_->allstreams) {
403 const QString stats = tr("%1 streams, avg bw: %2bps, max bw: %3bps, max burst: %4 / %5ms, max buffer: %6B")
404 .arg(statsTreeWidget()->topLevelItemCount())
405 .arg(bits_s_to_qstring(tapinfo_->allstreams->average_bw))
406 .arg(bits_s_to_qstring(tapinfo_->allstreams->element.maxbw))
407 .arg(tapinfo_->allstreams->element.topburstsize)
408 .arg(mcast_stream_burstint)
409 .arg(bits_s_to_qstring(tapinfo_->allstreams->element.topbuffusage));
410 hint.append(stats);
412 hint.prepend("<small><i>");
413 hint.append("</i></small>");
414 setHint(hint);
415 TapParameterDialog::updateWidgets();
418 void MulticastStatisticsDialog::updateMulticastParameters()
420 bool ok = false;
421 int param;
423 param = burst_measurement_interval_le_->text().toUInt(&ok);
424 if (ok && param > 0 && param <= 1000) {
425 mcast_stream_burstint = (uint16_t) param;
428 param = burst_alarm_threshold_le_->text().toInt(&ok);
429 if (ok) {
430 mcast_stream_trigger = param;
433 param = buffer_alarm_threshold_le_->text().toInt(&ok);
434 if (ok && param > 0) {
435 mcast_stream_bufferalarm = param;
438 param = stream_empty_speed_le_->text().toInt(&ok);
439 if (ok && param > 0 && param <= 10000000) {
440 mcast_stream_emptyspeed = param;
443 param = total_empty_speed_le_->text().toInt(&ok);
444 if (ok && param > 0 && param <= 10000000) {
445 mcast_stream_cumulemptyspeed = param;
449 void MulticastStatisticsDialog::fillTree()
451 QList<QWidget *> disable_widgets = QList<QWidget *>()
452 << line_edits_ << displayFilterLineEdit() << applyFilterButton();
454 foreach (QWidget *w, disable_widgets) w->setEnabled(false);
456 rescan();
458 foreach (QWidget *w, disable_widgets) w->setEnabled(true);
459 for (int col = 0; col < statsTreeWidget()->columnCount() - 1; col++) {
460 statsTreeWidget()->resizeColumnToContents(col);
462 updateWidgets();
465 void MulticastStatisticsDialog::rescan()
467 bool was_registered = tapinfo_->is_registered;
468 if (!tapinfo_->is_registered)
469 register_tap_listener_mcast_stream(tapinfo_);
471 cf_retap_packets(cap_file_.capFile());
473 if (!was_registered)
474 remove_tap_listener_mcast_stream(tapinfo_);
476 tapDraw(tapinfo_);
479 void MulticastStatisticsDialog::captureFileClosing()
481 /* Remove the stream tap listener */
482 remove_tap_listener_mcast_stream(tapinfo_);
484 WiresharkDialog::captureFileClosing();
487 // Stat command + args
489 static void
490 multicast_statistics_init(const char *args, void*) {
491 QStringList args_l = QString(args).split(',');
492 QByteArray filter;
493 if (args_l.length() > 2) {
494 filter = QStringList(args_l.mid(2)).join(",").toUtf8();
496 mainApp->emitStatCommandSignal("MulticastStatistics", filter.constData(), NULL);
499 static stat_tap_ui multicast_statistics_ui = {
500 REGISTER_STAT_GROUP_GENERIC,
501 NULL,
502 "multicast,stat",
503 multicast_statistics_init,
505 NULL
508 extern "C" {
510 void register_tap_listener_qt_multicast_statistics(void);
512 void
513 register_tap_listener_qt_multicast_statistics(void)
515 register_stat_tap_ui(&multicast_statistics_ui, NULL);