summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorKevin Hogan <kwabena@google.com>2016-12-05 23:50:45 -0800
committerPeter Wu <peter@lekensteyn.nl>2016-12-19 06:04:56 +0000
commit5f6732d74eb731f26d389f378567d2dfa532f24c (patch)
tree8492a27bd0829d1d33aced14c05a7eb21367bbc8 /ui
parent05b3c067ce65149fdb83790771650946aa948808 (diff)
downloadwireshark-5f6732d74eb731f26d389f378567d2dfa532f24c.tar.gz
Qt: minor updates to TCP stream dialog and throughput moving average
The time-based moving average code should use a constant window size as the denominator when calculating throughput. Added QDoubleSpinbox widget to choose the time-based moving average size. Also added (optional) ability to select ACK (reverse) packets as well as data packets when clicking on the base graph. (useful, for example, when examining SACK or DSACK packets) Added CheckBox widget (with tooltip) for user to choose ACK selection Change-Id: Ib3ba4f9be9e30aa8f3088b0b2d48b4ca214f7cc3 Reviewed-on: https://code.wireshark.org/review/19108 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/tcp_stream_dialog.cpp162
-rw-r--r--ui/qt/tcp_stream_dialog.h11
-rw-r--r--ui/qt/tcp_stream_dialog.ui20
3 files changed, 175 insertions, 18 deletions
diff --git a/ui/qt/tcp_stream_dialog.cpp b/ui/qt/tcp_stream_dialog.cpp
index 9bde33e478..d7b4a06b06 100644
--- a/ui/qt/tcp_stream_dialog.cpp
+++ b/ui/qt/tcp_stream_dialog.cpp
@@ -98,9 +98,11 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
packet_num_(0),
mouse_drags_(true),
rubber_band_(NULL),
+ graph_update_timer_(NULL),
num_dsegs_(-1),
num_acks_(-1),
- num_sack_ranges_(-1)
+ num_sack_ranges_(-1),
+ ma_window_size_(1.0)
{
struct segment current;
int graph_idx = -1;
@@ -184,11 +186,21 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
graph_.stream = header->th_stream;
findStream();
+ showWidgetsForGraphType();
+
ui->streamNumberSpinBox->blockSignals(true);
ui->streamNumberSpinBox->setMaximum(get_tcp_stream_count() - 1);
ui->streamNumberSpinBox->setValue(graph_.stream);
ui->streamNumberSpinBox->blockSignals(false);
+#ifdef MA_1_SECOND
+ ui->maWindowSizeSpinBox->blockSignals(true);
+ ui->maWindowSizeSpinBox->setDecimals(6);
+ ui->maWindowSizeSpinBox->setMinimum(0.000001);
+ ui->maWindowSizeSpinBox->setValue(ma_window_size_);
+ ui->maWindowSizeSpinBox->blockSignals(false);
+#endif
+
QCustomPlot *sp = ui->streamPlot;
QCPPlotTitle *file_title = new QCPPlotTitle(sp, cf_get_display_name(cap_file_));
file_title->setFont(sp->xAxis->labelFont());
@@ -202,7 +214,7 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
base_graph_->setPen(QPen(QBrush(graph_color_1), 0.25));
tput_graph_ = sp->addGraph(sp->xAxis, sp->yAxis2); // Throughput: Moving average
tput_graph_->setPen(QPen(QBrush(graph_color_2), 0.5));
- tput_graph_->setLineStyle(QCPGraph::lsLine);
+ tput_graph_->setLineStyle(QCPGraph::lsStepLeft);
seg_graph_ = sp->addGraph(); // tcptrace: fwd segments
seg_graph_->setErrorType(QCPGraph::etValue);
seg_graph_->setLineStyle(QCPGraph::lsNone);
@@ -264,6 +276,17 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event)
{
int pan_pixels = event->modifiers() & Qt::ShiftModifier ? 1 : 10;
+ if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) &&
+ ui->maWindowSizeSpinBox->hasFocus()) {
+
+ // If user was editing maWindowSize, then just use the new value
+ // clear the focus and accept the event
+ // (don't propagate to default close button)
+ ui->maWindowSizeSpinBox->clearFocus();
+ event->accept();
+ return;
+ }
+
// XXX - This differs from the main window but matches other applications (e.g. Mozilla and Safari)
switch(event->key()) {
case Qt::Key_Minus:
@@ -379,7 +402,7 @@ void TCPStreamDialog::findStream()
connect(sp, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoved(QMouseEvent*)));
}
-void TCPStreamDialog::fillGraph()
+void TCPStreamDialog::fillGraph(bool reset_axes, bool set_focus)
{
QCustomPlot *sp = ui->streamPlot;
@@ -424,17 +447,25 @@ void TCPStreamDialog::fillGraph()
time_stamp_map_.clear();
for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
+ // NOTE - adding both forward and reverse packets to time_stamp_map_
+ // so that both data and acks are selectable
+ // (this is important especially in selecting particular SACK pkts)
if (!compareHeaders(seg)) {
bytes_rev += seg->th_seglen;
pkts_rev++;
- continue;
+ } else {
+ bytes_fwd += seg->th_seglen;
+ pkts_fwd++;
}
- bytes_fwd += seg->th_seglen;
- pkts_fwd++;
double ts = seg->rel_secs + seg->rel_usecs / 1000000.0;
if (first) {
if (ts_origin_conn_) ts_offset_ = ts;
- if (seq_origin_zero_) seq_offset_ = seg->th_seq;
+ if (seq_origin_zero_) {
+ if (compareHeaders(seg))
+ seq_offset_ = seg->th_seq;
+ else
+ seq_offset_ = seg->th_ack;
+ }
first = false;
}
time_stamp_map_.insertMulti(ts - ts_offset_, seg);
@@ -469,11 +500,37 @@ void TCPStreamDialog::fillGraph()
.arg(gchar_free_to_qstring(format_size(pkts_rev, format_size_unit_none|format_size_prefix_si)))
.arg(gchar_free_to_qstring(format_size(bytes_rev, format_size_unit_bytes|format_size_prefix_si)));
mouseMoved(NULL);
- resetAxes();
+ if (reset_axes)
+ resetAxes();
+ else
+ sp->replot();
tracer_->setGraph(base_graph_);
// XXX QCustomPlot doesn't seem to draw any sort of focus indicator.
- sp->setFocus();
+ if (set_focus)
+ sp->setFocus();
+}
+
+void TCPStreamDialog::showWidgetsForGraphType()
+{
+#ifdef MA_1_SECOND
+ if (graph_.type == GRAPH_THROUGHPUT) {
+ ui->maWindowSizeLabel->setVisible(true);
+ ui->maWindowSizeSpinBox->setVisible(true);
+ } else {
+ ui->maWindowSizeLabel->setVisible(false);
+ ui->maWindowSizeSpinBox->setVisible(false);
+ }
+#else
+ ui->maWindowSizeLabel->setVisible(false);
+ ui->maWindowSizeSpinBox->setVisible(false);
+#endif
+
+ if (graph_.type == GRAPH_TSEQ_TCPTRACE) {
+ ui->selectAcksCheckBox->setVisible(true);
+ } else {
+ ui->selectAcksCheckBox->setVisible(false);
+ }
}
void TCPStreamDialog::zoomAxes(bool in)
@@ -597,6 +654,8 @@ void TCPStreamDialog::fillTcptrace()
setWindowTitle(dlg_title);
title_->setText(dlg_title);
+ bool allow_ack_select = ui->selectAcksCheckBox->isChecked();
+
QCustomPlot *sp = ui->streamPlot;
sp->yAxis->setLabel(sequence_number_label_);
@@ -606,13 +665,14 @@ void TCPStreamDialog::fillTcptrace()
ack_graph_->setVisible(true);
rwin_graph_->setVisible(true);
- QVector<double> seq_time, seq, sb_time, sb_center, sb_span, ackrwin_time, ack, rwin;
+ QVector<double> pkt_time, pkt_seqnums, sb_time, sb_center, sb_span, ackrwin_time, ack, rwin;
for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
double ts = (seg->rel_secs + seg->rel_usecs / 1000000.0) - ts_offset_;
if (compareHeaders(seg)) {
+ // Add forward direction to base_graph_ (to select data packets)
// Forward direction: seq + data
- seq_time.append(ts);
- seq.append(seg->th_seq - seq_offset_);
+ pkt_time.append(ts);
+ pkt_seqnums.append(seg->th_seq - seq_offset_);
// QCP doesn't have a segment graph type. For now, fake
// it with error bars.
@@ -629,12 +689,18 @@ void TCPStreamDialog::fillTcptrace()
continue;
}
double ackno = seg->th_ack - seq_offset_;
+ if (allow_ack_select) {
+ // Add reverse direction to base_graph_ (to select ACK packets)
+ pkt_time.append(ts);
+ pkt_seqnums.append(ackno);
+ }
+ // Also add reverse packets to the ack_graph_
ackrwin_time.append(ts);
ack.append(ackno);
rwin.append(ackno + seg->th_win);
}
}
- base_graph_->setData(seq_time, seq);
+ base_graph_->setData(pkt_time, pkt_seqnums);
seg_graph_->setDataValueError(sb_time, sb_center, sb_span);
ack_graph_->setData(ackrwin_time, ack);
rwin_graph_->setData(ackrwin_time, rwin);
@@ -644,7 +710,7 @@ void TCPStreamDialog::fillThroughput()
{
QString dlg_title = QString(tr("Throughput")) + streamDescription();
#ifdef MA_1_SECOND
- dlg_title.append(tr(" (1s MA)"));
+ dlg_title.append(tr(" (MA)"));
#else
dlg_title.append(QString(tr(" (%1 Segment MA)")).arg(moving_avg_period_));
#endif
@@ -660,7 +726,11 @@ void TCPStreamDialog::fillThroughput()
tput_graph_->setVisible(true);
+#ifdef MA_1_SECOND
+ if (!graph_.segments) {
+#else
if (!graph_.segments || !graph_.segments->next) {
+#endif
dlg_title.append(tr(" [not enough data]"));
return;
}
@@ -669,10 +739,20 @@ void TCPStreamDialog::fillThroughput()
int oldest = 0;
guint64 sum = 0;
// Financial charts don't show MA data until a full period has elapsed.
+ // [ NOTE - this is because they assume that there's old data that they
+ // don't have access to - but in our case we know that there's NO
+ // data prior to the first packet in the stream - so it's fine to
+ // spit out the MA immediately... ]
// The Rosetta Code MA examples start spitting out values immediately.
// For now use not-really-correct initial values just to keep our vector
// lengths the same.
+#ifdef MA_1_SECOND
+ // NOTE that for the time-based MA case, you certainly can start with the
+ // first segment!
+ for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
+#else
for (struct segment *seg = graph_.segments->next; seg != NULL; seg = seg->next) {
+#endif
if (!compareHeaders(seg)) {
continue;
}
@@ -683,8 +763,12 @@ void TCPStreamDialog::fillThroughput()
seg_len.append(seg->th_seglen);
#ifdef MA_1_SECOND
- while (ts - rel_time[oldest] > 1.0 && oldest < rel_time.size()) {
+ while (ts - rel_time[oldest] > ma_window_size_ && oldest < rel_time.size()) {
sum -= seg_len[oldest];
+ // append points where a packet LEAVES the MA window
+ // (as well as, below, where they ENTER the MA window)
+ tput.append(sum * 8.0 / ma_window_size_);
+ tput_time.append(rel_time[oldest] + ma_window_size_);
oldest++;
}
#else
@@ -694,14 +778,19 @@ void TCPStreamDialog::fillThroughput()
}
#endif
- double dtime = ts - rel_time[oldest];
double av_tput;
sum += seg->th_seglen;
+#ifdef MA_1_SECOND
+ // for time-based MA, delta_t is constant
+ av_tput = sum * 8.0 / ma_window_size_;
+#else
+ double dtime = ts - rel_time[oldest];
if (dtime > 0.0) {
av_tput = sum * 8.0 / dtime;
} else {
av_tput = 0.0;
}
+#endif
// Add a data point only if our time window has advanced. Otherwise
// update the most recent point. (We might want to show a warning
@@ -1087,6 +1176,7 @@ void TCPStreamDialog::on_graphTypeComboBox_currentIndexChanged(int index)
{
if (index < 0) return;
graph_.type = static_cast<tcp_graph_type>(ui->graphTypeComboBox->itemData(index).toInt());
+ showWidgetsForGraphType();
fillGraph();
}
@@ -1102,6 +1192,21 @@ void TCPStreamDialog::setCaptureFile(capture_file *cf)
}
}
+void TCPStreamDialog::updateGraph()
+{
+
+ // graph_update_timer_ is created only when there's a pending
+ // parameter change, and deleted when an update consumes that change.
+ // Therefore lack of an update timer means nothing to update.
+ if (graph_update_timer_) {
+ if (graph_update_timer_->isActive())
+ graph_update_timer_->stop();
+ delete graph_update_timer_;
+ graph_update_timer_ = NULL;
+ fillGraph(/*reset_axes=*/false, /*set_focus=*/false);
+ }
+}
+
void TCPStreamDialog::on_streamNumberSpinBox_valueChanged(int new_stream)
{
if (new_stream >= 0 && new_stream < int(get_tcp_stream_count())) {
@@ -1109,10 +1214,33 @@ void TCPStreamDialog::on_streamNumberSpinBox_valueChanged(int new_stream)
clear_address(&graph_.src_address);
clear_address(&graph_.dst_address);
findStream();
- fillGraph();
+ fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
+ }
+}
+
+void TCPStreamDialog::on_maWindowSizeSpinBox_valueChanged(double new_ma_size)
+{
+ if (new_ma_size > 0.0) {
+ ma_window_size_ = new_ma_size;
+ if (!graph_update_timer_) {
+ graph_update_timer_ = new QTimer(this);
+ graph_update_timer_->setSingleShot(true);
+ connect(graph_update_timer_, SIGNAL(timeout()), this, SLOT(updateGraph()));
+ }
+ graph_update_timer_->start(1000);
}
}
+void TCPStreamDialog::on_maWindowSizeSpinBox_editingFinished()
+{
+ updateGraph();
+}
+
+void TCPStreamDialog::on_selectAcksCheckBox_stateChanged(int /* state */)
+{
+ fillGraph(/*reset_axes=*/false, /*set_focus=*/true);
+}
+
void TCPStreamDialog::on_otherDirectionButton_clicked()
{
on_actionSwitchDirection_triggered();
diff --git a/ui/qt/tcp_stream_dialog.h b/ui/qt/tcp_stream_dialog.h
index 1c2ba0fb7f..980a3ef4f5 100644
--- a/ui/qt/tcp_stream_dialog.h
+++ b/ui/qt/tcp_stream_dialog.h
@@ -36,6 +36,7 @@
#include <QDialog>
#include <QMenu>
#include <QRubberBand>
+#include <QTimer>
namespace Ui {
class TCPStreamDialog;
@@ -54,6 +55,7 @@ signals:
public slots:
void setCaptureFile(capture_file *cf);
+ void updateGraph();
protected:
void showEvent(QShowEvent *event);
@@ -85,13 +87,17 @@ private:
QRubberBand *rubber_band_;
QPoint rb_origin_;
QMenu ctx_menu_;
+ QTimer *graph_update_timer_;
int num_dsegs_;
int num_acks_;
int num_sack_ranges_;
+ double ma_window_size_;
+
void findStream();
- void fillGraph();
+ void fillGraph(bool reset_axes = true, bool set_focus = true);
+ void showWidgetsForGraphType();
void zoomAxes(bool in);
void zoomXAxis(bool in);
void zoomYAxis(bool in);
@@ -117,6 +123,9 @@ private slots:
void on_graphTypeComboBox_currentIndexChanged(int index);
void on_resetButton_clicked();
void on_streamNumberSpinBox_valueChanged(int new_stream);
+ void on_maWindowSizeSpinBox_valueChanged(double new_ma_size);
+ void on_maWindowSizeSpinBox_editingFinished();
+ void on_selectAcksCheckBox_stateChanged(int state);
void on_otherDirectionButton_clicked();
void on_dragRadioButton_toggled(bool checked);
void on_zoomRadioButton_toggled(bool checked);
diff --git a/ui/qt/tcp_stream_dialog.ui b/ui/qt/tcp_stream_dialog.ui
index c64cb847a1..4e7cea956a 100644
--- a/ui/qt/tcp_stream_dialog.ui
+++ b/ui/qt/tcp_stream_dialog.ui
@@ -92,6 +92,26 @@
<widget class="QComboBox" name="graphTypeComboBox"/>
</item>
<item>
+ <widget class="QLabel" name="maWindowSizeLabel">
+ <property name="text">
+ <string>MA Window (s)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="maWindowSizeSpinBox" />
+ </item>
+ <item>
+ <widget class="QCheckBox" name="selectAcksCheckBox">
+ <property name="toolTip">
+ <string>Allow ACKs as well as data packets to be selected by clicking on the graph</string>
+ </property>
+ <property name="text">
+ <string>select ACKs</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>