diff --git a/Cargo.toml b/Cargo.toml index ff9cd05..c1adc28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,4 @@ edition = "2024" env_logger = "0.11" log = "0.4" ansi_term = "0.12" -clap = { version = "4.5.36", features = ["derive"] } - - -[[bin]] -name = "threads" - +clap = { version = "4.5", features = ["derive"] } diff --git a/src/bin/threads.rs b/src/bin/threads.rs deleted file mode 100644 index bc11d51..0000000 --- a/src/bin/threads.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::net::Ipv4Addr; -use std::process::Command; -use std::sync::mpsc; -use std::sync::mpsc::Receiver; -use std::sync::mpsc::Sender; -use std::thread; -use std::time::{Duration, SystemTime}; - -const SECONDS_BETWEEN_DISPLAY: u32 = 5; -const SECONDS_BETWEEN_PING: u32 = 1; - -#[derive(Clone)] -struct PingRequest { - target: Ipv4Addr, -} - -#[derive(Clone)] -struct PingResult { - target: Ipv4Addr, - success: bool, - rtt: u32, -} - -fn spawn_manager_thread(targets: Vec, sender: Sender) { - let local_targets = targets.clone(); - thread::spawn(move || { - loop { - for target in &local_targets { - spawn_single_ping(PingRequest { target: *target }, sender.clone()); - } - thread::sleep(Duration::from_secs(SECONDS_BETWEEN_PING as u64)); - } - }); -} - -// Spawns a thread that pings a target and sends the response back to the main thread -// via the sender -fn spawn_single_ping(request: PingRequest, sender: Sender) { - let local_request = request.clone(); - thread::spawn(move || { - - let mut result = 0; - let mut success = true; - let start_time = SystemTime::now(); - #[cfg(any(target_os="windows"))] { - result = Command::new("c:/windows/system32/ping.exe").arg(request.target.to_string()) - .arg("-n 1") - .arg("-w 10") - .arg("-4") - .output().unwrap().status.code().unwrap_or(255); - success = result == 1; - } - #[cfg(any(target_os="linux"))] { - result = Command::new("/usr/bin/ping").arg(request.target.to_string()) - .arg("-c 1") - .arg("-4") - .arg("-w 10") - .arg("-W 1") - .output().unwrap().status.code().unwrap_or(255); - success = result == 0; - } - let ping_duration = SystemTime::now().duration_since(start_time).unwrap_or(Duration::from_secs(600)); - sender.send(PingResult { target: local_request.target, success: result == 0, rtt: ping_duration.as_millis() as u32 }).expect("Unable to send response"); - let success = ping_duration.as_millis() >= SECONDS_BETWEEN_PING as u128 && result == 0; - - // println!("Attempt for for {}", local_request.target); - }); -} - - -#[derive(Clone)] -struct TargetState { - target: Ipv4Addr, - alive: bool, - last_rtt: u32, -} - -impl Default for TargetState { - fn default() -> Self { - TargetState { - target: Ipv4Addr::new(127, 0, 0, 1), - alive: false, - last_rtt: 0, - } - } -} - -#[derive(Default)] -pub struct State { - targets: Vec, -} - -impl State { - pub fn add_target(&mut self, to_add: Ipv4Addr) { - self.targets.push(TargetState { - target: to_add, - ..TargetState::default() - }); - } - - pub fn targets_ipv4(&self) -> Vec { - let mut working = vec![]; - - for current in &self.targets { - working.push(current.target); - } - - working - } -} - - -fn main() { - // channel to send requests to ping - let (ping_response_sender, ping_response_listener) = mpsc::channel::(); - - println!("Taxation is Theft"); - - let targets = vec![Ipv4Addr::new(127, 0, 0, 1), - Ipv4Addr::new(172, 24, 10, 200), - Ipv4Addr::new(1,1,1,1)]; - let mut state = State::default(); - - for current in &targets { - state.add_target(*current); - } - - println!("Setting up requests for {} hosts.", targets.len()); - spawn_manager_thread(state.targets_ipv4().clone(), ping_response_sender.clone()); - - let mut display_loop_start = SystemTime::now(); - let mut duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).unwrap(); - loop { - if let Ok(response) = ping_response_listener.recv_timeout(Duration::from_millis(100)) { - // println!("Master got a ping response for {} with {}/{}", response.target, response.success, response.rtt); - for (index, current_state) in state.targets.clone().iter().enumerate() { - if current_state.target == response.target { - let new_state = TargetState { - target: current_state.target, - alive: response.success, - last_rtt: response.rtt, - }; - state.targets[index] = new_state.clone(); - // println!("({}) Found the target -> {}/{}/{}", state.targets.clone().len(), new_state.target, new_state.alive, new_state.last_rtt); - } - } - } - duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).expect("unable to figure out how long ago we displayed stuff"); - if duration_since_last_loop.as_secs() > SECONDS_BETWEEN_DISPLAY as u64 { - println!("DISPLAY LOOP"); - println!("------------"); - for current_result in state.targets.clone() { - println!("{} / {} -> {}", current_result.target, current_result.alive, current_result.last_rtt); - } - display_loop_start = SystemTime::now(); - } - } -} diff --git a/src/main.rs b/src/main.rs index 4e14319..18917c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,214 +1,77 @@ -use std::fs::File; use std::net::Ipv4Addr; -use std::path::{Path, PathBuf}; use std::process::Command; -use std::str::FromStr; -use std::string::ToString; use std::sync::mpsc; use std::sync::mpsc::Sender; -use std::{io, thread}; -use std::io::BufRead; +use std::thread; use std::time::{Duration, SystemTime}; -use ansi_term::Colour::{Green, Red}; -use clap::Parser; -use log::{debug, error, log_enabled, info, Level}; +use crate::manager::Manager; +use crate::ping_result::PingResult; +use crate::state::State; +use crate::target_state::TargetState; -#[derive(Clone)] -struct HistoricHost { - pub name: String, - pub address: Ipv4Addr, - pub history: Vec, - pub alive: bool, -} +mod manager; +mod state; +mod target_state; +mod ping_result; +mod ping_request; -#[derive(Clone, Debug)] -struct PingResult { - pub address: Ipv4Addr, - pub rtt: u128, -} - -impl HistoricHost { - pub fn dump_state(&self) { - let working_history = self.history.clone(); - if working_history.len() == 0 { - println!("No Results for {} yet.", self.name); - return; - } - - let num_results = working_history.len(); - let mut running_total = 0; - for result in working_history { - running_total += result; - } - let average_ping_time = running_total.div_ceil(num_results as u128); - println!("Counted {} results, total time {} with average {}", - num_results, running_total, average_ping_time - ); - } - - pub fn get_ping_time_for(target: Ipv4Addr) -> (i32, Duration) { - let start_time = SystemTime::now(); - let result = Command::new("/usr/bin/ping").arg(target.to_string()) - .arg("-c 1") - .arg("-4") - .arg("-w 10") - .arg("-W 1") - .output().unwrap().status.code().unwrap_or(255); - let ping_duration = SystemTime::now().duration_since(start_time).unwrap_or(Duration::from_secs(600)); - (result, ping_duration) - } - - pub fn get_ping_time(&self) -> (i32, Duration) { - HistoricHost::get_ping_time_for(self.address) - } - - pub fn ping(&mut self) { - let (result, ping_duration) = self.get_ping_time(); - match result { - 0 => { - self.history.push(ping_duration.as_millis()) - } - 1 => { - println!("Error ping to {}", self.name); - } - _ => { - println!("General Ping Error."); - } - } - } -} - -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -struct PPArgs { - pub targets: Option, -} - - -// The output is wrapped in a Result to allow matching on errors. -// Returns an Iterator to the Reader of the lines of the file. -fn read_lines

(filename: P) -> io::Result>> - where P: AsRef, { - let file = File::open(filename)?; - Ok(io::BufReader::new(file).lines()) -} +const SECONDS_BETWEEN_DISPLAY: u32 = 1; +const SECONDS_BETWEEN_PING: u32 = 2; fn main() { - env_logger::init(); + // channel to send requests to ping + let (ping_response_sender, ping_response_listener) = mpsc::channel::(); - let args = PPArgs::parse(); + println!("Taxation is Theft"); - let targets = match args.targets { - Some(file) => { - println!("Loading hosts from {}", file.to_str().unwrap_or("no file.")); - let mut working = vec![]; - if let Ok(lines) = read_lines(file) { - // Consumes the iterator, returns an (Optional) String - for line in lines.map_while(Result::ok) { - println!("{}", line); - working.push(line.to_string()) - } - } - working.to_vec() - } - None => { - println!("Default Hosts used."); - vec!["127.0.0.1".to_string(), "1.1.1.1".to_string(), "8.8.8.8".to_string()] - } - }; + let targets = vec![Ipv4Addr::new(127, 0, 0, 1), + Ipv4Addr::new(172, 24, 10, 137), + Ipv4Addr::new(1,1,1,1)]; + let mut state = State::default(); - let (sender, receiver) = mpsc::channel::(); - - // sender gets cloned and sent to each pinger - - let mut hosts = vec![]; - - info!("Building hosts list..."); - // build hosts list... - for target in targets { - hosts.push( - HistoricHost { - name: target.to_string(), - address: Ipv4Addr::from_str(&target).unwrap_or(Ipv4Addr::new(127, 0, 0, 1)), - history: vec![], - alive: false, - } - ) + for current in &targets { + state.add_target(*current); } - info!("Completed building with {} hosts.", hosts.len()); - info!("Starting Manager Thread"); - // Manager Thread - let my_hosts = hosts.clone(); - let _ = thread::spawn(move || { - loop { - println!("\x1b[2J --------------"); - for current_target in my_hosts.clone() { - // debug!("[MT] Preparing to send off ping request to {}", current_target.address.to_string()); - let start_time = SystemTime::now(); + println!("Setting up requests for {} hosts.", targets.len()); + Manager::spawn_manager_thread(state.targets_ipv4().clone(), ping_response_sender.clone()); - let result = Command::new("/usr/bin/ping").arg(current_target.address.to_string()) - .arg("-c 1") - .arg("-4") - .arg("-w 10") - .arg("-W 1") - .output().unwrap().status.code().unwrap_or(255); - let ping_duration = SystemTime::now().duration_since(start_time).unwrap_or(Duration::from_secs(600)); - let to_send = if result == 0 { - PingResult { address: current_target.address, rtt: ping_duration.as_millis() } - } else { - PingResult { address: current_target.address, rtt: u128::MAX } - }; - let my_sender = sender.clone(); - let _ = my_sender.send(to_send); - } - thread::sleep(Duration::from_secs(2)); - } - }); + let mut display_loop_start = SystemTime::now(); + let mut duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).unwrap(); + loop { + if let Ok(response) = ping_response_listener.recv_timeout(Duration::from_millis(100)) { + // println!("[MM] Master got a ping response for {} with {}/{}", response.target, response.success, response.rtt); + for (index, current_state) in state.targets.clone().iter().enumerate() { + if current_state.target == response.target { + // print!("start with {} and {} for {}", response.success, current_state.alive, current_state.target); + let new_alive = current_state.alive != response.success; + let last_alive_change = if response.success == current_state.alive { + // println!("-- LAST ALIVE DID NOT CHANGE FOR {}", current_state.target); + current_state.last_alive_change + } else { + // println!("++ LAST ALIVE IS RESET"); + SystemTime::now() + }; - info!("Manager Thread Started"); - - info!("Starting Data Thread"); - // Data Thread - let _ = thread::spawn(move || { - debug!("[DT] STARTING WITH {} HOSTS", hosts.len()); - loop { - if let Ok(rx) = receiver.recv_timeout(Duration::from_micros(1000)) { - let addr = rx.clone().address; - let rtt = rx.clone().rtt; - if rtt == u128::MAX { - // error!("[DT] No reply from {}", addr); - println!("{} not responding", Red.paint(addr.to_string())); - } else { - // debug!("[DT] Recieved a ping result from {} with time of {}", addr, rtt); - println!("{} responding.", Green.paint(addr.to_string())); + let new_state = TargetState { + target: current_state.target, + alive: response.success, + last_rtt: response.rtt, + last_alive_change, + }; + state.targets[index] = new_state.clone(); + // println!("Found the target -> {}/{}/{}", new_state.target, new_state.alive, new_state.last_rtt); } } } - }); - info!("Data Thread Started"); - - info!("Keep Alive Thread Starting."); - let _ = thread::spawn(move || { - let mut counter = 0; - loop { - thread::sleep(Duration::from_millis(1000)); - counter += 1; - if counter % 1000 == 0 { - info!("Keep Alive Counter at {}", counter); + duration_since_last_loop = SystemTime::now().duration_since(display_loop_start).expect("unable to figure out how long ago we displayed stuff"); + if duration_since_last_loop.as_secs() > SECONDS_BETWEEN_DISPLAY as u64 { + println!("DISPLAY LOOP"); + println!("------------"); + for current_result in state.targets.clone() { + println!("{} / {} -> {} / Changed {}s ago", current_result.target, current_result.alive, current_result.last_rtt, SystemTime::now().duration_since(current_result.last_alive_change).unwrap().as_secs()); } + display_loop_start = SystemTime::now(); } - }).join(); - - // - // let _ = thread::spawn(move || { - // loop { - // println!("-- Status Start -- "); - // for host in &hosts.clone() { - // host.dump_state(); - // } - // println!("-- Status Done -- "); - // thread::sleep(Duration::from_secs(1)); - // } - // }).join(); + } } diff --git a/src/manager.rs b/src/manager.rs new file mode 100644 index 0000000..0696346 --- /dev/null +++ b/src/manager.rs @@ -0,0 +1,68 @@ +use std::net::Ipv4Addr; +use std::process::Command; +use std::sync::mpsc::Sender; +use std::thread; +use std::time::{Duration, SystemTime}; +use crate::ping_request::PingRequest; +use crate::ping_result::PingResult; +use crate::SECONDS_BETWEEN_PING; + +pub struct Manager; + +const WIN_PING_SUCCESS: u8 = 1; +const LIN_PING_SUCCESS: u8 = 0; + +impl Manager { + pub fn spawn_manager_thread(targets: Vec, sender: Sender) { + let local_targets = targets.clone(); + thread::spawn(move || { + loop { + for target in &local_targets { + Manager::spawn_single_ping(PingRequest { target: *target }, sender.clone()); + } + thread::sleep(Duration::from_secs(SECONDS_BETWEEN_PING as u64)); + } + }); + } + + // Spawns a thread that pings a target and sends the response back to the main thread +// via the sender + fn spawn_single_ping(request: PingRequest, sender: Sender) { + let local_request = request.clone(); + thread::spawn(move || { + + let mut result = 0; + let mut success = true; + let start_time = SystemTime::now(); + #[cfg(any(target_os="windows"))] { + result = Command::new("c:/windows/system32/ping.exe").arg(request.target.to_string()) + .arg("-n 1") + .arg("-w 10") + .arg("-4") + .output().unwrap().status.code().unwrap_or(255); + success = result == 1; + } + #[cfg(any(target_os="linux"))] { + result = Command::new("/usr/bin/ping").arg(request.target.to_string()) + .arg("-c 1") + .arg("-4") + .arg("-w 10") + .arg("-W 1") + .output().unwrap().status.code().unwrap_or(255); + success = result == 0; + } + let ping_duration = SystemTime::now() + .duration_since(start_time) + .unwrap_or(Duration::from_secs(600)); + let success = ping_duration.as_millis() >= SECONDS_BETWEEN_PING as u128 && success; + sender.send(PingResult { + target: local_request.target, + success, + rtt: ping_duration.as_millis() as u32 + }).expect("Unable to send response"); + + // println!("Attempt for for {}", local_request.target); + }); + } + +} diff --git a/src/ping_request.rs b/src/ping_request.rs new file mode 100644 index 0000000..09bb302 --- /dev/null +++ b/src/ping_request.rs @@ -0,0 +1,6 @@ +use std::net::Ipv4Addr; + +#[derive(Clone)] +pub struct PingRequest { + pub target: Ipv4Addr, +} diff --git a/src/ping_result.rs b/src/ping_result.rs new file mode 100644 index 0000000..edf9190 --- /dev/null +++ b/src/ping_result.rs @@ -0,0 +1,9 @@ +use std::net::Ipv4Addr; + +#[derive(Clone)] +pub struct PingResult { + pub target: Ipv4Addr, + pub success: bool, + pub rtt: u32, +} + diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..dc6090a --- /dev/null +++ b/src/state.rs @@ -0,0 +1,26 @@ +use std::net::Ipv4Addr; +use crate::target_state::TargetState; + +#[derive(Default)] +pub struct State { + pub targets: Vec, +} + +impl State { + pub fn add_target(&mut self, to_add: Ipv4Addr) { + self.targets.push(TargetState { + target: to_add, + ..TargetState::default() + }); + } + + pub fn targets_ipv4(&self) -> Vec { + let mut working = vec![]; + + for current in &self.targets { + working.push(current.target); + } + + working + } +} diff --git a/src/target_state.rs b/src/target_state.rs new file mode 100644 index 0000000..f66acf6 --- /dev/null +++ b/src/target_state.rs @@ -0,0 +1,21 @@ +use std::net::Ipv4Addr; +use std::time::SystemTime; + +#[derive(Clone)] +pub struct TargetState { + pub target: Ipv4Addr, + pub alive: bool, + pub last_rtt: u32, + pub last_alive_change: SystemTime +} + +impl Default for TargetState { + fn default() -> Self { + TargetState { + target: Ipv4Addr::new(127, 0, 0, 1), + alive: false, + last_rtt: 0, + last_alive_change: SystemTime::now() + } + } +}