summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/server.rs48
-rw-r--r--src/config/environment.rs126
-rw-r--r--src/config/file.rs (renamed from src/config.rs)82
-rw-r--r--src/config/mod.rs90
-rw-r--r--src/error.rs2
-rw-r--r--src/lib.rs1
6 files changed, 246 insertions, 103 deletions
diff --git a/src/bin/server.rs b/src/bin/server.rs
index 0a1bb21..9b2b01a 100644
--- a/src/bin/server.rs
+++ b/src/bin/server.rs
@@ -45,7 +45,6 @@ use std::io::ErrorKind;
use std::process;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
-use std::thread;
use std::time::Duration;
use mio::net::UdpSocket;
@@ -54,7 +53,7 @@ use mio_extras::timer::Timer;
use byteorder::{LittleEndian, WriteBytesExt};
-use roughenough::config::{FileConfig, ServerConfig};
+use roughenough::config::{EnvironmentConfig, FileConfig, ServerConfig};
use roughenough::keys::{LongTermKey, OnlineKey};
use roughenough::merkle::MerkleTree;
use roughenough::{Error, RtMessage, Tag};
@@ -104,18 +103,18 @@ fn nonce_from_request(buf: &[u8], num_bytes: usize) -> Result<&[u8], Error> {
}
fn polling_loop(
- config: &ServerConfig,
+ config: Box<ServerConfig>,
online_key: &mut OnlineKey,
cert_bytes: &[u8],
- response_counter: Arc<AtomicUsize>,
) {
+ let response_counter = AtomicUsize::new(0);
let keep_running = Arc::new(AtomicBool::new(true));
let kr = keep_running.clone();
ctrlc::set_handler(move || kr.store(false, Ordering::Release))
.expect("failed setting Ctrl-C handler");
- let sock_addr = config.socket_addr();
+ let sock_addr = config.socket_addr().expect("");
let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");
let poll_duration = Some(Duration::from_millis(100));
@@ -251,11 +250,16 @@ pub fn main() {
let mut args = env::args();
if args.len() != 2 {
- error!("Usage: server /path/to/config.file");
+ error!("Usage: server /path/to/config.file|ENV");
process::exit(1);
}
- let config = FileConfig::from_file(&args.nth(1).unwrap()).expect("Unable to load config");
+ let arg1 = args.nth(1).unwrap();
+
+ let config: Box<ServerConfig> = match arg1.as_ref() {
+ "ENV" => Box::new(EnvironmentConfig::new()),
+ _ => Box::new(FileConfig::from_file(&arg1).unwrap()),
+ };
let mut online_key = OnlineKey::new();
let mut long_term_key = LongTermKey::new(config.seed());
@@ -267,35 +271,9 @@ pub fn main() {
info!("Status updates every : {} seconds", config.status_interval().as_secs());
info!("Server listening on : {}:{}", config.interface(), config.port());
- let response_counter = Arc::new(AtomicUsize::new(0));
-
- if env::var("BENCH").is_ok() {
- log::set_max_level(log::LevelFilter::Warn);
- let response_counter = response_counter.clone();
-
- thread::spawn(move || loop {
- let old = time::get_time().sec;
- let old_reqs = response_counter.load(Ordering::SeqCst);
-
- thread::sleep(Duration::from_secs(1));
-
- let new = time::get_time().sec;
- let new_reqs = response_counter.load(Ordering::SeqCst);
-
- warn!(
- "Processing at {:?} reqs/sec",
- (new_reqs - old_reqs) / (new - old) as usize
- );
- });
- }
-
- polling_loop(
- &config,
- &mut online_key,
- &cert_bytes,
- response_counter.clone(),
- );
+ polling_loop(config, &mut online_key, &cert_bytes);
info!("Done.");
process::exit(0);
}
+
diff --git a/src/config/environment.rs b/src/config/environment.rs
new file mode 100644
index 0000000..c4d2c06
--- /dev/null
+++ b/src/config/environment.rs
@@ -0,0 +1,126 @@
+// Copyright 2017-2018 int08h LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate hex;
+
+use std::env;
+use std::net::SocketAddr;
+use std::time::Duration;
+
+use Error;
+use config::ServerConfig;
+use config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
+
+///
+/// Obtain a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
+/// from environment variables.
+///
+/// Config parameter | Environment Variable
+/// ---------------- | --------------------
+/// port | `ROUGHENOUGH_PORT`
+/// interface | `ROUGHENOUGH_INTERFACE`
+/// seed | `ROUGHENOUGH_SEED`
+/// batch_size | `ROUGHENOUGH_BATCH_SIZE`
+/// status_interval | `ROUGHENOUGH_STATUS_INTERVAL`
+///
+pub struct EnvironmentConfig {
+ port: u16,
+ interface: String,
+ seed: Vec<u8>,
+ batch_size: u8,
+ status_interval: Duration,
+}
+
+const ROUGHENOUGH_PORT: &str = "ROUGHENOUGH_PORT";
+const ROUGHENOUGH_INTERFACE: &str = "ROUGHENOUGH_INTERFACE";
+const ROUGHENOUGH_SEED: &str = "ROUGHENOUGH_SEED";
+const ROUGHENOUGH_BATCH_SIZE: &str = "ROUGHENOUGH_BATCH_SIZE";
+const ROUGHENOUGH_STATUS_INTERVAL: &str = "ROUGHENOUGH_STATUS_INTERVAL";
+
+impl EnvironmentConfig {
+ pub fn new() -> Self {
+ let mut cfg = EnvironmentConfig {
+ port: 0,
+ interface: "".to_string(),
+ seed: Vec::new(),
+ batch_size: DEFAULT_BATCH_SIZE,
+ status_interval: DEFAULT_STATUS_INTERVAL,
+ };
+
+ if let Ok(port) = env::var(ROUGHENOUGH_PORT) {
+ cfg.port = port
+ .parse()
+ .expect(format!("invalid port: {}", port).as_ref());
+ };
+
+ if let Ok(interface) = env::var(ROUGHENOUGH_INTERFACE) {
+ cfg.interface = interface.to_string();
+ };
+
+ if let Ok(seed) = env::var(ROUGHENOUGH_SEED) {
+ cfg.seed = hex::decode(&seed).expect(
+ format!(
+ "invalid seed value: {}\n'seed' should be 32 byte hex value",
+ seed
+ ).as_ref(),
+ );
+ };
+
+ if let Ok(batch_size) = env::var(ROUGHENOUGH_BATCH_SIZE) {
+ cfg.batch_size = batch_size
+ .parse()
+ .expect(format!("invalid batch_size: {}", batch_size).as_ref());
+ };
+
+ if let Ok(status_interval) = env::var(ROUGHENOUGH_STATUS_INTERVAL) {
+ let val: u16 = status_interval
+ .parse()
+ .expect(format!("invalid status_interval: {}", status_interval).as_ref());
+
+ cfg.status_interval = Duration::from_secs(val as u64);
+ };
+
+ cfg
+ }
+}
+
+impl ServerConfig for EnvironmentConfig {
+ fn interface(&self) -> &str {
+ self.interface.as_ref()
+ }
+
+ fn port(&self) -> u16 {
+ self.port
+ }
+
+ fn seed(&self) -> &[u8] {
+ &self.seed
+ }
+
+ fn batch_size(&self) -> u8 {
+ self.batch_size
+ }
+
+ fn status_interval(&self) -> Duration {
+ self.status_interval
+ }
+
+ fn socket_addr(&self) -> Result<SocketAddr, Error> {
+ let addr = format!("{}:{}", self.interface, self.port);
+ match addr.parse() {
+ Ok(v) => Ok(v),
+ Err(_) => Err(Error::InvalidConfiguration(addr)),
+ }
+ }
+}
diff --git a/src/config.rs b/src/config/file.rs
index 669df1e..24011bb 100644
--- a/src/config.rs
+++ b/src/config/file.rs
@@ -12,15 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//!
-//! Ways to configure the Roughenough server.
-//!
-//! The [ServerConfig](trait.ServerConfig.html) trait specifies the required and optional
-//! parameters available for configuring a Roughenoguh server instance.
-//!
-//! Implementations of `ServerConfig` obtain configurations from different back-end sources.
-//!
-
extern crate hex;
use std::fs::File;
@@ -28,64 +19,16 @@ use std::io::Read;
use std::net::SocketAddr;
use std::time::Duration;
use yaml_rust::YamlLoader;
-use Error;
-
-const DEFAULT_BATCH_SIZE: u8 = 64;
-const DEFAULT_STATUS_INTERVAL: Duration = Duration::from_secs(600);
-///
-/// Specifies parameters needed to configure a Roughenough server.
-///
-/// Parameters labeled "**Required**" must are always be provided and have no default value.
-/// Parameters labeled "**Optional**" provide default values that can be overridden.
-///
-/// * **`interface`** - [Required] IP address or interface name for listening to client requests
-/// * **`port`** - [Required] UDP port to listen for requests
-/// * **`seed`** - [Required] A 32-byte hexadecimal value used to generate the server's long-term
-/// key pair. **This is a secret value and must be un-guessable**,
-/// treat it with care.
-/// * **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All
-/// nonces in a batch are used to build a Merkle tree, the root of which
-/// is signed. Default is 64 requests per batch.
-/// * **`status_interval`** - [Optional] Amount of time between each logged status update.
-/// Default is 600 seconds (10 minutes).
-///
-/// Implementations of this trait obtain a valid configuration from different back-
-/// end sources.
-///
-/// See:
-/// * [FileConfig](struct.FileConfig.html)
-///
-pub trait ServerConfig {
- /// [Required] IP address or interface name to listen for client requests
- fn interface(&self) -> &str;
-
- /// [Required] UDP port to listen for requests
- fn port(&self) -> u16;
-
- /// [Required] A 32-byte hexadecimal value used to generate the server's
- /// long-term key pair. **This is a secret value and must be un-guessable**,
- /// treat it with care.
- fn seed(&self) -> &[u8];
-
- /// [Optional] The maximum number of requests to process in one batch. All
- /// nonces in a batch are used to build a Merkle tree, the root of which is signed.
- /// Default is 64 requests per batch.
- fn batch_size(&self) -> u8;
-
- /// [Optional] Amount of time between each logged status update.
- /// Default is 600 seconds (10 minutes).
- fn status_interval(&self) -> Duration;
-
- /// Convenience function to create a `SocketAddr` from the provided `interface` and `port`
- fn socket_addr(&self) -> SocketAddr;
-}
+use Error;
+use config::ServerConfig;
+use config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
///
-/// Read the configuration from a YAML file
+/// Read a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
+/// from a YAML file.
///
-/// Example minimal config file with only the required parameters from
-/// [ServerConfig](trait.ServerConfig.html):
+/// Example config:
///
/// ```yaml
/// interface: 127.0.0.1
@@ -120,7 +63,7 @@ impl FileConfig {
let mut config = FileConfig {
port: 0,
- interface: "unknown".to_string(),
+ interface: "".to_string(),
seed: Vec::new(),
batch_size: DEFAULT_BATCH_SIZE,
status_interval: DEFAULT_STATUS_INTERVAL,
@@ -142,7 +85,8 @@ impl FileConfig {
}
unknown => {
return Err(Error::InvalidConfiguration(format!(
- "unknown config key: {}", unknown
+ "unknown config key: {}",
+ unknown
)));
}
}
@@ -173,9 +117,11 @@ impl ServerConfig for FileConfig {
self.status_interval
}
- fn socket_addr(&self) -> SocketAddr {
+ fn socket_addr(&self) -> Result<SocketAddr, Error> {
let addr = format!("{}:{}", self.interface, self.port);
- addr.parse()
- .expect(&format!("could not create socket address from {}", addr))
+ match addr.parse() {
+ Ok(v) => Ok(v),
+ Err(_) => Err(Error::InvalidConfiguration(addr)),
+ }
}
}
diff --git a/src/config/mod.rs b/src/config/mod.rs
new file mode 100644
index 0000000..0cd8742
--- /dev/null
+++ b/src/config/mod.rs
@@ -0,0 +1,90 @@
+// Copyright 2017-2018 int08h LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//!
+//! Ways to configure the Roughenough server.
+//!
+//! The [ServerConfig](trait.ServerConfig.html) trait specifies the required and optional
+//! parameters available for configuring a Roughenoguh server instance.
+//!
+//! Implementations of `ServerConfig` obtain configurations from different back-end sources.
+//!
+
+extern crate hex;
+
+use std::net::SocketAddr;
+use std::time::Duration;
+
+mod file;
+pub use self::file::FileConfig;
+
+mod environment;
+pub use self::environment::EnvironmentConfig;
+
+use Error;
+
+/// Maximum number of requests to process in one batch and include the the Merkle tree.
+pub const DEFAULT_BATCH_SIZE: u8 = 64;
+
+/// Amount of time between each logged status update.
+pub const DEFAULT_STATUS_INTERVAL: Duration = Duration::from_secs(600);
+
+///
+/// Specifies parameters needed to configure a Roughenough server.
+///
+/// Parameters labeled "**Required**" must are always be provided and have no default value.
+/// Parameters labeled "**Optional**" provide default values that can be overridden.
+///
+/// * **`interface`** - [Required] IP address or interface name for listening to client requests
+/// * **`port`** - [Required] UDP port to listen for requests
+/// * **`seed`** - [Required] A 32-byte hexadecimal value used to generate the server's long-term
+/// key pair. **This is a secret value and must be un-guessable**,
+/// treat it with care.
+/// * **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All
+/// nonces in a batch are used to build a Merkle tree, the root of which
+/// is signed.
+/// Defaults to [DEFAULT_BATCH_SIZE](constant.DEFAULT_BATCH_SIZE.html)
+/// * **`status_interval`** - [Optional] Amount of time between each logged status update.
+/// Defaults to [DEFAULT_STATUS_INTERVAL](constant.DEFAULT_STATUS_INTERVAL.html)
+///
+/// Implementations of this trait obtain a valid configuration from different back-
+/// end sources.
+///
+/// See:
+/// * [FileConfig](struct.FileConfig.html)
+///
+pub trait ServerConfig {
+ /// [Required] IP address or interface name to listen for client requests
+ fn interface(&self) -> &str;
+
+ /// [Required] UDP port to listen for requests
+ fn port(&self) -> u16;
+
+ /// [Required] A 32-byte hexadecimal value used to generate the server's
+ /// long-term key pair. **This is a secret value and must be un-guessable**,
+ /// treat it with care.
+ fn seed(&self) -> &[u8];
+
+ /// [Optional] The maximum number of requests to process in one batch. All
+ /// nonces in a batch are used to build a Merkle tree, the root of which is signed.
+ /// Defaults to [DEFAULT_BATCH_SIZE](constant.DEFAULT_BATCH_SIZE.html)
+ fn batch_size(&self) -> u8;
+
+ /// [Optional] Amount of time between each logged status update.
+ /// Defaults to [DEFAULT_STATUS_INTERVAL](constant.DEFAULT_STATUS_INTERVAL.html)
+ fn status_interval(&self) -> Duration;
+
+ /// Convenience function to create a `SocketAddr` from the provided `interface` and `port`
+ fn socket_addr(&self) -> Result<SocketAddr, Error>;
+}
diff --git a/src/error.rs b/src/error.rs
index b681f33..49102a4 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -58,3 +58,5 @@ impl From<std::io::Error> for Error {
Error::EncodingFailure(err)
}
}
+
+
diff --git a/src/lib.rs b/src/lib.rs
index f0abb08..5d8b51c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -58,6 +58,7 @@ mod message;
mod tag;
pub mod config;
+
pub mod keys;
pub mod merkle;
pub mod sign;