From e143b186a3eba9c03af20156ad3a2e729c638dc9 Mon Sep 17 00:00:00 2001 From: Hristo Venev Date: Tue, 19 Mar 2019 10:14:23 +0200 Subject: BREAKING CHANGES ifname is now passed as an argument before the config file. own_public_key is obtained from the interface. --- src/main.rs | 144 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 49 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 0ef17aa..f5ebb26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ struct Source { config: config::Source, data: Option, next_update: Instant, - backoff: Option, + backoff: Option, } impl Source { @@ -38,25 +38,31 @@ pub struct Device { update_config: config::UpdateConfig, sources: Vec, current: wg::Config, - curl_command: String, } impl Device { - pub fn new(c: config::Config) -> Device { - let dev = wg::Device::new(c.ifname, c.wg_command); - let current = wg::ConfigBuilder::new(&c.peers).build(); - Device { + pub fn new(ifname: String, c: config::Config) -> io::Result { + let dev = wg::Device::new(ifname)?; + + Ok(Device { dev, - peer_config: c.peers, - update_config: c.update, + peer_config: c.peer_config, + update_config: c.update_config, sources: c.sources.into_iter().map(Source::new).collect(), - current, - curl_command: c.curl_command, - } + current: wg::Config::default(), + }) } - fn make_config(&self, ts: SystemTime) -> (wg::Config, Vec, SystemTime) { - let mut next_update = ts + Duration::from_secs(3600); + fn refresh_period(&self) -> Duration { + Duration::from_secs(u64::from(self.update_config.refresh_period)) + } + + fn make_config( + &self, + public_key: &str, + ts: SystemTime, + ) -> (wg::Config, Vec, SystemTime) { + let mut t_cfg = ts + self.refresh_period(); let mut sources: Vec<(&Source, &proto::SourceConfig)> = vec![]; for src in self.sources.iter() { if let Some(ref data) = src.data { @@ -67,7 +73,7 @@ impl Device { if ts >= next.update_at { Some(&next.config) } else { - next_update = next_update.min(next.update_at); + t_cfg = t_cfg.min(next.update_at); None } }) @@ -76,7 +82,7 @@ impl Device { } } - let mut cfg = wg::ConfigBuilder::new(&self.peer_config); + let mut cfg = wg::ConfigBuilder::new(public_key, &self.peer_config); let mut errs = vec![]; for (src, sc) in sources.iter() { for peer in sc.servers.iter() { @@ -90,26 +96,28 @@ impl Device { } let cfg = cfg.build(); - (cfg, errs, next_update) + (cfg, errs, t_cfg) } pub fn update(&mut self) -> io::Result { - let now = Instant::now(); - let refresh = self.update_config.refresh_period; - let after_refresh = now + Duration::from_secs(u64::from(refresh)); - let mut next_update = after_refresh; + let refresh = self.refresh_period(); + let mut now = Instant::now(); + let mut t_refresh = now + refresh; + for src in self.sources.iter_mut() { if now < src.next_update { - next_update = next_update.min(src.next_update); + t_refresh = t_refresh.min(src.next_update); continue; } - let r = match fetch_source(&self.curl_command, &src.config.url) { + let r = fetch_source(&src.config.url); + now = Instant::now(); + let r = match r { Ok(r) => { eprintln!("<6>Updated [{}]", &src.config.url); src.data = Some(r); src.backoff = None; - src.next_update = after_refresh; + src.next_update = now + refresh; continue; } Err(r) => r, @@ -120,20 +128,22 @@ impl Device { let b = src.backoff.unwrap_or(if src.data.is_some() { refresh / 3 } else { - u32::min(10, refresh / 10) + Duration::from_secs(10).min(refresh / 10) }); + src.next_update = now + b; + t_refresh = t_refresh.min(src.next_update); let b = (b + b / 3).min(refresh); src.backoff = Some(b); - src.next_update = now + Duration::from_secs(u64::from(b)); - next_update = next_update.min(src.next_update); } + let now = Instant::now(); let sysnow = SystemTime::now(); - let (config, errors, upd_time) = self.make_config(sysnow); - let time_to_upd = upd_time + let public_key = self.dev.get_public_key()?; + let (config, errors, t_cfg) = self.make_config(&public_key, sysnow); + let time_to_cfg = t_cfg .duration_since(sysnow) .unwrap_or(Duration::from_secs(0)); - next_update = next_update.min(now + time_to_upd); + let t_cfg = now + time_to_cfg; if config != self.current { eprintln!("<5>Applying configuration update"); @@ -143,27 +153,49 @@ impl Device { self.dev.apply_diff(&self.current, &config)?; self.current = config; } - eprintln!("<6>Next configuration update after {:?}", time_to_upd); - Ok(next_update) + Ok(if t_cfg < t_refresh { + eprintln!("<6>Next configuration update after {:?}", time_to_cfg); + t_cfg + } else if t_refresh > now { + eprintln!("<6>Next refresh after {:?}", t_refresh.duration_since(now)); + t_refresh + } else { + now + }) } } -fn fetch_source(curl_command: &str, url: &str) -> io::Result { +fn fetch_source(url: &str) -> io::Result { + use std::env; + use std::ffi::{OsStr, OsString}; use std::process::{Command, Stdio}; - let out = Command::new(curl_command) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::null()) - .arg("--fail") - .arg("--fail-early") - .arg("--") - .arg(url) - .output()?; + let curl = match env::var_os("CURL") { + None => OsString::new(), + Some(v) => v, + }; + let mut proc = Command::new(if curl.is_empty() { + OsStr::new("curl") + } else { + curl.as_os_str() + }); + + proc.stdin(Stdio::null()); + proc.stdout(Stdio::piped()); + proc.stderr(Stdio::null()); + proc.arg("--fail"); + proc.arg("--fail-early"); + proc.arg("--"); + proc.arg(url); + + let out = proc.output()?; if !out.status.success() { - return Err(io::Error::new(io::ErrorKind::Other, format!("Failed to download [{}]", url))); + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Failed to download [{}]", url), + )); } let mut de = serde_json::Deserializer::from_slice(&out.stdout); @@ -185,14 +217,20 @@ fn main() { use std::{env, process, thread}; let args: Vec = env::args().collect(); - if args.len() != 2 { + if args.len() != 3 { let arg0 = if !args.is_empty() { &args[0] } else { "wgconf" }; eprintln!("<1>Usage:"); - eprintln!("<1> {} CONFIG", arg0); + eprintln!("<1> {} IFNAME CONFIG", arg0); process::exit(1); } - let config = match load_config(&args[1]) { + let mut args = args.into_iter(); + let _ = args.next().unwrap(); + let ifname = args.next().unwrap(); + let config_path = args.next().unwrap(); + assert!(args.next().is_none()); + + let config = match load_config(&config_path) { Ok(c) => c, Err(e) => { eprintln!("<1>Failed to load config: {}", e); @@ -200,7 +238,14 @@ fn main() { } }; - let mut dev = Device::new(config); + let mut dev = match Device::new(ifname, config) { + Ok(dev) => dev, + Err(e) => { + eprintln!("<1>Failed to open device: {}", e); + process::exit(1); + } + }; + loop { let tm = match dev.update() { Ok(t) => t, @@ -210,8 +255,9 @@ fn main() { } }; let now = Instant::now(); - let sleep = tm.duration_since(now); - println!("Sleeping for {:?}", sleep); - thread::sleep(sleep); + if tm > now { + let sleep = tm.duration_since(now); + thread::sleep(sleep); + } } } -- cgit