mod lease_time;
use super::RESOLVED_SERVER_PORT;
use crate::v4::MessageOptions;
use ip_network::Ipv4Network;
pub use lease_time::LeaseTime;
use log::{info, warn};
use mac_address::MacAddress;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::{OpenOptions, read_to_string};
use std::io::Write;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::os::unix::fs::OpenOptionsExt;
use std::path::PathBuf;
use toml;
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
#[serde(skip)]
pub path: PathBuf,
pub lease_time: LeaseTime,
pub rapid_commit: bool,
pub network_cidr: Ipv4Network,
pub listen_address: SocketAddrV4,
pub interface: Option<String>,
pub server_address: Option<Ipv4Addr>,
pub parameters: HashMap<String, MessageOptions>,
pub static_leases: HashMap<MacAddress, Ipv4Addr>,
pub use_leases_file: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
path: PathBuf::new(), lease_time: LeaseTime::new(86_400).unwrap(), rapid_commit: true,
network_cidr: Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 16).unwrap(), listen_address: SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), RESOLVED_SERVER_PORT),
interface: None,
server_address: None,
parameters: HashMap::with_capacity(u8::MAX as usize),
static_leases: HashMap::new(),
use_leases_file: cfg!(all(
not(feature = "benchmark"),
not(feature = "integration")
)),
}
}
}
impl Config {
pub const FILE_NAME: &'static str = "toe-beans.toml";
pub fn read(from_where: PathBuf) -> Self {
let read_result = read_to_string(from_where.join(Self::FILE_NAME));
if let Ok(config_string) = read_result {
let toml_result = toml::from_str(&config_string);
match toml_result {
Ok(config) => {
return Self {
path: from_where, ..config
};
}
Err(error) => {
warn!("{error}");
warn!(
"Warning: invalid {}. Using default values.",
Self::FILE_NAME
);
}
}
} else {
warn!(
"Warning: can't read {}. Using default values.",
Self::FILE_NAME
);
}
Self {
path: from_where,
..Config::default()
}
}
pub fn write(&self) {
info!("Writing {}", Self::FILE_NAME);
let config_content = toml::to_string_pretty(self).expect("Failed to generate toml data");
let mode = 0o600;
let mut file = OpenOptions::new()
.read(false)
.write(true)
.create(true)
.truncate(true)
.mode(mode) .open(self.path.join(Self::FILE_NAME))
.unwrap_or_else(|_| panic!("Failed to open config {} for writing", Self::FILE_NAME));
file.write_all(config_content.as_bytes())
.unwrap_or_else(|_| panic!("Failed to write config to {}", Self::FILE_NAME));
}
}