From 03fd39d7f0c409a45e422d9142b48536ec5c8647 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Wed, 4 Sep 2013 23:15:59 +0000 Subject: Throughput graph updates. GTK+: Fix what appears to be an off-by-one error in the MA period (21 segments instead of 20). Throw away our initial segment length instead of subtracting it from the moving sum, which skews the sum. Qt: Add the througput graph. Use bits/s for the throughput y axis. Let the user switch between graph types. The dialog hangs when doing this. I haven't been able to track down the cause. Remove some unused code. Both: Tell the user that we're using a 20 segment moving average. Move more routines to tap-tcp-stream.[ch]. svn path=/trunk/; revision=51759 --- ui/gtk/tcp_graph.c | 80 ++++--------- ui/qt/main_window.h | 2 + ui/qt/main_window.ui | 9 ++ ui/qt/main_window_slots.cpp | 16 ++- ui/qt/tcp_stream_dialog.cpp | 285 +++++++++++++++++++++++++++++++++++--------- ui/qt/tcp_stream_dialog.h | 16 ++- ui/qt/tcp_stream_dialog.ui | 8 +- ui/tap-tcp-stream.c | 38 ++++++ ui/tap-tcp-stream.h | 4 + 9 files changed, 331 insertions(+), 127 deletions(-) diff --git a/ui/gtk/tcp_graph.c b/ui/gtk/tcp_graph.c index a085a12c57..157075accc 100644 --- a/ui/gtk/tcp_graph.c +++ b/ui/gtk/tcp_graph.c @@ -168,7 +168,7 @@ struct style_tseq_stevens { struct style_tput { int width, height; - int nsegs; + int ma_size; int flags; }; @@ -387,8 +387,6 @@ static void callback_graph_init_on_typechg(GtkWidget * , gpointer ); static void callback_create_help(GtkWidget * , gpointer ); static void get_mouse_position(GtkWidget *, int *pointer_x, int *pointer_y, GdkModifierType *mask); static void update_zoom_spins(struct gtk_graph * ); -static int get_num_dsegs(struct gtk_graph * ); -static int get_num_acks(struct gtk_graph *, int * ); static void graph_type_dependent_initialize(struct gtk_graph * ); static struct gtk_graph *graph_new(void); static void graph_destroy(struct gtk_graph * ); @@ -3615,41 +3613,6 @@ static void restore_initial_graph_view(struct gtk_graph *g) } } -static int get_num_dsegs(struct gtk_graph *g) -{ - int count; - struct segment *tmp; - - for (tmp=g->tg.segments, count=0; tmp; tmp=tmp->next) { - if (compare_headers(&g->tg.src_address, &g->tg.dst_address, - g->tg.src_port, g->tg.dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - count++; - } - } - return count; -} - -static int get_num_acks(struct gtk_graph *g, int *num_sack_ranges) -{ - int count; - struct segment *tmp; - - for (tmp = g->tg.segments, count=0; tmp; tmp = tmp->next) { - if (!compare_headers(&g->tg.src_address, &g->tg.dst_address, - g->tg.src_port, g->tg.dst_port, - &tmp->ip_src, &tmp->ip_dst, - tmp->th_sport, tmp->th_dport, - COMPARE_CURR_DIR)) { - count++; - *num_sack_ranges += tmp->num_sack_ranges; - } - } - return count; -} - /* * Stevens-style time-sequence grapH */ @@ -3810,7 +3773,7 @@ static void tseq_stevens_make_elmtlist(struct gtk_graph *g) debug(DBS_FENTRY) puts("tseq_stevens_make_elmtlist()"); if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs(g); + int n = 1 + get_num_dsegs(&g->tg); e = elements = (struct element * )g_malloc(n*sizeof(struct element)); } else e = elements = g->elists->elements; @@ -3936,7 +3899,7 @@ static void tseq_tcptrace_make_elmtlist(struct gtk_graph *g) if (g->elists->elements == NULL ) { /* 3 elements per data segment */ - int n = 1 + 3*get_num_dsegs(g); + int n = 1 + 3*get_num_dsegs(&g->tg); e0 = elements0 = (struct element * )g_malloc(n * sizeof(struct element)); } else { /* Existing array */ @@ -3945,7 +3908,7 @@ static void tseq_tcptrace_make_elmtlist(struct gtk_graph *g) if (g->elists->next->elements == NULL) { /* 4 elements per ACK, but only one for each SACK range */ - int n = 1 + 4*get_num_acks(g, &num_sack_ranges); + int n = 1 + 4*get_num_acks(&g->tg, &num_sack_ranges); n += num_sack_ranges; e1 = elements1 = (struct element * )g_malloc(n * sizeof(struct element)); } else { @@ -4140,18 +4103,18 @@ static void tput_make_elmtlist(struct gtk_graph *g) int num_sack_ranges; if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs(g) + get_num_acks(g, &num_sack_ranges); + int n = 1 + get_num_dsegs(&g->tg) + get_num_acks(&g->tg, &num_sack_ranges); e = elements = (struct element * )g_malloc(n * sizeof(struct element)); } else e = elements = g->elists->elements; - for (oldest=g->tg.segments, tmp=g->tg.segments->next, i=0; tmp; tmp=tmp->next, i++) { + for (oldest=g->tg.segments, tmp=g->tg.segments->next, i=1; tmp; tmp=tmp->next, i++) { double time_val = tmp->rel_secs + tmp->rel_usecs/1000000.0; - dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0); - if (i>g->s.tput.nsegs) { - sum -= oldest->th_seglen; + if (i>g->s.tput.ma_size) { oldest = oldest->next; + sum -= oldest->th_seglen; } + dtime = time_val - (oldest->rel_secs + oldest->rel_usecs/1000000.0); sum += tmp->th_seglen; tput = sum / dtime; /* debug(DBS_TPUT_ELMTS) printf("tput=%f\n", tput); */ @@ -4173,8 +4136,8 @@ static void tput_make_elmtlist(struct gtk_graph *g) * - call setup routine for style struct */ static void tput_initialize(struct gtk_graph *g) { - struct segment *tmp, *oldest/*, *last*/; - int i, sum = 0; + struct segment *tmp, *oldest = g->tg.segments/*, *last*/; + int i, sum = oldest->th_seglen; double dtime, tput, tputmax = 0; double t, t0, tmax = 0, yy0, ymax; @@ -4182,16 +4145,13 @@ static void tput_initialize(struct gtk_graph *g) tput_read_config(g); -#if 0 - for (last=g->tg.segments; last->next; last=last->next); /* XXX: does nothing useful ? */ -#endif - for (oldest=g->tg.segments, tmp=g->tg.segments->next, i=0; tmp; tmp=tmp->next, i++) { - dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 - - (oldest->rel_secs + oldest->rel_usecs/1000000.0); - if (i > g->s.tput.nsegs) { - sum -= oldest->th_seglen; + for (tmp=g->tg.segments->next, i=1; tmp; tmp=tmp->next, i++) { + if (i > g->s.tput.ma_size) { oldest = oldest->next; + sum -= oldest->th_seglen; } + dtime = tmp->rel_secs + tmp->rel_usecs/1000000.0 - + (oldest->rel_secs + oldest->rel_usecs/1000000.0); sum += tmp->th_seglen; tput = sum / dtime; debug(DBS_TPUT_ELMTS) printf("tput=%f\n", tput); @@ -4220,10 +4180,10 @@ static void tput_read_config(struct gtk_graph *g) g->s.tput.width = 4; g->s.tput.height = 4; - g->s.tput.nsegs = 20; + g->s.tput.ma_size = 20; g->title = (const char ** )g_malloc(2 * sizeof(char *)); - g->title[0] = "Throughput Graph"; + g->title[0] = "Throughput (20 segment MA)"; g->title[1] = NULL; g->y_axis->label = (const char ** )g_malloc(3 * sizeof(char * )); g->y_axis->label[0] = "[B/s]"; @@ -4400,7 +4360,7 @@ static void rtt_make_elmtlist(struct gtk_graph *g) debug(DBS_FENTRY) puts("rtt_make_elmtlist()"); if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs(g); + int n = 1 + get_num_dsegs(&g->tg); e = elements = (struct element * )g_malloc(n * sizeof(struct element)); } else { e = elements = g->elists->elements; @@ -4548,7 +4508,7 @@ static void wscale_make_elmtlist(struct gtk_graph *g) /* Allocate memory for elements if not already done */ if (g->elists->elements == NULL) { - int n = 1 + get_num_dsegs(g); + int n = 1 + get_num_dsegs(&g->tg); e = elements = (struct element*)g_malloc(n*sizeof(struct element)); } else diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 0f68a9b863..bdbf1bc168 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -298,7 +298,9 @@ private slots: void on_actionStopCapture_triggered(); void on_actionSummary_triggered(); + void openTcpStreamDialog(int graph_type); void on_actionStatisticsTcpStreamStevens_triggered(); + void on_actionStatisticsTcpStreamThroughput_triggered(); }; diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index 536093cef6..fdbeb811b9 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -320,6 +320,7 @@ TCP Stream Graphs + @@ -1256,6 +1257,14 @@ TCP time sequence graph (Stevens) + + + Throughput + + + TCP througput + + diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index ef927e020a..82f2b264ee 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -1689,14 +1689,26 @@ void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered() // Statistics Menu -void MainWindow::on_actionStatisticsTcpStreamStevens_triggered() + +void MainWindow::openTcpStreamDialog(int graph_type) { - TCPStreamDialog stream_dialog(this, cap_file_, GRAPH_TSEQ_STEVENS); + TCPStreamDialog stream_dialog(this, cap_file_, (tcp_graph_type)graph_type); connect(&stream_dialog, SIGNAL(goToPacket(int)), packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + &stream_dialog, SLOT(setCaptureFile(capture_file*))); stream_dialog.exec(); } +void MainWindow::on_actionStatisticsTcpStreamStevens_triggered() +{ + openTcpStreamDialog(GRAPH_TSEQ_STEVENS); +} + +void MainWindow::on_actionStatisticsTcpStreamThroughput_triggered() +{ + openTcpStreamDialog(GRAPH_THROUGHPUT); +} // Help Menu void MainWindow::on_actionHelpContents_triggered() { diff --git a/ui/qt/tcp_stream_dialog.cpp b/ui/qt/tcp_stream_dialog.cpp index 5eec0faca9..36b4ffcd51 100644 --- a/ui/qt/tcp_stream_dialog.cpp +++ b/ui/qt/tcp_stream_dialog.cpp @@ -37,11 +37,20 @@ #include +const int moving_avg_period_ = 20; +const QRgb graph_color_1 = tango_sky_blue_5; +const QRgb graph_color_2 = tango_butter_6; + +Q_DECLARE_METATYPE(tcp_graph_type) + TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_type graph_type) : QDialog(parent), ui(new Ui::TCPStreamDialog), cap_file_(cf), - tracer_(NULL) + tracer_(NULL), + num_dsegs_(-1), + num_acks_(-1), + num_sack_ranges_(-1) { struct segment current; @@ -55,74 +64,42 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty // ui->hintLabel->setAttribute(Qt::WA_MacSmallSize, true); //#endif + ui->graphTypeComboBox->setUpdatesEnabled(false); + ui->graphTypeComboBox->addItem(tr("Time / Sequence (Stevens)"), qVariantFromValue(GRAPH_TSEQ_STEVENS)); + ui->graphTypeComboBox->addItem(tr("Throughput"), qVariantFromValue(GRAPH_THROUGHPUT)); + ui->graphTypeComboBox->setCurrentIndex(-1); + ui->graphTypeComboBox->setUpdatesEnabled(true); + memset (&graph_, 0, sizeof(graph_)); graph_.type = graph_type; - graph_segment_list_get(cap_file_, &graph_, FALSE); - - QString dlg_title = QString(tr("TCP Graph %1 %2:%3 %4 %5:%6")) - .arg(cf_get_display_name(cap_file_)) - .arg(ep_address_to_str(&graph_.src_address)) - .arg(graph_.src_port) - .arg(UTF8_RIGHTWARDS_ARROW) - .arg(ep_address_to_str(&graph_.dst_address)) - .arg(graph_.dst_port); - setWindowTitle(dlg_title); - - QVector rel_time, seq; - double rel_time_min = QCPRange::maxRange, rel_time_max = QCPRange::minRange; - double seq_min = QCPRange::maxRange, seq_max = QCPRange::minRange; - for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) { - if (!compareHeaders(seg)) { - continue; - } - - double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0; - - rel_time.append(rt_val); - if (rel_time_min > rt_val) rel_time_min = rt_val; - if (rel_time_max < rt_val) rel_time_max = rt_val; - - seq.append(seg->th_seq); - if (seq_min > seg->th_seq) seq_min = seg->th_seq; - if (seq_max < seg->th_seq) seq_max = seg->th_seq; - - segment_map_.insertMulti(rt_val, seg); - } QCustomPlot *sp = ui->streamPlot; + title_ = new QCPPlotTitle(sp); + tracer_ = new QCPItemTracer(sp); sp->plotLayout()->insertRow(0); - sp->plotLayout()->addElement(0, 0, new QCPPlotTitle(sp, dlg_title)); - sp->addGraph(); - sp->graph(0)->setData(rel_time, seq); + sp->plotLayout()->addElement(0, 0, title_); + sp->addGraph(); // 0 - All: Selectable segments + sp->addGraph(sp->xAxis, sp->yAxis2); // 1 - Throughput: Moving average + sp->addItem(tracer_); + + // Fills the graph + ui->graphTypeComboBox->setCurrentIndex(ui->graphTypeComboBox->findData(qVariantFromValue(graph_type))); + sp->setInteractions( QCP::iRangeDrag | QCP::iRangeZoom ); sp->setMouseTracking(true); - // True Stevens-style graphs don't have lines but I like them - gcc - sp->graph(0)->setPen(QPen(QBrush(tango_sky_blue_5), 0.25)); - sp->graph(0)->setLineStyle(QCPGraph::lsStepLeft); + sp->graph(0)->setPen(QPen(QBrush(graph_color_1), 0.25)); sp->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); sp->xAxis->setLabel(tr("Time (s)")); - double range_pad = (rel_time_max - rel_time_min) * 0.05; - data_range_.setLeft(rel_time_min - range_pad); - data_range_.setRight(rel_time_max + range_pad); - sp->xAxis->setRange(data_range_.left(), data_range_.right()); - sp->yAxis->setLabel(tr("Sequence number (B)")); - range_pad = (seq_max - seq_min) * 0.05; - data_range_.setBottom(seq_min - range_pad); - data_range_.setTop(seq_max + range_pad); - sp->yAxis->setRange(data_range_.bottom(), data_range_.top()); + sp->yAxis->setTickLabelColor(QColor(graph_color_1)); - tracer_ = new QCPItemTracer(sp); tracer_->setVisible(false); - tracer_->setGraph(sp->graph(0)); - tracer_->setInterpolating(false); - sp->addItem(tracer_); toggleTracerStyle(true); - // XXX - QCustomPlot doesn't seem to draw any sort of focus indicator. + // XXX QCustomPlot doesn't seem to draw any sort of focus indicator. sp->setFocus(); QPushButton *save_bt = ui->buttonBox->button(QDialogButtonBox::Save); @@ -130,7 +107,10 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty connect(sp, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(graphClicked(QMouseEvent*))); connect(sp, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMoved(QMouseEvent*))); + connect(sp->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(translateYRange(QCPRange))); disconnect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + + mouseMoved(NULL); } TCPStreamDialog::~TCPStreamDialog() @@ -189,9 +169,7 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event) case Qt::Key_ParenRight: // Shifted 0 on U.S. keyboards case Qt::Key_R: case Qt::Key_Home: - sp->xAxis->setRange(data_range_.left(), data_range_.right()); - sp->yAxis->setRange(data_range_.bottom(), data_range_.top()); - sp->replot(); + resetAxes(); break; // Alas, there is no Blade Runner-style Qt::Key_Ehance } @@ -216,6 +194,177 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event) QDialog::keyPressEvent(event); } +void TCPStreamDialog::fillGraph() +{ + QCustomPlot *sp = ui->streamPlot; + + if (sp->graphCount() < 1) return; + + segment_map_.clear(); + graph_segment_list_free(&graph_); + graph_segment_list_get(cap_file_, &graph_, FALSE); + + for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) { + if (!compareHeaders(seg)) { + continue; + } + double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0; + segment_map_.insertMulti(rt_val, seg); + } + + tracer_->setGraph(NULL); + // We need at least one graph, so don't bother deleting the first one. + for (int i = 0; i < sp->graphCount(); i++) { + sp->graph(i)->clearData(); + sp->graph(i)->setVisible(i == 0 ? true : false); + } + sp->yAxis2->setVisible(false); + sp->yAxis2->setLabel(QString()); + + if (!cap_file_) { + QString dlg_title = QString(tr("No capture file")); + setWindowTitle(dlg_title); + title_->setText(dlg_title); + sp->setEnabled(false); + } else { + switch (graph_.type) { + case GRAPH_TSEQ_STEVENS: + initializeStevens(); + break; + case GRAPH_THROUGHPUT: + initializeThroughput(); + break; + default: + break; + } + sp->setEnabled(true); + } + resetAxes(); + tracer_->setGraph(sp->graph(0)); +} + +void TCPStreamDialog::resetAxes() +{ + QCustomPlot *sp = ui->streamPlot; + + y_translate_mul_ = 0.0; + + sp->graph(0)->rescaleAxes(false, true); + for (int i = 1; i < sp->graphCount(); i++) { + sp->graph(i)->rescaleValueAxis(false, true); + } + + double range_pad = (sp->xAxis->range().upper - sp->xAxis->range().lower) * 0.05; + sp->xAxis->setRange(sp->xAxis->range().lower - range_pad, + sp->xAxis->range().upper + range_pad); + + range_pad = (sp->yAxis->range().upper - sp->yAxis->range().lower) * 0.05; + sp->yAxis->setRange(sp->yAxis->range().lower - range_pad, + sp->yAxis->range().upper + range_pad); + + range_pad = (sp->yAxis2->range().upper - sp->yAxis2->range().lower) * 0.05; + sp->yAxis2->setRange(sp->yAxis2->range().lower - range_pad, + sp->yAxis2->range().upper + range_pad); + + y_translate_mul_ = (sp->yAxis2->range().upper - sp->yAxis2->range().lower) + / (sp->yAxis->range().upper - sp->yAxis->range().lower); + + sp->replot(); +} + +void TCPStreamDialog::initializeStevens() +{ + QString dlg_title = QString(tr("TCP Graph ")) + streamDescription(); + setWindowTitle(dlg_title); + title_->setText(dlg_title); + + QCustomPlot *sp = ui->streamPlot; + // True Stevens-style graphs don't have lines but I like them - gcc + sp->graph(0)->setLineStyle(QCPGraph::lsStepLeft); + + QVector rel_time, seq; + for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) { + if (!compareHeaders(seg)) { + continue; + } + + double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0; + rel_time.append(rt_val); + seq.append(seg->th_seq); + } + sp->graph(0)->setData(rel_time, seq); + sp->yAxis->setLabel(tr("Sequence number (B)")); +} + +void TCPStreamDialog::initializeThroughput() +{ + QString dlg_title = QString(tr("Throughput ")) + + streamDescription() + + QString(tr(" (%1 segment MA)")).arg(moving_avg_period_); + setWindowTitle(dlg_title); + title_->setText(dlg_title); + + QCustomPlot *sp = ui->streamPlot; + sp->graph(0)->setLineStyle(QCPGraph::lsNone); + sp->graph(1)->setVisible(true); + sp->graph(1)->setPen(QPen(QBrush(graph_color_2), 0.5)); + sp->graph(1)->setLineStyle(QCPGraph::lsLine); + + if (!graph_.segments || !graph_.segments->next) { + dlg_title.append(tr(" [not enough data]")); + return; + } + + QVector rel_time, seg_len, tput; + struct segment *oldest_seg = graph_.segments; + int i = 1, sum = 0; + // Financial charts don't show MA data until a full period has elapsed. + // 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. + for (struct segment *seg = graph_.segments->next; seg != NULL; seg = seg->next) { + double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0; + + if (i > moving_avg_period_) { + oldest_seg = oldest_seg->next; + sum -= oldest_seg->th_seglen; + } + i++; + + double dtime = rt_val - (oldest_seg->rel_secs + oldest_seg->rel_usecs / 1000000.0); + double av_tput; + sum += seg->th_seglen; + if (dtime > 0.0) { + av_tput = sum * 8.0 / dtime; + } else { + av_tput = 0.0; + } + + rel_time.append(rt_val); + seg_len.append(seg->th_seglen); + tput.append(av_tput); + } + sp->graph(0)->setData(rel_time, seg_len); + sp->graph(1)->setData(rel_time, tput); + + sp->yAxis->setLabel(tr("Segment length (B)")); + + sp->yAxis2->setLabel(tr("Avg througput (bits/s)")); + sp->yAxis2->setTickLabelColor(QColor(graph_color_2)); + sp->yAxis2->setVisible(true); +} + +QString TCPStreamDialog::streamDescription() +{ + return QString(tr("%1 %2:%3 %4 %5:%6")) + .arg(cf_get_display_name(cap_file_)) + .arg(ep_address_to_str(&graph_.src_address)) + .arg(graph_.src_port) + .arg(UTF8_RIGHTWARDS_ARROW) + .arg(ep_address_to_str(&graph_.dst_address)) + .arg(graph_.dst_port); +} + bool TCPStreamDialog::compareHeaders(segment *seg) { return (compare_headers(&graph_.src_address, &graph_.dst_address, @@ -265,11 +414,10 @@ void TCPStreamDialog::graphClicked(QMouseEvent *event) // using a QTimer instead. void TCPStreamDialog::mouseMoved(QMouseEvent *event) { - QRect spr = ui->streamPlot->axisRect()->rect(); struct segment *packet_seg = NULL; packet_num_ = 0; - if (spr.contains(event->pos())) { + if (event && tracer_->graph() && tracer_->position->axisRect()->rect().contains(event->pos())) { double ts = tracer_->position->key(); packet_seg = segment_map_.value(ts, NULL); } @@ -294,6 +442,16 @@ void TCPStreamDialog::mouseMoved(QMouseEvent *event) ui->streamPlot->replot(); } +void TCPStreamDialog::translateYRange(const QCPRange &y_range1) +{ + if (y_translate_mul_ <= 0.0) return; + + QCustomPlot *sp = ui->streamPlot; + + sp->yAxis2->setRangeUpper(y_range1.upper * y_translate_mul_); + sp->yAxis2->setRangeLower(y_range1.lower * y_translate_mul_); +} + void TCPStreamDialog::on_buttonBox_accepted() { QString file_name, extension; @@ -331,6 +489,19 @@ void TCPStreamDialog::on_buttonBox_accepted() } } +void TCPStreamDialog::on_graphTypeComboBox_currentIndexChanged(int index) +{ + if (index < 0) return; + graph_.type = ui->graphTypeComboBox->itemData(index).value(); + fillGraph(); +} + +void TCPStreamDialog::setCaptureFile(capture_file *cf) +{ + cap_file_ = cf; + fillGraph(); +} + /* * Editor modelines * diff --git a/ui/qt/tcp_stream_dialog.h b/ui/qt/tcp_stream_dialog.h index 129c1b9345..f9b874a9dd 100644 --- a/ui/qt/tcp_stream_dialog.h +++ b/ui/qt/tcp_stream_dialog.h @@ -52,6 +52,9 @@ public: signals: void goToPacket(int packet_num); +public slots: + void setCaptureFile(capture_file *cf); + protected: void keyPressEvent(QKeyEvent *event); @@ -60,18 +63,29 @@ private: capture_file *cap_file_; QMap segment_map_; struct tcp_graph graph_; - QRectF data_range_; + QCPPlotTitle *title_; QCPItemTracer *tracer_; guint32 packet_num_; + double y_translate_mul_; + int num_dsegs_; + int num_acks_; + int num_sack_ranges_; + void fillGraph(); + void resetAxes(); + void initializeStevens(); + void initializeThroughput(); + QString streamDescription(); bool compareHeaders(struct segment *seg); void toggleTracerStyle(bool force_default = false); private slots: void graphClicked(QMouseEvent *event); void mouseMoved(QMouseEvent *event); + void translateYRange(const QCPRange &y_range1); void on_buttonBox_accepted(); + void on_graphTypeComboBox_currentIndexChanged(int index); }; #endif // TCP_STREAM_DIALOG_H diff --git a/ui/qt/tcp_stream_dialog.ui b/ui/qt/tcp_stream_dialog.ui index 12a09c5982..fb37550ea3 100644 --- a/ui/qt/tcp_stream_dialog.ui +++ b/ui/qt/tcp_stream_dialog.ui @@ -64,13 +64,7 @@ - - - - Time / Sequence (Stevens) - - - + diff --git a/ui/tap-tcp-stream.c b/ui/tap-tcp-stream.c index 4be31f4c4e..dffa6cd15d 100644 --- a/ui/tap-tcp-stream.c +++ b/ui/tap-tcp-stream.c @@ -176,6 +176,44 @@ compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1 } } +int +get_num_dsegs(struct tcp_graph *tg) +{ + int count; + struct segment *tmp; + + for (tmp=tg->segments, count=0; tmp; tmp=tmp->next) { + if (compare_headers(&tg->src_address, &tg->dst_address, + tg->src_port, tg->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + count++; + } + } + return count; +} + +int +get_num_acks(struct tcp_graph *tg, int *num_sack_ranges) +{ + int count; + struct segment *tmp; + + for (tmp = tg->segments, count=0; tmp; tmp = tmp->next) { + if (!compare_headers(&tg->src_address, &tg->dst_address, + tg->src_port, tg->dst_port, + &tmp->ip_src, &tmp->ip_dst, + tmp->th_sport, tmp->th_dport, + COMPARE_CURR_DIR)) { + count++; + *num_sack_ranges += tmp->num_sack_ranges; + } + } + return count; +} + + typedef struct _th_t { int num_hdrs; diff --git a/ui/tap-tcp-stream.h b/ui/tap-tcp-stream.h index 71f9a5c0f6..551b09af15 100644 --- a/ui/tap-tcp-stream.h +++ b/ui/tap-tcp-stream.h @@ -84,8 +84,12 @@ void graph_segment_list_free(struct tcp_graph * ); int compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir); +int get_num_dsegs(struct tcp_graph * ); +int get_num_acks(struct tcp_graph *, int * ); + struct tcpheader *select_tcpip_session(capture_file *, struct segment * ); + #ifdef __cplusplus } #endif /* __cplusplus */ -- cgit v1.2.1