fixed coord timeouts

This commit is contained in:
Valmo Trindade
2026-06-29 10:32:55 +00:00
parent 189b496ad9
commit d83acce887
2 changed files with 113 additions and 23 deletions
+12 -3
View File
@@ -113,7 +113,7 @@ pub async fn run_coordinator(
} }
maybe_finished = handlers.join_next(), if !handlers.is_empty() => { maybe_finished = handlers.join_next(), if !handlers.is_empty() => {
if let Some(join_result) = maybe_finished { if let Some(join_result) = maybe_finished {
join_result??; log_worker_result(join_result);
} }
} }
} }
@@ -124,7 +124,7 @@ pub async fn run_coordinator(
} }
while let Some(join_result) = handlers.join_next().await { while let Some(join_result) = handlers.join_next().await {
join_result??; log_worker_result(join_result);
} }
let duration = start.elapsed().as_secs_f64(); let duration = start.elapsed().as_secs_f64();
@@ -175,6 +175,14 @@ pub async fn run_coordinator(
Ok(()) Ok(())
} }
fn log_worker_result(result: std::result::Result<Result<()>, tokio::task::JoinError>) {
match result {
Ok(Ok(())) => {}
Ok(Err(err)) => eprintln!("worker handler ended with error: {err:#}"),
Err(err) => eprintln!("worker task failed: {err}"),
}
}
async fn handle_worker( async fn handle_worker(
stream: TcpStream, stream: TcpStream,
peer: std::net::SocketAddr, peer: std::net::SocketAddr,
@@ -194,7 +202,8 @@ async fn handle_worker(
let worker_name = match lines.next_line().await? { let worker_name = match lines.next_line().await? {
Some(line) if line.starts_with("HELLO ") => line[6..].trim().to_string(), Some(line) if line.starts_with("HELLO ") => line[6..].trim().to_string(),
Some(line) => { Some(line) => {
return Err(anyhow!("unexpected worker handshake from {peer}: {line}")); eprintln!("rejected non-worker connection from {peer}: {line}");
return Ok(());
} }
None => return Ok(()), None => return Ok(()),
}; };
+101 -20
View File
@@ -1,9 +1,13 @@
use crate::{config::Config, scan::check_port_open, terminal::TerminalUi}; use crate::{
config::Config,
scan::check_port_open,
terminal::{ScreenState, TerminalUi},
};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use std::{net::Ipv4Addr, sync::Arc}; use std::{net::Ipv4Addr, sync::Arc};
use tokio::{ use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
net::TcpStream, net::{tcp::OwnedWriteHalf, TcpStream},
task::JoinSet, task::JoinSet,
time::sleep, time::sleep,
}; };
@@ -13,6 +17,36 @@ pub async fn run_worker(config: Config, ui: Arc<TerminalUi>) -> Result<()> {
ui.print_banner(); ui.print_banner();
} }
loop {
render_worker_status(&ui, "conectando", 0, 0);
match run_worker_session(&config, &ui).await? {
WorkerSession::Done => break,
WorkerSession::Disconnected => {
eprintln!("coordinator connection lost; reconnecting...");
sleep(std::time::Duration::from_secs(1)).await;
}
}
}
if ui.is_enabled() {
ui.render(&ScreenState {
current_ip: "concluído".to_string(),
tested: 0,
total: 0,
});
ui.finish();
}
Ok(())
}
enum WorkerSession {
Done,
Disconnected,
}
async fn run_worker_session(config: &Config, ui: &TerminalUi) -> Result<WorkerSession> {
let stream = connect_with_retry(&config.coordinator_addr).await?; let stream = connect_with_retry(&config.coordinator_addr).await?;
let (read_half, mut write_half) = stream.into_split(); let (read_half, mut write_half) = stream.into_split();
let mut lines = BufReader::new(read_half).lines(); let mut lines = BufReader::new(read_half).lines();
@@ -20,34 +54,50 @@ pub async fn run_worker(config: Config, ui: Arc<TerminalUi>) -> Result<()> {
.write_all(format!("HELLO {}\n", config.worker_name).as_bytes()) .write_all(format!("HELLO {}\n", config.worker_name).as_bytes())
.await?; .await?;
render_worker_status(ui, "aguardando job", 0, 0);
loop { loop {
let Some(line) = lines.next_line().await? else { let Some(line) = lines.next_line().await? else {
break; return Ok(WorkerSession::Disconnected);
}; };
if line == "DONE" { if line == "DONE" || line == "SHUTDOWN" {
break; return Ok(WorkerSession::Done);
}
if line == "SHUTDOWN" {
break;
} }
let job = parse_job_line(&line)?; let job = parse_job_line(&line)?;
let result = render_job_start(ui, &job);
execute_job(&job.ips, config.port, config.timeout_ms, config.concurrency).await?; let result = execute_job(
&job.ips,
config.port,
config.timeout_ms,
config.concurrency,
ui,
)
.await?;
let result_line = format!( if write_result(&mut write_half, &job, &result).await.is_err() {
"RESULT {} {} {} {} {}\n", return Ok(WorkerSession::Disconnected);
job.chunk_start, }
job.chunk_end,
result.tested, render_worker_status(ui, "aguardando job", result.tested, job.ips.len());
result.open_ips.len(),
format_ips(&result.open_ips)
);
write_half.write_all(result_line.as_bytes()).await?;
} }
}
async fn write_result(
write_half: &mut OwnedWriteHalf,
job: &Job,
result: &JobOutcome,
) -> Result<()> {
let result_line = format!(
"RESULT {} {} {} {} {}\n",
job.chunk_start,
job.chunk_end,
result.tested,
result.open_ips.len(),
format_ips(&result.open_ips)
);
write_half.write_all(result_line.as_bytes()).await?;
Ok(()) Ok(())
} }
@@ -114,11 +164,36 @@ fn parse_job_line(line: &str) -> Result<Job> {
}) })
} }
fn render_job_start(ui: &TerminalUi, job: &Job) {
let current_ip = job
.ips
.first()
.map(ToString::to_string)
.unwrap_or_else(|| "sem IP".to_string());
render_worker_status(ui, &current_ip, 0, job.ips.len());
}
fn render_worker_status(ui: &TerminalUi, current_ip: &str, tested: usize, total: usize) {
if ui.is_enabled() {
let display_total = if total == 0 && current_ip != "concluído" {
1
} else {
total
};
ui.render(&ScreenState {
current_ip: current_ip.to_string(),
tested,
total: display_total,
});
}
}
async fn execute_job( async fn execute_job(
ips: &[Ipv4Addr], ips: &[Ipv4Addr],
port: u16, port: u16,
timeout_ms: u64, timeout_ms: u64,
concurrency: usize, concurrency: usize,
ui: &TerminalUi,
) -> Result<JobOutcome> { ) -> Result<JobOutcome> {
let mut tested = 0usize; let mut tested = 0usize;
let mut open_ips = Vec::new(); let mut open_ips = Vec::new();
@@ -139,6 +214,12 @@ async fn execute_job(
if is_open { if is_open {
open_ips.push(ip); open_ips.push(ip);
} }
ui.render(&ScreenState {
current_ip: ip.to_string(),
tested,
total: ips.len(),
});
} }
index = end; index = end;