quincy_server/server/
address_pool.rs1use dashmap::DashSet;
2use ipnet::{IpAddrRange, IpNet, Ipv4AddrRange, Ipv6AddrRange};
3use std::net::IpAddr;
4
5pub struct AddressPool {
7 network: IpNet,
8 used_addresses: DashSet<IpAddr>,
9}
10
11impl AddressPool {
12 pub fn new(network: IpNet) -> Self {
17 let pool = Self {
18 network,
19 used_addresses: DashSet::new(),
20 };
21
22 pool.reset();
23
24 pool
25 }
26
27 pub fn next_available_address(&self) -> Option<IpNet> {
29 let mut range = match self.network {
30 IpNet::V4(network) => {
31 IpAddrRange::V4(Ipv4AddrRange::new(network.network(), network.broadcast()))
32 }
33 IpNet::V6(network) => {
34 IpAddrRange::V6(Ipv6AddrRange::new(network.network(), network.broadcast()))
35 }
36 };
37
38 range
39 .find(|address| !self.used_addresses.contains(address))
40 .map(|address| {
41 self.used_addresses.insert(address);
42 IpNet::with_netmask(address, self.network.netmask())
43 .expect("Netmask will always be valid")
44 })
45 }
46
47 pub fn release_address(&self, address: &IpAddr) {
52 self.used_addresses.remove(address);
53 }
54
55 pub fn reset(&self) {
57 self.used_addresses.clear();
58 self.used_addresses.insert(self.network.network());
59 self.used_addresses.insert(self.network.addr());
60 self.used_addresses.insert(self.network.broadcast());
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use crate::server::address_pool::AddressPool;
67 use ipnet::{IpNet, Ipv4Net};
68 use std::net::{IpAddr, Ipv4Addr};
69
70 #[test]
71 fn test_address_pool() {
72 let pool = AddressPool::new(IpNet::V4(
73 Ipv4Net::with_netmask(
74 Ipv4Addr::new(10, 0, 0, 1),
75 Ipv4Addr::new(255, 255, 255, 252),
76 )
77 .unwrap(),
78 ));
79
80 assert_eq!(
81 pool.next_available_address().unwrap(),
82 IpNet::V4(
83 Ipv4Net::with_netmask(
84 Ipv4Addr::new(10, 0, 0, 2),
85 Ipv4Addr::new(255, 255, 255, 252),
86 )
87 .unwrap()
88 )
89 );
90
91 assert_eq!(pool.next_available_address(), None);
92 pool.release_address(&IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)));
93
94 assert_eq!(
95 pool.next_available_address().unwrap(),
96 IpNet::V4(
97 Ipv4Net::with_netmask(
98 Ipv4Addr::new(10, 0, 0, 2),
99 Ipv4Addr::new(255, 255, 255, 252),
100 )
101 .unwrap()
102 )
103 );
104 }
105}