use fuchsia_sync::Mutex;
use std::collections::HashSet;
use {fidl_fuchsia_net as net, fidl_fuchsia_net_ext as net_ext};
pub type ServerList = Vec<net::SocketAddress>;
#[derive(Debug)]
struct ServerConfigInner {
servers: ServerList,
}
#[derive(Debug)]
pub struct ServerConfigState(Mutex<ServerConfigInner>);
#[derive(Debug, PartialEq, Eq)]
pub enum UpdateServersResult {
Updated(ServerList),
NoChange,
InvalidsServers,
}
impl ServerConfigState {
pub fn new() -> Self {
Self(Mutex::new(ServerConfigInner { servers: Vec::new() }))
}
pub fn servers(&self) -> ServerList {
let Self(current) = self;
let inner = current.lock();
inner.servers.clone()
}
pub fn update_servers(&self, mut servers: ServerList) -> UpdateServersResult {
let Self(current) = self;
if servers.iter().any(|s| {
let net_ext::SocketAddress(sockaddr) = From::from(*s);
let ip = sockaddr.ip();
ip.is_multicast() || ip.is_unspecified()
}) {
return UpdateServersResult::InvalidsServers;
}
let mut set = HashSet::new();
let () = servers.retain(|s| set.insert(*s));
let mut inner = current.lock();
if inner.servers == servers {
return UpdateServersResult::NoChange;
}
inner.servers = servers.clone();
UpdateServersResult::Updated(servers)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::*;
use net_declare::fidl_socket_addr;
#[test]
fn test_config_state() {
let state = ServerConfigState::new();
assert_eq!(state.servers(), []);
let values = [DHCP_SERVER, NDP_SERVER];
assert_eq!(
state.update_servers(values.to_vec()),
UpdateServersResult::Updated(values.to_vec())
);
assert_eq!(state.servers(), values);
assert_eq!(
state.update_servers(vec![DHCP_SERVER, DHCP_SERVER, NDP_SERVER]),
UpdateServersResult::NoChange
);
assert_eq!(state.servers(), values);
for addr in [
fidl_socket_addr!("0.0.0.0:1111"),
fidl_socket_addr!("[::]:2222"),
fidl_socket_addr!("224.0.0.1:3333"),
fidl_socket_addr!("[ff02::1]:4444"),
] {
assert_eq!(state.update_servers(vec![addr]), UpdateServersResult::InvalidsServers);
}
assert_eq!(state.servers(), values);
assert_eq!(state.update_servers(vec![]), UpdateServersResult::Updated(vec![]));
assert_eq!(state.servers(), []);
}
}