wireshark/ui/qt/response_time_delay_dialog.cpp

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(&timestat_->rtd->min), 'f', 6));
setText(col_max_srt_, QString::number(nstime_to_sec(&timestat_->rtd->max), 'f', 6));
setText(col_avg_srt_, QString::number(get_average(&timestat_->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(&timestat_->rtd->min, &other_row->timestat_->rtd->min) < 0;
case col_max_srt_:
return nstime_cmp(&timestat_->rtd->max, &other_row->timestat_->rtd->max) < 0;
case col_avg_srt_:
{
double our_avg = get_average(&timestat_->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(&timestat_->rtd->min) << nstime_to_sec(&timestat_->rtd->max)
<< get_average(&timestat_->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;
}