diff options
Diffstat (limited to 'ui/qt/sctp_graph_dialog.cpp')
-rw-r--r-- | ui/qt/sctp_graph_dialog.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/ui/qt/sctp_graph_dialog.cpp b/ui/qt/sctp_graph_dialog.cpp new file mode 100644 index 0000000000..83c7ff907e --- /dev/null +++ b/ui/qt/sctp_graph_dialog.cpp @@ -0,0 +1,399 @@ +#include "sctp_graph_dialog.h" +#include "ui_sctp_graph_dialog.h" + +#include "wireshark_application.h" + +SCTPGraphDialog::SCTPGraphDialog(QWidget *parent, sctp_assoc_info_t *assoc, capture_file *cf, int dir) : + QDialog(parent), + ui(new Ui::SCTPGraphDialog), + selected_assoc(assoc), + cap_file_(cf), + direction(dir) +{ + ui->setupUi(this); + this->setWindowTitle(QString("SCTP TSNs and SACKs over Time: %1 Port1 %2 Port2 %3").arg(cf_get_display_name(cap_file_)).arg(selected_assoc->port1).arg(selected_assoc->port2)); + if ((direction == 1 && selected_assoc->n_array_tsn1 == 0) || (direction == 2 && selected_assoc->n_array_tsn2 == 0)) { + QMessageBox msgBox; + msgBox.setText("No Data Chunks sent"); + msgBox.exec(); + return; + } else { + drawGraph(3); + } +} + +SCTPGraphDialog::~SCTPGraphDialog() +{ + delete ui; +} + +void SCTPGraphDialog::drawNRSACKGraph() +{ + tsn_t *sack; + GList *list=NULL, *tlist; + guint16 gap_start=0, gap_end=0, i, numberOf_gaps, numberOf_nr_gaps; + guint8 type; + guint32 tsnumber, j, min_tsn; + struct nr_sack_chunk_header *nr_sack_header; + struct gaps *nr_gap; + /* This holds the sum of gap acks and nr gap acks */ + guint16 total_gaps = 0; + + if (direction == 1) { + list = g_list_last(selected_assoc->sack1); + min_tsn = selected_assoc->min_tsn1; + } else { + list = g_list_last(selected_assoc->sack1); + min_tsn = selected_assoc->min_tsn1; + } + while (list) { + sack = (tsn_t*) (list->data); + tlist = g_list_first(sack->tsns); + while (tlist) { + type = ((struct chunk_header *)tlist->data)->type; + if (type == SCTP_NR_SACK_CHUNK_ID) { + gIsNRSackChunkPresent = 1; + nr_sack_header =(struct nr_sack_chunk_header *)tlist->data; + numberOf_nr_gaps=g_ntohs(nr_sack_header->nr_of_nr_gaps); + numberOf_gaps=g_ntohs(nr_sack_header->nr_of_gaps); + tsnumber = g_ntohl(nr_sack_header->cum_tsn_ack); + total_gaps = numberOf_gaps + numberOf_nr_gaps; + /* If the number of nr_gaps is greater than 0 */ + if ( total_gaps > 0 ) { + nr_gap = &nr_sack_header->gaps[0]; + for (i = 0; i < total_gaps; i++) { + gap_start = g_ntohs(nr_gap->start); + gap_end = g_ntohs(nr_gap->end); + for ( j = gap_start; j <= gap_end; j++) { + if (i >= numberOf_gaps) { + yn.append(j + tsnumber); + xn.append(sack->secs + sack->usecs/1000000.0); + fn.append(sack->frame_number); + } else { + yg.append(j + tsnumber); + xg.append(sack->secs + sack->usecs/1000000.0); + fg.append(sack->frame_number); + } + } + if (i < total_gaps-1) + nr_gap++; + } + + if (tsnumber>=min_tsn) { + ys.append(j + tsnumber); + xs.append(sack->secs + sack->usecs/1000000.0); + fs.append(sack->frame_number); + } + } + } + tlist = g_list_next(tlist); + } + list = g_list_previous(list); + } +} + +void SCTPGraphDialog::drawSACKGraph() +{ + GList *listSACK = NULL, *tlist; + guint16 gap_start=0, gap_end=0, nr, dup_nr; + struct sack_chunk_header *sack_header; + struct gaps *gap; + tsn_t *tsn; + guint8 type; + guint32 tsnumber=0; + guint32 minTSN; + guint32 *dup_list; + int i, j; + + if (direction == 1) { + minTSN = selected_assoc->min_tsn1; + listSACK = g_list_last(selected_assoc->sack1); + } else { + minTSN = selected_assoc->min_tsn2; + listSACK = g_list_last(selected_assoc->sack2); + } + while (listSACK) { + tsn = (tsn_t*) (listSACK->data); + tlist = g_list_first(tsn->tsns); + while (tlist) { + type = ((struct chunk_header *)tlist->data)->type; + if (type == SCTP_SACK_CHUNK_ID) { + gIsSackChunkPresent = 1; + sack_header =(struct sack_chunk_header *)tlist->data; + nr=g_ntohs(sack_header->nr_of_gaps); + tsnumber = g_ntohl(sack_header->cum_tsn_ack); + dup_nr=g_ntohs(sack_header->nr_of_dups); + if (nr>0) { // Gap Reports green + gap = &sack_header->gaps[0]; + for(i=0;i<nr; i++) { + gap_start=g_ntohs(gap->start); + gap_end = g_ntohs(gap->end); + for (j=gap_start; j<=gap_end; j++) { + yg.append(j+tsnumber); + xg.append(tsn->secs + tsn->usecs/1000000.0); + fg.append(tsn->frame_number); + } + if (i < nr-1) + gap++; + } + } + if (tsnumber>=minTSN) { // CumTSNAck red + ys.append(tsnumber); + xs.append(tsn->secs + tsn->usecs/1000000.0); + fs.append(tsn->frame_number); + } + if (dup_nr > 0) { // Duplicates cyan + dup_list = &sack_header->a_rwnd + 2 + nr; + for (i = 0; i < dup_nr; i++) { + tsnumber = g_ntohl(dup_list[i]); + if (tsnumber >= minTSN) { + yd.append(tsnumber); + xd.append(tsn->secs + tsn->usecs/1000000.0); + fd.append(tsn->frame_number); + } + } + } + } + tlist = g_list_next(tlist); + } + listSACK = g_list_previous(listSACK); + } + + QCPScatterStyle myScatter; + myScatter.setShape(QCPScatterStyle::ssCircle); + myScatter.setSize(3); + + int graphcount = ui->sctpPlot->graphCount(); + // create graph and assign data to it: + + // Add SACK graph + if (xs.size() > 0) { + ui->sctpPlot->addGraph(); + myScatter.setPen(QPen(Qt::red)); + myScatter.setBrush(Qt::red); + ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter); + ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone); + ui->sctpPlot->graph(graphcount)->setData(xs, ys); + typeStrings.insert(graphcount, QString("CumTSNAck")); + graphcount++; + } + + // Add Gap Acks + if (xg.size() > 0) { + ui->sctpPlot->addGraph(); + myScatter.setPen(QPen(Qt::green)); + myScatter.setBrush(Qt::green); + ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter); + ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone); + ui->sctpPlot->graph(graphcount)->setData(xg, yg); + typeStrings.insert(graphcount, QString("Gap Ack")); + graphcount++; + } + + // Add NR Gap Acks + if (xn.size() > 0) { + ui->sctpPlot->addGraph(); + myScatter.setPen(QPen(Qt::blue)); + myScatter.setBrush(Qt::blue); + ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter); + ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone); + ui->sctpPlot->graph(graphcount)->setData(xg, yg); + typeStrings.insert(graphcount, QString("NR Gap Ack")); + graphcount++; + } + + // Add Duplicates + if (xd.size() > 0) { + ui->sctpPlot->addGraph(); + myScatter.setPen(QPen(Qt::cyan)); + myScatter.setBrush(Qt::cyan); + ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter); + ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone); + ui->sctpPlot->graph(graphcount)->setData(xd, yd); + typeStrings.insert(graphcount, QString("Duplicate Ack")); + } +} + +void SCTPGraphDialog::drawTSNGraph() +{ + GList *listTSN = NULL,*tlist; + tsn_t *tsn; + guint8 type; + guint32 tsnumber=0; + guint32 minTSN; + + if (direction == 1) { + minTSN = selected_assoc->min_tsn1; + listTSN = g_list_last(selected_assoc->tsn1); + } else { + minTSN = selected_assoc->min_tsn2; + listTSN = g_list_last(selected_assoc->tsn2); + } + + + while (listTSN) { + tsn = (tsn_t*) (listTSN->data); + tlist = g_list_first(tsn->tsns); + while (tlist) + { + type = ((struct chunk_header *)tlist->data)->type; + if (type == SCTP_DATA_CHUNK_ID || type == SCTP_FORWARD_TSN_CHUNK_ID) { + tsnumber = g_ntohl(((struct data_chunk_header *)tlist->data)->tsn); + yt.append(tsnumber); + xt.append(tsn->secs + tsn->usecs/1000000.0); + ft.append(tsn->frame_number); + } + tlist = g_list_next(tlist); + } + listTSN = g_list_previous(listTSN); + } + + QCPScatterStyle myScatter; + myScatter.setShape(QCPScatterStyle::ssCircle); + myScatter.setSize(3); + + int graphcount = ui->sctpPlot->graphCount(); + // create graph and assign data to it: + + // Add TSN graph + if (xt.size() > 0) { + ui->sctpPlot->addGraph(); + myScatter.setPen(QPen(Qt::black)); + myScatter.setBrush(Qt::black); + ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter); + ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone); + ui->sctpPlot->graph(graphcount)->setData(xt, yt); + typeStrings.insert(graphcount, QString("TSN")); + } +} + +void SCTPGraphDialog::drawGraph(int which) +{ + guint32 minTSN, maxTSN; + + gIsSackChunkPresent = false; + gIsNRSackChunkPresent = false; + + if (direction == 1) { + minTSN = selected_assoc->min_tsn1; + maxTSN = selected_assoc->max_tsn1; + } else { + minTSN = selected_assoc->min_tsn2; + maxTSN = selected_assoc->max_tsn2; + } + + switch (which) { + case 1: drawSACKGraph(); + drawNRSACKGraph(); + break; + case 2: drawTSNGraph(); + break; + case 3: drawTSNGraph(); + drawSACKGraph(); + drawNRSACKGraph(); + break; + default: drawTSNGraph(); + drawSACKGraph(); + drawNRSACKGraph(); + } + + // give the axes some labels: + ui->sctpPlot->xAxis->setLabel("time [secs]"); + ui->sctpPlot->yAxis->setLabel("TSNs"); + ui->sctpPlot->setInteractions(QCP::iRangeZoom | QCP::iRangeDrag | QCP::iSelectPlottables); + connect(ui->sctpPlot, SIGNAL(plottableClick(QCPAbstractPlottable*,QMouseEvent*)), this, SLOT(graphClicked(QCPAbstractPlottable*, QMouseEvent*))); + // set axes ranges, so we see all data: + QCPRange myXRange(0, (selected_assoc->max_secs+1)); + QCPRange myYRange(0, maxTSN); + ui->sctpPlot->xAxis->setRange(myXRange); + ui->sctpPlot->yAxis->setRange(myYRange); + ui->sctpPlot->replot(); +} + +void SCTPGraphDialog::on_pushButton_clicked() +{ + drawGraph(1); +} + +void SCTPGraphDialog::on_pushButton_2_clicked() +{ + drawGraph(2); +} + +void SCTPGraphDialog::on_pushButton_3_clicked() +{ + drawGraph(3); +} + +void SCTPGraphDialog::on_pushButton_4_clicked() +{ + ui->sctpPlot->xAxis->setRange(selected_assoc->min_secs+selected_assoc->min_usecs/1000000.0, selected_assoc->max_secs+selected_assoc->max_usecs/1000000.0); + if (direction == 1) { + ui->sctpPlot->yAxis->setRange(selected_assoc->min_tsn1, selected_assoc->max_tsn1); + } else { + ui->sctpPlot->yAxis->setRange(selected_assoc->min_tsn2, selected_assoc->max_tsn2); + } + ui->sctpPlot->replot(); +} + +void SCTPGraphDialog::graphClicked(QCPAbstractPlottable* plottable, QMouseEvent* event) +{ + if (plottable->name().contains("Graph", Qt::CaseInsensitive)) { + // double tsn = round(ui->sctpPlot->yAxis->pixelToCoord(event->pos().y())); + int index = yt.indexOf(round(ui->sctpPlot->yAxis->pixelToCoord(event->pos().y()))); + // double time = xt.at(index); + frame_num = ft.at(index); + if (cap_file_ && frame_num > 0) { + cf_goto_frame(cap_file_, frame_num); + } + } + int num = plottable->name().remove("Graph ",Qt::CaseInsensitive).toInt(); + ui->hintLabel->setText(QString("<small><i>%1: %2: %3 Time: %4 secs </i></small>") + .arg(plottable->name()) + .arg(typeStrings[num-1]) + .arg(round(ui->sctpPlot->yAxis->pixelToCoord(event->pos().y()))) + .arg(ui->sctpPlot->xAxis->pixelToCoord(event->pos().x()))); +} + +void SCTPGraphDialog::save_graph(QDialog *dlg, QCustomPlot *plot) +{ + QString file_name, extension; + QDir path(wsApp->lastOpenDir()); + QString pdf_filter = tr("Portable Document Format (*.pdf)"); + QString png_filter = tr("Portable Network Graphics (*.png)"); + QString bmp_filter = tr("Windows Bitmap (*.bmp)"); + // Gaze upon my beautiful graph with lossy artifacts! + QString jpeg_filter = tr("JPEG File Interchange Format (*.jpeg *.jpg)"); + QString filter = QString("%1;;%2;;%3;;%4") + .arg(pdf_filter) + .arg(png_filter) + .arg(bmp_filter) + .arg(jpeg_filter); + + file_name = QFileDialog::getSaveFileName(dlg, tr("Wireshark: Save Graph As..."), + path.canonicalPath(), filter, &extension); + + if (file_name.length() > 0) { + bool save_ok = false; + if (extension.compare(pdf_filter) == 0) { + save_ok = plot->savePdf(file_name); + } else if (extension.compare(png_filter) == 0) { + save_ok = plot->savePng(file_name); + } else if (extension.compare(bmp_filter) == 0) { + save_ok = plot->saveBmp(file_name); + } else if (extension.compare(jpeg_filter) == 0) { + save_ok = plot->saveJpg(file_name); + } + // else error dialog? + if (save_ok) { + path = QDir(file_name); + wsApp->setLastOpenDir(path.canonicalPath().toUtf8().constData()); + } + } +} + + +void SCTPGraphDialog::on_saveButton_clicked() +{ + save_graph(this, ui->sctpPlot); +} |