From 80ab2ff4401220b6e2b520d265b6c1fa931550ec Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Fri, 4 Nov 2022 23:32:19 +0100 Subject: [PATCH] charts data are updated every 1 second even if user interacts with GUI; restructured upper part of GUI run page --- Cargo.toml | 5 + src/app.rs | 6 +- src/charts_data.rs | 41 +++++++ src/gui_run_page.rs | 239 ++++++++++--------------------------- src/main.rs | 18 ++- src/style.rs | 1 + src/thread_write_report.rs | 72 ++++++++++- 7 files changed, 194 insertions(+), 188 deletions(-) create mode 100644 src/charts_data.rs diff --git a/Cargo.toml b/Cargo.toml index ec4f0f8a..922f2ae3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/app.rs b/src/app.rs index 491af84e..afd0bd35 100644 --- a/src/app.rs +++ b/src/app.rs @@ -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, diff --git a/src/charts_data.rs b/src/charts_data.rs new file mode 100644 index 00000000..06e19643 --- /dev/null +++ b/src/charts_data.rs @@ -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 + } + } + +} \ No newline at end of file diff --git a/src/gui_run_page.rs b/src/gui_run_page.rs index 1700d408..52b5676c 100644 --- a/src/gui_run_page.rs +++ b/src/gui_run_page.rs @@ -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 { @@ -123,25 +124,29 @@ pub fn run_page(sniffer: &mut Sniffer) -> Column { (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 { .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 { .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 { pub struct TrafficChart { info_traffic: Arc>, - sent_bits: VecDeque<(u128, i128)>, - received_bits: VecDeque<(u128, i128)>, - sent_packets: VecDeque<(u128, i128)>, - received_packets: VecDeque<(u128, i128)>, + charts_data: Arc>, 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>) -> Self { + pub fn new(info_traffic: Arc>, charts_data: Arc>) -> 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 { - 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 for TrafficChart { fn build_chart(&self, mut chart: ChartBuilder) { 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 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"); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c21a893e..54275df8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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>, info_traffic: Arc>, + charts_data: Arc>, device: Arc>, filters: Arc>, status_pair: Arc<(Mutex, Condvar)>, @@ -41,10 +44,11 @@ pub struct Sniffer { git: button::State, app: pick_list::State, 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, diff --git a/src/style.rs b/src/style.rs index b4461ef8..fbe493bc 100644 --- a/src/style.rs +++ b/src/style.rs @@ -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)] diff --git a/src/thread_write_report.rs b/src/thread_write_report.rs index 876f9e3c..cdfbbf8f 100644 --- a/src/thread_write_report.rs +++ b/src/thread_write_report.rs @@ -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>, lowest_port: u16, highest_port: u16, interval: u64, device: Arc>, filters: Arc>, output_folder: String, info_traffic_mutex: Arc>, - status_pair: Arc<(Mutex, Condvar)>) { + status_pair: Arc<(Mutex, Condvar)>, + charts_data: Arc>) { let cvar = &status_pair.1; @@ -134,6 +135,9 @@ pub fn sleep_and_write_report_loop(current_capture_id: Arc>, 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>, 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 } \ No newline at end of file