aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorHristo Venev <hristo@venev.name>2019-03-19 10:14:23 +0200
committerHristo Venev <hristo@venev.name>2019-03-19 10:14:23 +0200
commite143b186a3eba9c03af20156ad3a2e729c638dc9 (patch)
tree20f966ffc8981d90ab5a94c3c6a86172f92fd3f2 /src/main.rs
parent517040083e7796f59c47f8afe6a782417b132c20 (diff)
BREAKING CHANGES
ifname is now passed as an argument before the config file. own_public_key is obtained from the interface.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs144
1 files changed, 95 insertions, 49 deletions
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<proto::Source>,
next_update: Instant,
- backoff: Option<u32>,
+ backoff: Option<Duration>,
}
impl Source {
@@ -38,25 +38,31 @@ pub struct Device {
update_config: config::UpdateConfig,
sources: Vec<Source>,
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<Device> {
+ 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<wg::ConfigError>, 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<wg::ConfigError>, 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<Instant> {
- 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<proto::Source> {
+fn fetch_source(url: &str) -> io::Result<proto::Source> {
+ 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<String> = 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);
+ }
}
}