Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / sctp_graph_dialog.cpp
blob342498c1a587602b1d05dfa22b44be37e1c94976
1 /* sctp_graph_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include <wsutil/utf8_entities.h>
12 #include "sctp_graph_dialog.h"
13 #include <ui_sctp_graph_dialog.h>
14 #include "sctp_assoc_analyse_dialog.h"
16 #include <file.h>
17 #include <math.h>
18 #include <epan/dissectors/packet-sctp.h>
19 #include "epan/packet.h"
21 #include "ui/tap-sctp-analysis.h"
23 #include <QMessageBox>
25 #include <ui/qt/utils/qt_ui_utils.h>
26 #include <ui/qt/widgets/qcustomplot.h>
27 #include "ui/qt/widgets/wireshark_file_dialog.h"
28 #include "main_application.h"
30 SCTPGraphDialog::SCTPGraphDialog(QWidget *parent, const sctp_assoc_info_t *assoc,
31 capture_file *cf, int dir) :
32 QDialog(parent),
33 ui(new Ui::SCTPGraphDialog),
34 cap_file_(cf),
35 frame_num(0),
36 direction(dir),
37 relative(false),
38 type(1)
40 Q_ASSERT(assoc);
41 selected_assoc_id = assoc->assoc_id;
43 ui->setupUi(this);
44 Qt::WindowFlags flags = Qt::Window | Qt::WindowSystemMenuHint
45 | Qt::WindowMinimizeButtonHint
46 | Qt::WindowMaximizeButtonHint
47 | Qt::WindowCloseButtonHint;
48 this->setWindowFlags(flags);
49 this->setWindowTitle(tr("SCTP TSNs and SACKs over Time: %1 Port1 %2 Port2 %3")
50 .arg(gchar_free_to_qstring(cf_get_display_name(cap_file_))).arg(assoc->port1).arg(assoc->port2));
51 if ((direction == 1 && assoc->n_array_tsn1 == 0) || (direction == 2 && assoc->n_array_tsn2 == 0)) {
52 QMessageBox msgBox;
53 msgBox.setText(tr("No Data Chunks sent"));
54 msgBox.exec();
55 return;
56 } else {
57 drawGraph(assoc);
61 SCTPGraphDialog::~SCTPGraphDialog()
63 delete ui;
66 void SCTPGraphDialog::drawNRSACKGraph(const sctp_assoc_info_t* selected_assoc)
68 tsn_t *sack = Q_NULLPTR;
69 GList *list = Q_NULLPTR, *tlist = Q_NULLPTR;
70 uint16_t gap_start=0, gap_end=0, i, numberOf_gaps, numberOf_nr_gaps;
71 uint8_t type;
72 uint32_t tsnumber, j = 0, min_tsn, rel = 0;
73 struct nr_sack_chunk_header *nr_sack_header = Q_NULLPTR;
74 struct gaps *nr_gap = Q_NULLPTR;
75 /* This holds the sum of gap acks and nr gap acks */
76 uint16_t total_gaps = 0;
78 if (direction == 1) {
79 list = g_list_last(selected_assoc->sack1);
80 min_tsn = selected_assoc->min_tsn1;
81 } else {
82 list = g_list_last(selected_assoc->sack2);
83 min_tsn = selected_assoc->min_tsn2;
85 if (relative) {
86 rel = min_tsn;
88 while (list) {
89 sack = gxx_list_data(tsn_t*, list);
90 tlist = g_list_first(sack->tsns);
91 while (tlist) {
92 type = gxx_list_data(struct chunk_header *, tlist)->type;
93 if (type == SCTP_NR_SACK_CHUNK_ID) {
94 nr_sack_header = gxx_list_data(struct nr_sack_chunk_header *, tlist);
95 numberOf_nr_gaps=g_ntohs(nr_sack_header->nr_of_nr_gaps);
96 numberOf_gaps=g_ntohs(nr_sack_header->nr_of_gaps);
97 tsnumber = g_ntohl(nr_sack_header->cum_tsn_ack);
98 total_gaps = numberOf_gaps + numberOf_nr_gaps;
99 /* If the number of nr_gaps is greater than 0 */
100 if (total_gaps > 0) {
101 nr_gap = &nr_sack_header->gaps[0];
102 for (i = 0; i < total_gaps; i++) {
103 gap_start = g_ntohs(nr_gap->start);
104 gap_end = g_ntohs(nr_gap->end);
105 for (j = gap_start; j <= gap_end; j++) {
106 if (i >= numberOf_gaps) {
107 yn.append(j + tsnumber - rel);
108 xn.append(sack->secs + sack->usecs/1000000.0);
109 fn.append(sack->frame_number);
110 } else {
111 yg.append(j + tsnumber - rel);
112 xg.append(sack->secs + sack->usecs/1000000.0);
113 fg.append(sack->frame_number);
116 if (i < total_gaps-1)
117 nr_gap++;
120 if (tsnumber>=min_tsn) {
121 ys.append(j + tsnumber - rel);
122 xs.append(sack->secs + sack->usecs/1000000.0);
123 fs.append(sack->frame_number);
127 tlist = gxx_list_next(tlist);
129 list = gxx_list_previous(list);
133 void SCTPGraphDialog::drawSACKGraph(const sctp_assoc_info_t* selected_assoc)
135 GList *listSACK = Q_NULLPTR, *tlist = Q_NULLPTR;
136 uint16_t gap_start=0, gap_end=0, nr, dup_nr;
137 struct sack_chunk_header *sack_header = Q_NULLPTR;
138 struct gaps *gap = Q_NULLPTR;
139 tsn_t *tsn = Q_NULLPTR;
140 uint8_t type;
141 uint32_t tsnumber=0, rel = 0;
142 uint32_t minTSN;
143 uint32_t *dup_list = Q_NULLPTR;
144 int i, j;
146 if (direction == 1) {
147 minTSN = selected_assoc->min_tsn1;
148 listSACK = g_list_last(selected_assoc->sack1);
149 } else {
150 minTSN = selected_assoc->min_tsn2;
151 listSACK = g_list_last(selected_assoc->sack2);
153 if (relative) {
154 rel = minTSN;
156 while (listSACK) {
157 tsn = gxx_list_data(tsn_t*, listSACK);
158 tlist = g_list_first(tsn->tsns);
159 while (tlist) {
160 type = gxx_list_data(struct chunk_header *, tlist)->type;
161 if (type == SCTP_SACK_CHUNK_ID) {
162 sack_header = gxx_list_data(struct sack_chunk_header *, tlist);
163 nr=g_ntohs(sack_header->nr_of_gaps);
164 tsnumber = g_ntohl(sack_header->cum_tsn_ack);
165 dup_nr=g_ntohs(sack_header->nr_of_dups);
166 if (nr>0) { // Gap Reports green
167 gap = &sack_header->gaps[0];
168 for (i=0;i<nr; i++) {
169 gap_start=g_ntohs(gap->start);
170 gap_end = g_ntohs(gap->end);
171 for (j=gap_start; j<=gap_end; j++) {
172 yg.append(j + tsnumber - rel);
173 xg.append(tsn->secs + tsn->usecs/1000000.0);
174 fg.append(tsn->frame_number);
176 if (i < nr-1)
177 gap++;
180 if (tsnumber>=minTSN) { // CumTSNAck red
181 ys.append(tsnumber - rel);
182 xs.append(tsn->secs + tsn->usecs/1000000.0);
183 fs.append(tsn->frame_number);
185 if (dup_nr > 0) { // Duplicates cyan
186 dup_list = &sack_header->a_rwnd + 2 + nr;
187 for (i = 0; i < dup_nr; i++) {
188 tsnumber = g_ntohl(dup_list[i]);
189 if (tsnumber >= minTSN) {
190 yd.append(tsnumber - rel);
191 xd.append(tsn->secs + tsn->usecs/1000000.0);
192 fd.append(tsn->frame_number);
197 tlist = gxx_list_next(tlist);
199 listSACK = gxx_list_previous(listSACK);
202 QCPScatterStyle myScatter;
203 myScatter.setShape(QCPScatterStyle::ssCircle);
204 myScatter.setSize(3);
206 int graphcount = ui->sctpPlot->graphCount();
207 // create graph and assign data to it:
209 // Add SACK graph
210 if (xs.size() > 0) {
211 QCPGraph *gr = ui->sctpPlot->addGraph();
212 gr->setName(QStringLiteral("SACK"));
213 myScatter.setPen(QPen(Qt::red));
214 myScatter.setBrush(Qt::red);
215 ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter);
216 ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone);
217 ui->sctpPlot->graph(graphcount)->setData(xs, ys);
218 typeStrings.insert(graphcount, tr("CumTSNAck"));
219 graphcount++;
222 // Add Gap Acks
223 if (xg.size() > 0) {
224 QCPGraph *gr = ui->sctpPlot->addGraph();
225 gr->setName(QStringLiteral("GAP"));
226 myScatter.setPen(QPen(Qt::green));
227 myScatter.setBrush(Qt::green);
228 ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter);
229 ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone);
230 ui->sctpPlot->graph(graphcount)->setData(xg, yg);
231 typeStrings.insert(graphcount, tr("Gap Ack"));
232 graphcount++;
235 // Add NR Gap Acks
236 if (xn.size() > 0) {
237 QCPGraph *gr = ui->sctpPlot->addGraph();
238 gr->setName(QStringLiteral("NR_GAP"));
239 myScatter.setPen(QPen(Qt::blue));
240 myScatter.setBrush(Qt::blue);
241 ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter);
242 ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone);
243 ui->sctpPlot->graph(graphcount)->setData(xn, yn);
244 typeStrings.insert(graphcount, tr("NR Gap Ack"));
245 graphcount++;
248 // Add Duplicates
249 if (xd.size() > 0) {
250 QCPGraph *gr = ui->sctpPlot->addGraph();
251 gr->setName(QStringLiteral("DUP"));
252 myScatter.setPen(QPen(Qt::cyan));
253 myScatter.setBrush(Qt::cyan);
254 ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter);
255 ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone);
256 ui->sctpPlot->graph(graphcount)->setData(xd, yd);
257 typeStrings.insert(graphcount, tr("Duplicate Ack"));
261 void SCTPGraphDialog::drawTSNGraph(const sctp_assoc_info_t* selected_assoc)
263 GList *listTSN = Q_NULLPTR,*tlist = Q_NULLPTR;
264 tsn_t *tsn = Q_NULLPTR;
265 uint8_t type;
266 uint32_t tsnumber=0, rel = 0, minTSN;
268 if (direction == 1) {
269 listTSN = g_list_last(selected_assoc->tsn1);
270 minTSN = selected_assoc->min_tsn1;
271 } else {
272 listTSN = g_list_last(selected_assoc->tsn2);
273 minTSN = selected_assoc->min_tsn2;
276 if (relative) {
277 rel = minTSN;
280 while (listTSN) {
281 tsn = gxx_list_data(tsn_t*, listTSN);
282 tlist = g_list_first(tsn->tsns);
283 while (tlist)
285 type = gxx_list_data(struct chunk_header *, tlist)->type;
286 if (type == SCTP_DATA_CHUNK_ID || type == SCTP_I_DATA_CHUNK_ID || type == SCTP_FORWARD_TSN_CHUNK_ID) {
287 tsnumber = g_ntohl(gxx_list_data(struct data_chunk_header *, tlist)->tsn);
288 yt.append(tsnumber - rel);
289 xt.append(tsn->secs + tsn->usecs/1000000.0);
290 ft.append(tsn->frame_number);
292 tlist = gxx_list_next(tlist);
294 listTSN = gxx_list_previous(listTSN);
297 QCPScatterStyle myScatter;
298 myScatter.setShape(QCPScatterStyle::ssCircle);
299 myScatter.setSize(3);
301 int graphcount = ui->sctpPlot->graphCount();
302 // create graph and assign data to it:
304 // Add TSN graph
305 if (xt.size() > 0) {
306 QCPGraph *gr = ui->sctpPlot->addGraph();
307 gr->setName(QStringLiteral("TSN"));
308 myScatter.setPen(QPen(Qt::black));
309 myScatter.setBrush(Qt::black);
310 ui->sctpPlot->graph(graphcount)->setScatterStyle(myScatter);
311 ui->sctpPlot->graph(graphcount)->setLineStyle(QCPGraph::lsNone);
312 ui->sctpPlot->graph(graphcount)->setData(xt, yt);
313 typeStrings.insert(graphcount, tr("TSN"));
317 void SCTPGraphDialog::drawGraph(const sctp_assoc_info_t* selected_assoc)
319 if (!selected_assoc) {
320 selected_assoc = SCTPAssocAnalyseDialog::findAssoc(this, selected_assoc_id);
321 if (!selected_assoc) return;
324 uint32_t maxTSN, minTSN;
326 if (direction == 1) {
327 maxTSN = selected_assoc->max_tsn1;
328 minTSN = selected_assoc->min_tsn1;
329 } else {
330 maxTSN = selected_assoc->max_tsn2;
331 minTSN = selected_assoc->min_tsn2;
333 ui->sctpPlot->clearGraphs();
334 xt.clear();
335 yt.clear();
336 xs.clear();
337 ys.clear();
338 xg.clear();
339 yg.clear();
340 xd.clear();
341 yd.clear();
342 xn.clear();
343 yn.clear();
344 ft.clear();
345 fs.clear();
346 fg.clear();
347 fd.clear();
348 fn.clear();
349 typeStrings.clear();
350 switch (type) {
351 case 1:
352 drawSACKGraph(selected_assoc);
353 drawNRSACKGraph(selected_assoc);
354 break;
355 case 2:
356 drawTSNGraph(selected_assoc);
357 break;
358 case 3:
359 drawTSNGraph(selected_assoc);
360 drawSACKGraph(selected_assoc);
361 drawNRSACKGraph(selected_assoc);
362 break;
363 default:
364 drawTSNGraph(selected_assoc);
365 drawSACKGraph(selected_assoc);
366 drawNRSACKGraph(selected_assoc);
367 break;
370 // give the axes some labels:
371 ui->sctpPlot->xAxis->setLabel(tr("time [secs]"));
372 ui->sctpPlot->yAxis->setLabel(tr("TSNs"));
373 ui->sctpPlot->setInteractions(QCP::iRangeZoom | QCP::iRangeDrag | QCP::iSelectPlottables);
374 connect(ui->sctpPlot, &QCustomPlot::plottableClick, this, &SCTPGraphDialog::graphClicked);
375 // set axes ranges, so we see all data:
376 QCPRange myXRange(selected_assoc->min_secs, (selected_assoc->max_secs+1));
377 if (relative) {
378 QCPRange myYRange(0, maxTSN - minTSN + 1);
379 ui->sctpPlot->yAxis->setRange(myYRange);
380 } else {
381 QCPRange myYRange(minTSN, maxTSN + 1);
382 ui->sctpPlot->yAxis->setRange(myYRange);
384 ui->sctpPlot->xAxis->setRange(myXRange);
385 ui->sctpPlot->replot();
388 void SCTPGraphDialog::on_pushButton_clicked()
390 type = 1;
391 drawGraph();
394 void SCTPGraphDialog::on_pushButton_2_clicked()
396 type = 2;
397 drawGraph();
400 void SCTPGraphDialog::on_pushButton_3_clicked()
402 type = 3;
403 drawGraph();
406 void SCTPGraphDialog::on_pushButton_4_clicked()
408 const sctp_assoc_info_t* selected_assoc = SCTPAssocAnalyseDialog::findAssoc(this, selected_assoc_id);
409 if (!selected_assoc) return;
411 ui->sctpPlot->xAxis->setRange(selected_assoc->min_secs, selected_assoc->max_secs+1);
412 if (relative) {
413 if (direction == 1) {
414 ui->sctpPlot->yAxis->setRange(0, selected_assoc->max_tsn1 - selected_assoc->min_tsn1);
415 } else {
416 ui->sctpPlot->yAxis->setRange(0, selected_assoc->max_tsn2 - selected_assoc->min_tsn2);
418 } else {
419 if (direction == 1) {
420 ui->sctpPlot->yAxis->setRange(selected_assoc->min_tsn1, selected_assoc->max_tsn1);
421 } else {
422 ui->sctpPlot->yAxis->setRange(selected_assoc->min_tsn2, selected_assoc->max_tsn2);
425 ui->sctpPlot->replot();
428 void SCTPGraphDialog::graphClicked(QCPAbstractPlottable* plottable, int, QMouseEvent* event)
430 frame_num = 0;
431 int i=0;
432 double times = ui->sctpPlot->xAxis->pixelToCoord(event->pos().x());
433 if (plottable->name().contains("TSN", Qt::CaseInsensitive)) {
434 for (i = 0; i < xt.size(); i++) {
435 if (times <= xt.value(i)) {
436 frame_num = ft.at(i);
437 break;
440 } else if (plottable->name().contains("SACK", Qt::CaseInsensitive)) {
441 for (i = 0; i < xs.size(); i++) {
442 if (times <= xs.value(i)) {
443 frame_num = fs.at(i);
444 break;
447 } else if (plottable->name().contains("DUP", Qt::CaseInsensitive)) {
448 for (i = 0; i < xd.size(); i++) {
449 if (times <= xd.value(i)) {
450 frame_num = fd.at(i);
451 break;
454 } else if (plottable->name().contains("NR_GAP", Qt::CaseInsensitive)) {
455 for (i = 0; i < xn.size(); i++) {
456 if (times <= xn.value(i)) {
457 frame_num = fn.at(i);
458 break;
461 } else if (plottable->name().contains("GAP", Qt::CaseInsensitive)) {
462 for (i = 0; i < xs.size(); i++) {
463 if (times <= xs.value(i)) {
464 frame_num = fs.at(i);
465 break;
469 if (cap_file_ && frame_num > 0) {
470 cf_goto_frame(cap_file_, frame_num, false);
472 ui->hintLabel->setText(tr("<small><i>%1: %2 Time: %3 secs </i></small>")
473 .arg(plottable->name())
474 .arg(floor(ui->sctpPlot->yAxis->pixelToCoord(event->pos().y()) + 0.5))
475 .arg(ui->sctpPlot->xAxis->pixelToCoord(event->pos().x())));
478 void SCTPGraphDialog::save_graph(QDialog *dlg, QCustomPlot *plot)
480 QString file_name, extension;
481 QDir path(mainApp->openDialogInitialDir());
482 QString pdf_filter = tr("Portable Document Format (*.pdf)");
483 QString png_filter = tr("Portable Network Graphics (*.png)");
484 QString bmp_filter = tr("Windows Bitmap (*.bmp)");
485 // Gaze upon my beautiful graph with lossy artifacts!
486 QString jpeg_filter = tr("JPEG File Interchange Format (*.jpeg *.jpg)");
487 QString filter = QStringLiteral("%1;;%2;;%3;;%4")
488 .arg(pdf_filter)
489 .arg(png_filter)
490 .arg(bmp_filter)
491 .arg(jpeg_filter);
493 file_name = WiresharkFileDialog::getSaveFileName(dlg, mainApp->windowTitleString(tr("Save Graph As…")),
494 path.canonicalPath(), filter, &extension);
496 if (file_name.length() > 0) {
497 bool save_ok = false;
498 if (extension.compare(pdf_filter) == 0) {
499 save_ok = plot->savePdf(file_name);
500 } else if (extension.compare(png_filter) == 0) {
501 save_ok = plot->savePng(file_name);
502 } else if (extension.compare(bmp_filter) == 0) {
503 save_ok = plot->saveBmp(file_name);
504 } else if (extension.compare(jpeg_filter) == 0) {
505 save_ok = plot->saveJpg(file_name);
507 // else error dialog?
508 if (save_ok) {
509 mainApp->setLastOpenDirFromFilename(file_name);
515 void SCTPGraphDialog::on_saveButton_clicked()
517 save_graph(this, ui->sctpPlot);
520 void SCTPGraphDialog::on_relativeTsn_stateChanged(int arg1)
522 relative = arg1;
523 drawGraph();