1 /* response_time_delay_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 #include "response_time_delay_dialog.h"
14 #include "epan/proto.h"
15 #include "epan/rtd_table.h"
17 #include <QTreeWidget>
19 #include <ui/qt/utils/qt_ui_utils.h>
20 #include "main_application.h"
22 static QHash
<const QString
, register_rtd_t
*> cfg_str_to_rtd_
;
26 rtd_init(const char *args
, void*) {
27 QStringList args_l
= QString(args
).split(',');
28 if (args_l
.length() > 1) {
29 QString rtd
= QStringLiteral("%1,%2").arg(args_l
[0]).arg(args_l
[1]);
31 if (args_l
.length() > 2) {
32 filter
= QStringList(args_l
.mid(2)).join(",");
34 mainApp
->emitTapParameterSignal(rtd
, filter
, NULL
);
39 bool register_response_time_delay_tables(const void *, void *value
, void*)
41 register_rtd_t
*rtd
= (register_rtd_t
*)value
;
42 const char* short_name
= proto_get_protocol_short_name(find_protocol_by_id(get_rtd_proto_id(rtd
)));
43 char *cfg_abbr
= rtd_table_get_tap_string(rtd
);
45 cfg_str_to_rtd_
[cfg_abbr
] = rtd
;
46 TapParameterDialog::registerDialog(
49 REGISTER_STAT_GROUP_RESPONSE_TIME
,
51 ResponseTimeDelayDialog::createRtdDialog
);
65 col_discarded_responses_
,
66 col_repeated_requests_
,
67 col_repeated_responses_
71 rtd_table_type_
= 1000,
75 class RtdTimeStatTreeWidgetItem
: public QTreeWidgetItem
78 RtdTimeStatTreeWidgetItem(QTreeWidget
*parent
, const QString type
, const rtd_timestat
*timestat
) :
79 QTreeWidgetItem (parent
, rtd_time_stat_type_
),
83 setText(col_type_
, type_
);
87 setText(col_messages_
, QString::number(timestat_
->rtd
->num
));
88 setText(col_min_srt_
, QString::number(nstime_to_sec(×tat_
->rtd
->min
), 'f', 6));
89 setText(col_max_srt_
, QString::number(nstime_to_sec(×tat_
->rtd
->max
), 'f', 6));
90 setText(col_avg_srt_
, QString::number(get_average(×tat_
->rtd
->tot
, timestat_
->rtd
->num
) / 1000.0, 'f', 6));
91 setText(col_min_frame_
, QString::number(timestat_
->rtd
->min_num
));
92 setText(col_max_frame_
, QString::number(timestat_
->rtd
->max_num
));
93 setText(col_open_requests
, QString::number(timestat_
->open_req_num
));
94 setText(col_discarded_responses_
, QString::number(timestat_
->disc_rsp_num
));
95 setText(col_repeated_requests_
, QString::number(timestat_
->req_dup_num
));
96 setText(col_repeated_responses_
, QString::number(timestat_
->rsp_dup_num
));
98 setHidden(timestat_
->rtd
->num
< 1);
100 bool operator< (const QTreeWidgetItem
&other
) const
102 if (other
.type() != rtd_time_stat_type_
) return QTreeWidgetItem::operator< (other
);
103 const RtdTimeStatTreeWidgetItem
*other_row
= static_cast<const RtdTimeStatTreeWidgetItem
*>(&other
);
105 switch (treeWidget()->sortColumn()) {
107 return timestat_
->rtd
->num
< other_row
->timestat_
->rtd
->num
;
109 return nstime_cmp(×tat_
->rtd
->min
, &other_row
->timestat_
->rtd
->min
) < 0;
111 return nstime_cmp(×tat_
->rtd
->max
, &other_row
->timestat_
->rtd
->max
) < 0;
114 double our_avg
= get_average(×tat_
->rtd
->tot
, timestat_
->rtd
->num
);
115 double other_avg
= get_average(&other_row
->timestat_
->rtd
->tot
, other_row
->timestat_
->rtd
->num
);
116 return our_avg
< other_avg
;
119 return timestat_
->rtd
->min_num
< other_row
->timestat_
->rtd
->min_num
;
121 return timestat_
->rtd
->max_num
< other_row
->timestat_
->rtd
->max_num
;
122 case col_open_requests
:
123 return timestat_
->open_req_num
< other_row
->timestat_
->open_req_num
;
124 case col_discarded_responses_
:
125 return timestat_
->disc_rsp_num
< other_row
->timestat_
->disc_rsp_num
;
126 case col_repeated_requests_
:
127 return timestat_
->req_dup_num
< other_row
->timestat_
->req_dup_num
;
128 case col_repeated_responses_
:
129 return timestat_
->rsp_dup_num
< other_row
->timestat_
->rsp_dup_num
;
134 return QTreeWidgetItem::operator< (other
);
136 QList
<QVariant
> rowData() {
137 return QList
<QVariant
>() << type_
<< timestat_
->rtd
->num
138 << nstime_to_sec(×tat_
->rtd
->min
) << nstime_to_sec(×tat_
->rtd
->max
)
139 << get_average(×tat_
->rtd
->tot
, timestat_
->rtd
->num
) / 1000.0
140 << timestat_
->rtd
->min_num
<< timestat_
->rtd
->max_num
141 << timestat_
->open_req_num
<< timestat_
->disc_rsp_num
142 << timestat_
->req_dup_num
<< timestat_
->rsp_dup_num
;
147 const rtd_timestat
*timestat_
;
150 ResponseTimeDelayDialog::ResponseTimeDelayDialog(QWidget
&parent
, CaptureFile
&cf
, register_rtd
*rtd
, const QString filter
, int help_topic
) :
151 TapParameterDialog(parent
, cf
, help_topic
),
154 QString subtitle
= tr("%1 Response Time Delay Statistics")
155 .arg(proto_get_protocol_short_name(find_protocol_by_id(get_rtd_proto_id(rtd
))));
156 setWindowSubtitle(subtitle
);
157 loadGeometry(0, 0, "ResponseTimeDelayDialog");
159 QStringList header_names
= QStringList()
160 << tr("Type") << tr("Messages")
161 << tr("Min SRT") << tr("Max SRT") << tr("Avg SRT")
162 << tr("Min in Frame") << tr("Max in Frame")
163 << tr("Open Requests") << tr("Discarded Responses")
164 << tr("Repeated Requests") << tr("Repeated Responses");
166 statsTreeWidget()->setHeaderLabels(header_names
);
168 for (int col
= 0; col
< statsTreeWidget()->columnCount(); col
++) {
169 if (col
== col_type_
) continue;
170 statsTreeWidget()->headerItem()->setTextAlignment(col
, Qt::AlignRight
);
173 if (!filter
.isEmpty()) {
174 setDisplayFilter(filter
);
178 TapParameterDialog
*ResponseTimeDelayDialog::createRtdDialog(QWidget
&parent
, const QString cfg_str
, const QString filter
, CaptureFile
&cf
)
180 if (!cfg_str_to_rtd_
.contains(cfg_str
)) {
185 register_rtd_t
*rtd
= cfg_str_to_rtd_
[cfg_str
];
187 return new ResponseTimeDelayDialog(parent
, cf
, rtd
, filter
);
190 void ResponseTimeDelayDialog::addRtdTable(const _rtd_stat_table
*rtd_table
)
192 for (unsigned i
= 0; i
< rtd_table
->num_rtds
; i
++) {
193 const QString type
= val_to_qstring(i
, get_rtd_value_string(rtd_
), "Other (%d)");
194 new RtdTimeStatTreeWidgetItem(statsTreeWidget(), type
, &rtd_table
->time_stats
[i
]);
198 void ResponseTimeDelayDialog::tapReset(void *rtdd_ptr
)
200 rtd_data_t
*rtdd
= (rtd_data_t
*) rtdd_ptr
;
201 ResponseTimeDelayDialog
*rtd_dlg
= static_cast<ResponseTimeDelayDialog
*>(rtdd
->user_data
);
202 if (!rtd_dlg
) return;
204 reset_rtd_table(&rtdd
->stat_table
);
205 rtd_dlg
->statsTreeWidget()->clear();
206 rtd_dlg
->addRtdTable(&rtdd
->stat_table
);
209 void ResponseTimeDelayDialog::tapDraw(void *rtdd_ptr
)
211 rtd_data_t
*rtdd
= (rtd_data_t
*) rtdd_ptr
;
212 ResponseTimeDelayDialog
*rtd_dlg
= static_cast<ResponseTimeDelayDialog
*>(rtdd
->user_data
);
213 if (!rtd_dlg
|| !rtd_dlg
->statsTreeWidget()) return;
215 QTreeWidgetItemIterator
it(rtd_dlg
->statsTreeWidget());
217 if ((*it
)->type() == rtd_time_stat_type_
) {
218 RtdTimeStatTreeWidgetItem
*rtd_ts_ti
= static_cast<RtdTimeStatTreeWidgetItem
*>((*it
));
224 for (int i
= 0; i
< rtd_dlg
->statsTreeWidget()->columnCount() - 1; i
++) {
225 rtd_dlg
->statsTreeWidget()->resizeColumnToContents(i
);
229 void ResponseTimeDelayDialog::fillTree()
232 memset (&rtd_data
, 0, sizeof(rtd_data
));
233 rtd_table_dissector_init(rtd_
, &rtd_data
.stat_table
, NULL
, NULL
);
234 rtd_data
.user_data
= this;
236 QByteArray display_filter
= displayFilter().toUtf8();
237 if (!registerTapListener(get_rtd_tap_listener_name(rtd_
),
239 display_filter
.constData(),
242 get_rtd_packet_func(rtd_
),
244 free_rtd_table(&rtd_data
.stat_table
);
245 reject(); // XXX Stay open instead?
249 statsTreeWidget()->setSortingEnabled(false);
251 cap_file_
.retapPackets();
255 statsTreeWidget()->sortItems(col_type_
, Qt::AscendingOrder
);
256 statsTreeWidget()->setSortingEnabled(true);
258 removeTapListeners();
259 free_rtd_table(&rtd_data
.stat_table
);
262 QList
<QVariant
> ResponseTimeDelayDialog::treeItemData(QTreeWidgetItem
*ti
) const
265 if (ti
->type() == rtd_time_stat_type_
) {
266 RtdTimeStatTreeWidgetItem
*rtd_ts_ti
= static_cast<RtdTimeStatTreeWidgetItem
*>(ti
);
267 tid
<< rtd_ts_ti
->rowData();