1use fidl_fuchsia_net as net;
6use fidl_fuchsia_net_ext as net_ext;
7use fuchsia_sync::Mutex;
8use std::collections::HashSet;
9
10pub type ServerList = Vec<net::SocketAddress>;
14
15#[derive(Debug)]
17struct ServerConfigInner {
18 servers: ServerList,
19}
20
21#[derive(Debug)]
23pub struct ServerConfigState(Mutex<ServerConfigInner>);
24
25#[derive(Debug, PartialEq, Eq)]
27pub enum UpdateServersResult {
28 Updated(ServerList),
30 NoChange,
32 InvalidsServers,
34}
35
36impl ServerConfigState {
37 pub fn new() -> Self {
39 Self(Mutex::new(ServerConfigInner { servers: Vec::new() }))
40 }
41
42 pub fn servers(&self) -> ServerList {
44 let Self(current) = self;
45 let inner = current.lock();
46 inner.servers.clone()
47 }
48
49 pub fn update_servers(&self, mut servers: ServerList) -> UpdateServersResult {
51 let Self(current) = self;
52
53 if servers.iter().any(|s| {
54 let net_ext::SocketAddress(sockaddr) = From::from(*s);
56 let ip = sockaddr.ip();
57 ip.is_multicast() || ip.is_unspecified()
58 }) {
59 return UpdateServersResult::InvalidsServers;
60 }
61
62 let mut set = HashSet::new();
63 servers.retain(|s| set.insert(*s));
64 let mut inner = current.lock();
65 if inner.servers == servers {
66 return UpdateServersResult::NoChange;
67 }
68 inner.servers = servers.clone();
69 UpdateServersResult::Updated(servers)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::test_util::*;
77 use net_declare::fidl_socket_addr;
78
79 #[test]
80 fn test_config_state() {
81 let state = ServerConfigState::new();
82 assert_eq!(state.servers(), []);
83
84 let values = [DHCP_SERVER, NDP_SERVER];
86 assert_eq!(
87 state.update_servers(values.to_vec()),
88 UpdateServersResult::Updated(values.to_vec())
89 );
90 assert_eq!(state.servers(), values);
91
92 assert_eq!(
94 state.update_servers(vec![DHCP_SERVER, DHCP_SERVER, NDP_SERVER]),
95 UpdateServersResult::NoChange
96 );
97 assert_eq!(state.servers(), values);
98
99 for addr in [
101 fidl_socket_addr!("0.0.0.0:1111"),
102 fidl_socket_addr!("[::]:2222"),
103 fidl_socket_addr!("224.0.0.1:3333"),
104 fidl_socket_addr!("[ff02::1]:4444"),
105 ] {
106 assert_eq!(state.update_servers(vec![addr]), UpdateServersResult::InvalidsServers);
107 }
108 assert_eq!(state.servers(), values);
109
110 assert_eq!(state.update_servers(vec![]), UpdateServersResult::Updated(vec![]));
112 assert_eq!(state.servers(), []);
113 }
114}