charts data are updated every 1 second even if user interacts with GUI; restructured upper part of GUI run page

This commit is contained in:
Giuliano Bellini s294739 2022-11-04 23:32:19 +01:00
parent 896e631249
commit 80ab2ff440
7 changed files with 194 additions and 188 deletions

View file

@ -9,9 +9,14 @@ keywords = ["filter", "network", "packet", "sniffer", "parser"]
categories = ["command-line-utilities", "concurrency", "network-programming"]
license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
#[profile.release]
#lto = true
[package.metadata.bundle]
name = "Sniffnet"
identifier = "gyulyvgc.sniffnet"

View file

@ -1,5 +1,5 @@
use std::thread;
use crate::{InfoTraffic, parse_packets_loop, Sniffer, Status, TrafficChart};
use crate::{ChartsData, InfoTraffic, parse_packets_loop, Sniffer, Status, TrafficChart};
use iced::{executor, Application, Column, Command, Container, Element, Length, Subscription};
use std::time::Duration;
use pcap::Device;
@ -117,8 +117,10 @@ impl Application for Sniffer {
let filters = self.filters.clone();
let info_traffic_mutex = self.info_traffic.clone();
*info_traffic_mutex.lock().unwrap() = InfoTraffic::new();
let charts_data_mutex = self.charts_data.clone();
*charts_data_mutex.lock().unwrap() = ChartsData::new();
*self.status_pair.0.lock().unwrap() = Status::Running;
self.traffic_chart = TrafficChart::new(info_traffic_mutex.clone());
self.traffic_chart = TrafficChart::new(info_traffic_mutex.clone(), charts_data_mutex.clone());
self.status_pair.1.notify_all();
thread::spawn(move || {
parse_packets_loop(current_capture_id, device,

41
src/charts_data.rs Normal file
View file

@ -0,0 +1,41 @@
use std::collections::VecDeque;
pub struct ChartsData {
pub sent_bits: VecDeque<(u128, i128)>,
pub received_bits: VecDeque<(u128, i128)>,
pub sent_packets: VecDeque<(u128, i128)>,
pub received_packets: VecDeque<(u128, i128)>,
pub tot_sent_bits_prev: i128,
pub tot_received_bits_prev: i128,
pub tot_sent_packets_prev: i128,
pub tot_received_packets_prev: i128,
pub min_sent_bits: i128,
pub max_received_bits: i128,
pub min_sent_packets: i128,
pub max_received_packets: i128,
pub ticks: u128
}
impl ChartsData {
/// Constructs a new ChartsData element.
pub fn new () -> Self {
ChartsData {
sent_bits: Default::default(),
received_bits: Default::default(),
sent_packets: Default::default(),
received_packets: Default::default(),
tot_sent_bits_prev: 0,
tot_received_bits_prev: 0,
tot_sent_packets_prev: 0,
tot_received_packets_prev: 0,
min_sent_bits: 0,
max_received_bits: 0,
min_sent_packets: 0,
max_received_packets: 0,
ticks: 0
}
}
}

View file

@ -1,15 +1,16 @@
use std::cmp::{max, min};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use iced::{alignment, Alignment, Button, Column, Container, Element, Length, Radio, Row, Text};
use iced::{alignment, Alignment, Button, Column, Container, Element, Length, Radio, Row, Scrollable, Text};
use iced::alignment::{Horizontal, Vertical};
use iced::Length::FillPortion;
use plotters::prelude::IntoFont;
use plotters::style::RGBColor;
use thousands::Separable;
use crate::app::Message;
use crate::{FONT_SIZE_TITLE, get_app_count_string, icon_sun_moon, InfoTraffic, Mode, Sniffer};
use crate::{ChartsData, FONT_SIZE_TITLE, get_app_count_string, icon_sun_moon, InfoTraffic, Mode, Sniffer};
use crate::address_port_pair::AddressPortPair;
use crate::info_address_port_pair::InfoAddressPortPair;
use crate::style::{COLOR_CHART_MIX_DAY, COLOR_CHART_MIX_NIGHT, COURIER_PRIME, COURIER_PRIME_BOLD, COURIER_PRIME_BOLD_ITALIC, COURIER_PRIME_ITALIC, FONT_SIZE_FOOTER, HEIGHT_BODY, HEIGHT_FOOTER, HEIGHT_HEADER, icon, logo_glyph, SPECIAL_DAY_RGB, SPECIAL_NIGHT_RGB};
use crate::style::{CHARTS_LINE_BORDER, COLOR_CHART_MIX_DAY, COLOR_CHART_MIX_NIGHT, COURIER_PRIME, COURIER_PRIME_BOLD, COURIER_PRIME_BOLD_ITALIC, COURIER_PRIME_ITALIC, FONT_SIZE_FOOTER, HEIGHT_BODY, HEIGHT_FOOTER, HEIGHT_HEADER, icon, logo_glyph, SPECIAL_DAY_RGB, SPECIAL_NIGHT_RGB};
use plotters_iced::{Chart, ChartWidget, DrawingBackend, ChartBuilder};
pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
@ -123,25 +124,29 @@ pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
(observed, filtered) => { //observed > filtered > 0 || observed = filtered > 0
let active_radio_chart = if sniffer.chart_packets { "packets" } else { "bits" };
let row_radio_chart = Row::new().spacing(10)
.push(Radio::new(
"bits",
"bits per second",
Some(active_radio_chart),
|what_to_display| Message::ChartSelection(what_to_display.to_string()),
).width(Length::Fill).font(font).size(15).style(sniffer.style))
let row_radio_chart = Row::new().padding(10).spacing(10)
.push(Column::new().width(Length::FillPortion(1)))
.push(Radio::new(
"packets",
"packets per second",
Some(active_radio_chart),
|what_to_display| Message::ChartSelection(what_to_display.to_string()),
).width(Length::Fill).font(font).size(15).style(sniffer.style));
).width(Length::FillPortion(2)).font(font).size(15).style(sniffer.style))
.push(Radio::new(
"bits",
"bits per second",
Some(active_radio_chart),
|what_to_display| Message::ChartSelection(what_to_display.to_string()),
).width(Length::FillPortion(2)).font(font).size(15).style(sniffer.style))
.push(Column::new().width(Length::FillPortion(1)));
let col_chart = Container::new(sniffer.traffic_chart.view(sniffer.style, sniffer.chart_packets))
let col_chart = Container::new(
Column::new()
.push(row_radio_chart)
.push(sniffer.traffic_chart.view(sniffer.style, sniffer.chart_packets)))
.width(Length::FillPortion(2))
.align_x(Horizontal::Center)
.align_y(Vertical::Center)
.padding(10)
.style(Mode::BorderedRound);
sniffer_lock = sniffer.info_traffic.lock().unwrap();
@ -149,11 +154,13 @@ pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
.width(Length::FillPortion(1))
.padding(10)
.spacing(15)
.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()).font(font))
.push(Text::new(format!("Total intercepted packets: {}",
observed.separate_with_spaces())).font(font))
.push(Text::new(format!("Filtered packets: {}",
filtered.separate_with_spaces())).font(font));
.push(Scrollable::new(&mut sniffer.scroll_packets)
.push(iced::Text::new(std::env::current_dir().unwrap().to_str().unwrap()).font(font))
.push(Text::new(format!("Total intercepted packets: {}",
observed.separate_with_spaces())).font(font))
.push(Text::new(format!("Filtered packets: {}",
filtered.separate_with_spaces())).font(font))
);
col_packets = col_packets
.push(iced::Text::new(format!("Filtered packets per application protocol:\n{}",get_app_count_string(sniffer_lock.app_protocols.clone(), filtered))).font(font));
@ -185,10 +192,9 @@ pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
.push(col_open_report);
body = body
.push(row_radio_chart)
.push(Row::new().height(Length::FillPortion(3))
.push(Row::new().spacing(10).height(Length::FillPortion(3))
.push(col_chart)
.push(col_packets))
.push(Container::new(col_packets).padding(10).height(Length::Fill).style(Mode::BorderedRound)))
.push(row_report);
}
}
@ -225,153 +231,62 @@ pub fn run_page(sniffer: &mut Sniffer) -> Column<Message> {
pub struct TrafficChart {
info_traffic: Arc<Mutex<InfoTraffic>>,
sent_bits: VecDeque<(u128, i128)>,
received_bits: VecDeque<(u128, i128)>,
sent_packets: VecDeque<(u128, i128)>,
received_packets: VecDeque<(u128, i128)>,
charts_data: Arc<Mutex<ChartsData>>,
color_mix: f64,
font_color: RGBColor,
chart_packets: bool,
tot_sent_bits_prev: i128,
tot_received_bits_prev: i128,
tot_sent_packets_prev: i128,
tot_received_packets_prev: i128,
min_sent_bits: i128,
max_received_bits: i128,
min_sent_packets: i128,
max_received_packets: i128,
tick: u128
}
impl TrafficChart {
pub fn new(info_traffic: Arc<Mutex<InfoTraffic>>) -> Self {
pub fn new(info_traffic: Arc<Mutex<InfoTraffic>>, charts_data: Arc<Mutex<ChartsData>>) -> Self {
TrafficChart {
info_traffic,
sent_bits: Default::default(),
received_bits: Default::default(),
sent_packets: Default::default(),
received_packets: Default::default(),
charts_data,
color_mix: 0.0,
font_color: Default::default(),
chart_packets: true,
tot_sent_bits_prev: 0,
tot_received_bits_prev: 0,
tot_sent_packets_prev: 0,
tot_received_packets_prev: 0,
min_sent_bits: 0,
max_received_bits: 0,
min_sent_packets: 0,
max_received_packets: 0,
tick: 0
}
}
fn view(&mut self, mode: Mode, chart_packets: bool) -> Element<Message> {
let info_traffic_lock = self.info_traffic.lock().unwrap();
let tot_received_bytes = info_traffic_lock.tot_received_bytes;
let tot_sent_bytes = info_traffic_lock.tot_sent_bytes;
let tot_received_packets = info_traffic_lock.tot_received_packets;
let tot_sent_packets = info_traffic_lock.tot_sent_packets;
drop(info_traffic_lock);
let tot_seconds = self.tick;
let interval = 1;
self.tick += 1;
self.color_mix = if mode == Mode::Day {COLOR_CHART_MIX_DAY} else { COLOR_CHART_MIX_NIGHT };
self.chart_packets = chart_packets;
// update sent bits traffic data
if self.sent_bits.len() >= 30 {
self.sent_bits.pop_front();
}
self.sent_bits.push_back((tot_seconds as u128, (-1 * (tot_sent_bytes * 8) as i128 + self.tot_sent_bits_prev) / interval as i128));
self.min_sent_bits = get_min(self.sent_bits.clone());
self.tot_sent_bits_prev = (tot_sent_bytes * 8) as i128;
// update received bits traffic data
if self.received_bits.len() >= 30 {
self.received_bits.pop_front();
}
self.received_bits.push_back((tot_seconds as u128, (tot_received_bytes as i128 * 8 - self.tot_received_bits_prev) / interval as i128));
self.max_received_bits = get_max(self.received_bits.clone());
self.tot_received_bits_prev = (tot_received_bytes * 8) as i128;
// // update packets traffic data
// self.sent_packets.push((tot_seconds as u128, (-(tot_sent_packets as i128) + tot_sent_packets_prev) / interval as i128));
// tot_sent_packets_prev = tot_sent_packets as i128;
// self.received_packets.push((tot_seconds as u128, (tot_received_packets as i128 - tot_received_packets_prev) / interval as i128));
// tot_received_packets_prev = tot_received_packets as i128;
// update sent packets traffic data
if self.sent_packets.len() >= 30 {
self.sent_packets.pop_front();
}
self.sent_packets.push_back((tot_seconds as u128, (-1 * tot_sent_packets as i128 + self.tot_sent_packets_prev) / interval as i128));
self.min_sent_packets = get_min(self.sent_packets.clone());
self.tot_sent_packets_prev = tot_sent_packets as i128;
// update received bits traffic data
if self.received_packets.len() >= 30 {
self.received_packets.pop_front();
}
self.received_packets.push_back((tot_seconds as u128, (tot_received_packets as i128 - self.tot_received_packets_prev) / interval as i128));
self.max_received_packets = get_max(self.received_packets.clone());
self.tot_received_packets_prev = tot_received_packets as i128;
self.font_color = if mode == Mode::Day { plotters::style::colors::BLACK } else { plotters::style::colors::WHITE };
Container::new(
Column::new()
.spacing(5)
.push(
ChartWidget::new(self)//.height(Length::Fill)
),
)
.align_x(Horizontal::Center)
.align_y(Vertical::Center)
.push(ChartWidget::new(self)))
.align_x(Horizontal::Left)
.align_y(Vertical::Bottom)
.into()
}
}
fn get_min(deque: VecDeque<(u128, i128)>) -> i128 {
let mut min = 0;
for (_, x) in deque.iter() {
if *x < min {
min = *x;
}
}
min
}
fn get_max(deque: VecDeque<(u128, i128)>) -> i128 {
let mut max = 0;
for (_, x) in deque.iter() {
if *x > max {
max = *x;
}
}
max
}
impl Chart<Message> for TrafficChart {
fn build_chart<DB: DrawingBackend>(&self, mut chart: ChartBuilder<DB>) {
use plotters::{prelude::*, style::Color};
let interval = 1;
let tot_seconds = self.tick - 1;
let first_time_displayed = max(0, self.tick as i128 - 30) as u128;
let charts_data_lock = self.charts_data.lock().unwrap();
if charts_data_lock.ticks == 0 {
return
}
let tot_seconds = charts_data_lock.ticks - 1;
let first_time_displayed = max(0, charts_data_lock.ticks as i128 - 30) as u128;
match self.chart_packets {
false => { //display bits chart
let mut chart = chart
let mut chart = chart.margin_right(30)
.set_label_area_size(LabelAreaPosition::Left, 60)
.set_label_area_size(LabelAreaPosition::Bottom, 50)
.build_cartesian_2d(first_time_displayed..tot_seconds as u128, self.min_sent_bits / interval as i128..self.max_received_bits / interval as i128)
.build_cartesian_2d(first_time_displayed..tot_seconds as u128, charts_data_lock.min_sent_bits..charts_data_lock.max_received_bits)
.expect("Error drawing graph");
chart.configure_mesh()
.label_style(("helvetica", 13))
.axis_desc_style(("helvetica", 13))
.label_style(("helvetica", 13).into_font().color(&self.font_color))
// .x_label_formatter(&|seconds| {
// (time_origin + chrono::Duration::from_std(Duration::from_secs(*seconds as u64)).unwrap())
// .format("%H:%M:%S").to_string()
@ -386,86 +301,52 @@ impl Chart<Message> for TrafficChart {
})
.draw().unwrap();
chart.draw_series(
AreaSeries::new(self.received_bits.iter().copied(), 0, SPECIAL_NIGHT_RGB.mix(self.color_mix))
.border_style(&SPECIAL_NIGHT_RGB))
AreaSeries::new(charts_data_lock.received_bits.iter().copied(), 0, SPECIAL_NIGHT_RGB.mix(self.color_mix))
.border_style(ShapeStyle::from(&SPECIAL_NIGHT_RGB).stroke_width(CHARTS_LINE_BORDER)))
.expect("Error drawing graph")
.label("Incoming bits")
.legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_NIGHT_RGB.filled()));
chart.draw_series(
AreaSeries::new(self.sent_bits.iter().copied(), 0, SPECIAL_DAY_RGB.mix(self.color_mix))
.border_style(&SPECIAL_DAY_RGB))
AreaSeries::new(charts_data_lock.sent_bits.iter().copied(), 0, SPECIAL_DAY_RGB.mix(self.color_mix))
.border_style(ShapeStyle::from(&SPECIAL_DAY_RGB).stroke_width(CHARTS_LINE_BORDER)))
.expect("Error drawing graph")
.label("Outgoing bits")
.legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_DAY_RGB.filled()));
chart.configure_series_labels().position(SeriesLabelPosition::UpperRight)//.margin(5)
.border_style(BLACK).label_font(("helvetica", 13)).draw().expect("Error drawing graph");
.border_style(BLACK).label_font(("helvetica", 13).into_font().color(&self.font_color)).draw().expect("Error drawing graph");
}
true => { //display packets chart
let mut chart = chart
let mut chart = chart.margin_right(30)
.set_label_area_size(LabelAreaPosition::Left, 60)
.set_label_area_size(LabelAreaPosition::Bottom, 50)
.build_cartesian_2d(first_time_displayed..tot_seconds as u128, self.min_sent_packets / interval as i128..self.max_received_packets / interval as i128)
.build_cartesian_2d(first_time_displayed..tot_seconds as u128, charts_data_lock.min_sent_packets..charts_data_lock.max_received_packets)
.expect("Error drawing graph");
chart.configure_mesh()
.label_style(("helvetica", 13))
.axis_desc_style(("helvetica", 13))
.label_style(("helvetica", 13).into_font().color(&self.font_color))
// .x_label_formatter(&|seconds| {
// (time_origin + chrono::Duration::from_std(Duration::from_secs(*seconds as u64)).unwrap())
// .format("%H:%M:%S").to_string()
// })
.draw().unwrap();
chart.draw_series(
AreaSeries::new(self.received_packets.iter().copied(), 0, SPECIAL_NIGHT_RGB.mix(self.color_mix))
.border_style(&SPECIAL_NIGHT_RGB))
AreaSeries::new(charts_data_lock.received_packets.iter().copied(), 0, SPECIAL_NIGHT_RGB.mix(self.color_mix))
.border_style(ShapeStyle::from(&SPECIAL_NIGHT_RGB).stroke_width(CHARTS_LINE_BORDER)))
.expect("Error drawing graph")
.label("Incoming packets")
.legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_NIGHT_RGB.filled()));
chart.draw_series(
AreaSeries::new(self.sent_packets.iter().copied(), 0, SPECIAL_DAY_RGB.mix(self.color_mix))
.border_style(&SPECIAL_DAY_RGB))
AreaSeries::new(charts_data_lock.sent_packets.iter().copied(), 0, SPECIAL_DAY_RGB.mix(self.color_mix))
.border_style(ShapeStyle::from(&SPECIAL_DAY_RGB).stroke_width(CHARTS_LINE_BORDER)))
.expect("Error drawing graph")
.label("Outgoing packets")
.legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], SPECIAL_DAY_RGB.filled()));
chart.configure_series_labels().position(SeriesLabelPosition::UpperRight)//.margin(5)
.border_style(BLACK).label_font(("helvetica", 13)).draw().expect("Error drawing graph");
.border_style(BLACK).label_font(("helvetica", 13).into_font().color(&self.font_color)).draw().expect("Error drawing graph");
}
}
// // packets graph
//
// let mut chart_packets = ChartBuilder::on(&packets_area)
// .set_label_area_size(LabelAreaPosition::Left, 60)
// .set_label_area_size(LabelAreaPosition::Bottom, 50)
// .caption("Packet traffic per second", ("helvetica", 30))
// .build_cartesian_2d(0..tot_seconds as u128, min_sent_packets_second / interval as i128..max_received_packets_second / interval as i128)
// .expect("Error drawing graph");
// chart_packets.configure_mesh()
// .y_desc("packet/s")
// .label_style(("helvetica", 16))
// .axis_desc_style(("helvetica", 16))
// .x_label_formatter(&|seconds| {
// (time_origin + chrono::Duration::from_std(Duration::from_secs(*seconds as u64)).unwrap())
// .format("%H:%M:%S").to_string()
// })
// .draw().unwrap();
// chart_packets.draw_series(
// AreaSeries::new(received_packets_graph.iter().copied(), 0, GREEN_800.mix(0.2))
// .border_style(&GREEN_800))
// .expect("Error drawing graph")
// .label("Incoming packets")
// .legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], GREEN_800.filled()));
// chart_packets.draw_series(
// AreaSeries::new(sent_packets_graph.iter().copied(), 0, BLUE.mix(0.2))
// .border_style(&BLUE))
// .expect("Error drawing graph")
// .label("Outgoing packets")
// .legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 25, y + 5)], BLUE.filled()));
// chart_packets.configure_series_labels().position(SeriesLabelPosition::UpperRight).margin(5)
// .border_style(BLACK).label_font(("helvetica", 16)).draw().expect("Error drawing graph");
}
}

View file

@ -7,6 +7,7 @@ mod style;
mod app;
mod gui_initial_page;
mod gui_run_page;
mod charts_data;
use pcap::{Device};
use crate::info_address_port_pair::{AppProtocol, TransProtocol};
@ -19,6 +20,7 @@ use std::sync::{Arc, Mutex, Condvar};
use iced::{Application, button, pick_list, scrollable, Settings, window};
use crate::info_traffic::InfoTraffic;
use style::{Mode, FONT_SIZE_BODY, FONT_SIZE_SUBTITLE, FONT_SIZE_TITLE, icon_sun_moon};
use crate::charts_data::ChartsData;
pub struct Filters {
@ -31,6 +33,7 @@ pub struct Filters {
pub struct Sniffer {
current_capture_id: Arc<Mutex<u16>>,
info_traffic: Arc<Mutex<InfoTraffic>>,
charts_data: Arc<Mutex<ChartsData>>,
device: Arc<Mutex<Device>>,
filters: Arc<Mutex<Filters>>,
status_pair: Arc<(Mutex<Status>, Condvar)>,
@ -41,10 +44,11 @@ pub struct Sniffer {
git: button::State,
app: pick_list::State<AppProtocol>,
scroll_adapters: scrollable::State,
scroll_packets: scrollable::State,
style: Mode,
waiting: String,
traffic_chart: TrafficChart,
chart_packets: bool
chart_packets: bool,
}
@ -72,6 +76,10 @@ pub fn main() -> iced::Result {
let mutex_map2 = mutex_map1.clone();
let mutex_map3 = mutex_map1.clone();
let charts_data1 = Arc::new(Mutex::new(ChartsData::new()));
let charts_data2 = charts_data1.clone();
let charts_data3 = charts_data1.clone();
//shared tuple containing the application status and the relative condition variable
let status_pair1 = Arc::new((Mutex::new(Status::Init), Condvar::new()));
let status_pair2 = status_pair1.clone();
@ -97,7 +105,7 @@ pub fn main() -> iced::Result {
thread::spawn(move || {
sleep_and_write_report_loop(current_capture_id2, 0, 65535, 1,
found_device2, filters2, "./sniffnet_report".to_string(),
mutex_map2, status_pair2);
mutex_map2, status_pair2, charts_data2);
});
Sniffer::run(Settings {
@ -116,6 +124,7 @@ pub fn main() -> iced::Result {
flags: Sniffer {
current_capture_id: current_capture_id1,
info_traffic: mutex_map1,
charts_data: charts_data1,
device: found_device1,
filters: filters1,
status_pair: status_pair1,
@ -126,10 +135,11 @@ pub fn main() -> iced::Result {
git: button::State::new(),
app: pick_list::State::new(),
scroll_adapters: scrollable::State::new(),
scroll_packets: scrollable::State::new(),
style: Mode::Night,
waiting: String::new(),
traffic_chart: TrafficChart::new(mutex_map3),
chart_packets: false
traffic_chart: TrafficChart::new(mutex_map3, charts_data3),
chart_packets: true
},
default_font: None,
default_text_size: FONT_SIZE_BODY,

View file

@ -62,6 +62,7 @@ pub const SPECIAL_DAY_RGB: RGBColor = RGBColor {0: 0, 1: 89, 2: 189};
pub const COLOR_CHART_MIX_DAY: f64 = 0.8;
pub const COLOR_CHART_MIX_NIGHT: f64 = 0.4;
pub const CHARTS_LINE_BORDER: u32 = 1;
#[derive(Copy, Eq, PartialEq)]

View file

@ -6,7 +6,7 @@
use std::cmp::Ordering;
use std::cmp::Ordering::Equal;
use std::collections::{HashMap, HashSet};
use std::collections::{HashMap, HashSet, VecDeque};
use std::fs::File;
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration};
@ -14,7 +14,7 @@ use std::{fs, thread};
use chrono::{Local};
use std::io::{BufWriter, Seek, SeekFrom, Write};
use thousands::Separable;
use crate::{AppProtocol, Filters, InfoTraffic, Status, TransProtocol};
use crate::{AppProtocol, ChartsData, Filters, InfoTraffic, Status, TransProtocol};
use pcap::Device;
@ -53,7 +53,8 @@ use pcap::Device;
pub fn sleep_and_write_report_loop(current_capture_id: Arc<Mutex<u16>>, lowest_port: u16, highest_port: u16, interval: u64,
device: Arc<Mutex<Device>>, filters: Arc<Mutex<Filters>>,
output_folder: String, info_traffic_mutex: Arc<Mutex<InfoTraffic>>,
status_pair: Arc<(Mutex<Status>, Condvar)>) {
status_pair: Arc<(Mutex<Status>, Condvar)>,
charts_data: Arc<Mutex<ChartsData>>) {
let cvar = &status_pair.1;
@ -134,6 +135,9 @@ pub fn sleep_and_write_report_loop(current_capture_id: Arc<Mutex<u16>>, lowest_p
let tot_sent_packets = info_traffic.tot_sent_packets;
let tot_received_packets = info_traffic.tot_received_packets;
let all_packets = info_traffic.all_packets;
let tot_received_bytes = info_traffic.tot_received_bytes;
let tot_sent_bytes = info_traffic.tot_sent_bytes;
let mut output2 = BufWriter::new(File::create(path_statistics.clone()).expect("Error creating output file\n\r"));
@ -168,6 +172,46 @@ pub fn sleep_and_write_report_loop(current_capture_id: Arc<Mutex<u16>>, lowest_p
drop(info_traffic);
let mut charts_data_lock = charts_data.lock().unwrap();
let tot_seconds = charts_data_lock.ticks;
charts_data_lock.ticks += 1;
let tot_sent_bits_prev = charts_data_lock.tot_sent_bits_prev;
let tot_received_bits_prev = charts_data_lock.tot_received_bits_prev;
let tot_sent_packets_prev = charts_data_lock.tot_sent_packets_prev;
let tot_received_packets_prev = charts_data_lock.tot_received_packets_prev;
// update sent bits traffic data
if charts_data_lock.sent_bits.len() >= 30 {
charts_data_lock.sent_bits.pop_front();
}
charts_data_lock.sent_bits.push_back((tot_seconds as u128, (-1 * (tot_sent_bytes * 8) as i128 + tot_sent_bits_prev)));
charts_data_lock.min_sent_bits = get_min(charts_data_lock.sent_bits.clone());
charts_data_lock.tot_sent_bits_prev = (tot_sent_bytes * 8) as i128;
// update received bits traffic data
if charts_data_lock.received_bits.len() >= 30 {
charts_data_lock.received_bits.pop_front();
}
charts_data_lock.received_bits.push_back((tot_seconds as u128, (tot_received_bytes as i128 * 8 - tot_received_bits_prev)));
charts_data_lock.max_received_bits = get_max(charts_data_lock.received_bits.clone());
charts_data_lock.tot_received_bits_prev = (tot_received_bytes * 8) as i128;
// update sent packets traffic data
if charts_data_lock.sent_packets.len() >= 30 {
charts_data_lock.sent_packets.pop_front();
}
charts_data_lock.sent_packets.push_back((tot_seconds as u128, (-1 * tot_sent_packets as i128 + tot_sent_packets_prev)));
charts_data_lock.min_sent_packets = get_min(charts_data_lock.sent_packets.clone());
charts_data_lock.tot_sent_packets_prev = tot_sent_packets as i128;
// update received bits traffic data
if charts_data_lock.received_packets.len() >= 30 {
charts_data_lock.received_packets.pop_front();
}
charts_data_lock.received_packets.push_back((tot_seconds as u128, (tot_received_packets as i128 - tot_received_packets_prev)));
charts_data_lock.max_received_packets = get_max(charts_data_lock.received_packets.clone());
charts_data_lock.tot_received_packets_prev = tot_received_packets as i128;
}
else if *status == Status::Stop {
return;
@ -428,4 +472,26 @@ fn write_statistics(mut output: File, device_name: String, first_timestamp: Stri
writeln!(output, "{}", app_count_string).expect("Error writing output file\n");
}
}
fn get_min(deque: VecDeque<(u128, i128)>) -> i128 {
let mut min = 0;
for (_, x) in deque.iter() {
if *x < min {
min = *x;
}
}
min
}
fn get_max(deque: VecDeque<(u128, i128)>) -> i128 {
let mut max = 0;
for (_, x) in deque.iter() {
if *x > max {
max = *x;
}
}
max
}