summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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>