forked from osmocom/wireshark
271 lines
9.4 KiB
C++
271 lines
9.4 KiB
C++
/* response_time_delay_dialog.cpp
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "response_time_delay_dialog.h"
|
|
|
|
#include "file.h"
|
|
|
|
#include "epan/proto.h"
|
|
#include "epan/rtd_table.h"
|
|
|
|
#include <QTreeWidget>
|
|
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
|
#include "wireshark_application.h"
|
|
|
|
static QHash<const QString, register_rtd_t *> cfg_str_to_rtd_;
|
|
|
|
extern "C" {
|
|
static void
|
|
rtd_init(const char *args, void*) {
|
|
QStringList args_l = QString(args).split(',');
|
|
if (args_l.length() > 1) {
|
|
QString rtd = QString("%1,%2").arg(args_l[0]).arg(args_l[1]);
|
|
QString filter;
|
|
if (args_l.length() > 2) {
|
|
filter = QStringList(args_l.mid(2)).join(",");
|
|
}
|
|
wsApp->emitTapParameterSignal(rtd, filter, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
gboolean register_response_time_delay_tables(const void *, void *value, void*)
|
|
{
|
|
register_rtd_t *rtd = (register_rtd_t*)value;
|
|
const char* short_name = proto_get_protocol_short_name(find_protocol_by_id(get_rtd_proto_id(rtd)));
|
|
char *cfg_abbr = rtd_table_get_tap_string(rtd);
|
|
|
|
cfg_str_to_rtd_[cfg_abbr] = rtd;
|
|
TapParameterDialog::registerDialog(
|
|
short_name,
|
|
cfg_abbr,
|
|
REGISTER_STAT_GROUP_RESPONSE_TIME,
|
|
rtd_init,
|
|
ResponseTimeDelayDialog::createRtdDialog);
|
|
g_free(cfg_abbr);
|
|
return FALSE;
|
|
}
|
|
|
|
enum {
|
|
col_type_,
|
|
col_messages_,
|
|
col_min_srt_,
|
|
col_max_srt_,
|
|
col_avg_srt_,
|
|
col_min_frame_,
|
|
col_max_frame_,
|
|
col_open_requests,
|
|
col_discarded_responses_,
|
|
col_repeated_requests_,
|
|
col_repeated_responses_
|
|
};
|
|
|
|
enum {
|
|
rtd_table_type_ = 1000,
|
|
rtd_time_stat_type_
|
|
};
|
|
|
|
class RtdTimeStatTreeWidgetItem : public QTreeWidgetItem
|
|
{
|
|
public:
|
|
RtdTimeStatTreeWidgetItem(QTreeWidget *parent, const QString type, const rtd_timestat *timestat) :
|
|
QTreeWidgetItem (parent, rtd_time_stat_type_),
|
|
type_(type),
|
|
timestat_(timestat)
|
|
{
|
|
setText(col_type_, type_);
|
|
setHidden(true);
|
|
}
|
|
void draw() {
|
|
setText(col_messages_, QString::number(timestat_->rtd->num));
|
|
setText(col_min_srt_, QString::number(nstime_to_sec(×tat_->rtd->min), 'f', 6));
|
|
setText(col_max_srt_, QString::number(nstime_to_sec(×tat_->rtd->max), 'f', 6));
|
|
setText(col_avg_srt_, QString::number(get_average(×tat_->rtd->tot, timestat_->rtd->num) / 1000.0, 'f', 6));
|
|
setText(col_min_frame_, QString::number(timestat_->rtd->min_num));
|
|
setText(col_max_frame_, QString::number(timestat_->rtd->max_num));
|
|
setText(col_open_requests, QString::number(timestat_->open_req_num));
|
|
setText(col_discarded_responses_, QString::number(timestat_->disc_rsp_num));
|
|
setText(col_repeated_requests_, QString::number(timestat_->req_dup_num));
|
|
setText(col_repeated_responses_, QString::number(timestat_->rsp_dup_num));
|
|
|
|
setHidden(timestat_->rtd->num < 1);
|
|
}
|
|
bool operator< (const QTreeWidgetItem &other) const
|
|
{
|
|
if (other.type() != rtd_time_stat_type_) return QTreeWidgetItem::operator< (other);
|
|
const RtdTimeStatTreeWidgetItem *other_row = static_cast<const RtdTimeStatTreeWidgetItem *>(&other);
|
|
|
|
switch (treeWidget()->sortColumn()) {
|
|
case col_messages_:
|
|
return timestat_->rtd->num < other_row->timestat_->rtd->num;
|
|
case col_min_srt_:
|
|
return nstime_cmp(×tat_->rtd->min, &other_row->timestat_->rtd->min) < 0;
|
|
case col_max_srt_:
|
|
return nstime_cmp(×tat_->rtd->max, &other_row->timestat_->rtd->max) < 0;
|
|
case col_avg_srt_:
|
|
{
|
|
double our_avg = get_average(×tat_->rtd->tot, timestat_->rtd->num);
|
|
double other_avg = get_average(&other_row->timestat_->rtd->tot, other_row->timestat_->rtd->num);
|
|
return our_avg < other_avg;
|
|
}
|
|
case col_min_frame_:
|
|
return timestat_->rtd->min_num < other_row->timestat_->rtd->min_num;
|
|
case col_max_frame_:
|
|
return timestat_->rtd->max_num < other_row->timestat_->rtd->max_num;
|
|
case col_open_requests:
|
|
return timestat_->open_req_num < other_row->timestat_->open_req_num;
|
|
case col_discarded_responses_:
|
|
return timestat_->disc_rsp_num < other_row->timestat_->disc_rsp_num;
|
|
case col_repeated_requests_:
|
|
return timestat_->req_dup_num < other_row->timestat_->req_dup_num;
|
|
case col_repeated_responses_:
|
|
return timestat_->rsp_dup_num < other_row->timestat_->rsp_dup_num;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return QTreeWidgetItem::operator< (other);
|
|
}
|
|
QList<QVariant> rowData() {
|
|
return QList<QVariant>() << type_ << timestat_->rtd->num
|
|
<< nstime_to_sec(×tat_->rtd->min) << nstime_to_sec(×tat_->rtd->max)
|
|
<< get_average(×tat_->rtd->tot, timestat_->rtd->num) / 1000.0
|
|
<< timestat_->rtd->min_num << timestat_->rtd->max_num
|
|
<< timestat_->open_req_num << timestat_->disc_rsp_num
|
|
<< timestat_->req_dup_num << timestat_->rsp_dup_num;
|
|
}
|
|
|
|
private:
|
|
const QString type_;
|
|
const rtd_timestat *timestat_;
|
|
};
|
|
|
|
ResponseTimeDelayDialog::ResponseTimeDelayDialog(QWidget &parent, CaptureFile &cf, register_rtd *rtd, const QString filter, int help_topic) :
|
|
TapParameterDialog(parent, cf, help_topic),
|
|
rtd_(rtd)
|
|
{
|
|
QString subtitle = tr("%1 Response Time Delay Statistics")
|
|
.arg(proto_get_protocol_short_name(find_protocol_by_id(get_rtd_proto_id(rtd))));
|
|
setWindowSubtitle(subtitle);
|
|
loadGeometry(0, 0, "ResponseTimeDelayDialog");
|
|
|
|
QStringList header_names = QStringList()
|
|
<< tr("Type") << tr("Messages")
|
|
<< tr("Min SRT") << tr("Max SRT") << tr("Avg SRT")
|
|
<< tr("Min in Frame") << tr("Max in Frame")
|
|
<< tr("Open Requests") << tr("Discarded Responses")
|
|
<< tr("Repeated Requests") << tr("Repeated Responses");
|
|
|
|
statsTreeWidget()->setHeaderLabels(header_names);
|
|
|
|
for (int col = 0; col < statsTreeWidget()->columnCount(); col++) {
|
|
if (col == col_type_) continue;
|
|
statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
|
|
}
|
|
|
|
if (!filter.isEmpty()) {
|
|
setDisplayFilter(filter);
|
|
}
|
|
}
|
|
|
|
TapParameterDialog *ResponseTimeDelayDialog::createRtdDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf)
|
|
{
|
|
if (!cfg_str_to_rtd_.contains(cfg_str)) {
|
|
// XXX MessageBox?
|
|
return NULL;
|
|
}
|
|
|
|
register_rtd_t *rtd = cfg_str_to_rtd_[cfg_str];
|
|
|
|
return new ResponseTimeDelayDialog(parent, cf, rtd, filter);
|
|
}
|
|
|
|
void ResponseTimeDelayDialog::addRtdTable(const _rtd_stat_table *rtd_table)
|
|
{
|
|
for (unsigned i = 0; i < rtd_table->num_rtds; i++) {
|
|
const QString type = val_to_qstring(i, get_rtd_value_string(rtd_), "Other (%d)");
|
|
new RtdTimeStatTreeWidgetItem(statsTreeWidget(), type, &rtd_table->time_stats[i]);
|
|
}
|
|
}
|
|
|
|
void ResponseTimeDelayDialog::tapReset(void *rtdd_ptr)
|
|
{
|
|
rtd_data_t *rtdd = (rtd_data_t*) rtdd_ptr;
|
|
ResponseTimeDelayDialog *rtd_dlg = static_cast<ResponseTimeDelayDialog *>(rtdd->user_data);
|
|
if (!rtd_dlg) return;
|
|
|
|
reset_rtd_table(&rtdd->stat_table);
|
|
rtd_dlg->statsTreeWidget()->clear();
|
|
rtd_dlg->addRtdTable(&rtdd->stat_table);
|
|
}
|
|
|
|
void ResponseTimeDelayDialog::tapDraw(void *rtdd_ptr)
|
|
{
|
|
rtd_data_t *rtdd = (rtd_data_t*) rtdd_ptr;
|
|
ResponseTimeDelayDialog *rtd_dlg = static_cast<ResponseTimeDelayDialog *>(rtdd->user_data);
|
|
if (!rtd_dlg || !rtd_dlg->statsTreeWidget()) return;
|
|
|
|
QTreeWidgetItemIterator it(rtd_dlg->statsTreeWidget());
|
|
while (*it) {
|
|
if ((*it)->type() == rtd_time_stat_type_) {
|
|
RtdTimeStatTreeWidgetItem *rtd_ts_ti = static_cast<RtdTimeStatTreeWidgetItem *>((*it));
|
|
rtd_ts_ti->draw();
|
|
}
|
|
++it;
|
|
}
|
|
|
|
for (int i = 0; i < rtd_dlg->statsTreeWidget()->columnCount() - 1; i++) {
|
|
rtd_dlg->statsTreeWidget()->resizeColumnToContents(i);
|
|
}
|
|
}
|
|
|
|
void ResponseTimeDelayDialog::fillTree()
|
|
{
|
|
rtd_data_t rtd_data;
|
|
memset (&rtd_data, 0, sizeof(rtd_data));
|
|
rtd_table_dissector_init(rtd_, &rtd_data.stat_table, NULL, NULL);
|
|
rtd_data.user_data = this;
|
|
|
|
QByteArray display_filter = displayFilter().toUtf8();
|
|
if (!registerTapListener(get_rtd_tap_listener_name(rtd_),
|
|
&rtd_data,
|
|
display_filter.constData(),
|
|
0,
|
|
tapReset,
|
|
get_rtd_packet_func(rtd_),
|
|
tapDraw)) {
|
|
free_rtd_table(&rtd_data.stat_table);
|
|
reject(); // XXX Stay open instead?
|
|
return;
|
|
}
|
|
|
|
statsTreeWidget()->setSortingEnabled(false);
|
|
|
|
cap_file_.retapPackets();
|
|
|
|
tapDraw(&rtd_data);
|
|
|
|
statsTreeWidget()->sortItems(col_type_, Qt::AscendingOrder);
|
|
statsTreeWidget()->setSortingEnabled(true);
|
|
|
|
removeTapListeners();
|
|
free_rtd_table(&rtd_data.stat_table);
|
|
}
|
|
|
|
QList<QVariant> ResponseTimeDelayDialog::treeItemData(QTreeWidgetItem *ti) const
|
|
{
|
|
QList<QVariant> tid;
|
|
if (ti->type() == rtd_time_stat_type_) {
|
|
RtdTimeStatTreeWidgetItem *rtd_ts_ti = static_cast<RtdTimeStatTreeWidgetItem *>(ti);
|
|
tid << rtd_ts_ti->rowData();
|
|
}
|
|
return tid;
|
|
}
|