Files
RedBear-OS/netstack/src/port_set.rs
T
Red Bear OS bd595851e2 base: apply Red Bear patches on latest upstream/main
251 files: init, acpid, ipcd, netcfg, ihdgd, virtio-gpud, scheme-utils,
inputd, block driver, ptyd, ramfs, randd, initfs bootstrap, path deps,
version +rb0.3.1, author attribution
2026-07-11 11:39:24 +03:00

73 lines
2.0 KiB
Rust

use std::collections::btree_map::{BTreeMap, Entry};
pub struct PortSet {
from: u16,
range: u16,
next: u16,
ports: BTreeMap<u16, usize>,
}
impl PortSet {
pub fn new(from: u16, to: u16) -> Option<PortSet> {
if from > to {
return None;
}
Some(PortSet {
from,
range: to - from + 1,
next: 0,
ports: BTreeMap::new(),
})
}
pub fn get_port(&mut self) -> Option<u16> {
if self.ports.len() >= self.range as usize {
return None;
}
let port = loop {
if let Entry::Vacant(entry) = self.ports.entry(self.next) {
entry.insert(1);
let port = self.from + self.next;
self.next = self.next.wrapping_add(1);
break port;
}
self.next = self.next.wrapping_add(1);
};
Some(port)
}
pub fn claim_port(&mut self, port: u16) -> bool {
if let Entry::Vacant(entry) = self.ports.entry(port) {
entry.insert(1);
true
} else {
false
}
}
/// Increment the reference count for an already-claimed port (SO_REUSEADDR).
/// Always succeeds: the caller has indicated SO_REUSEADDR is set, so
/// multiple sockets are allowed to bind to the same port. The actual
/// collision check (returning EADDRINUSE) is done by `claim_port` first.
/// Returns true on success.
pub fn claim_port_reuse(&mut self, port: u16) -> bool {
self.ports.entry(port).and_modify(|c| *c += 1).or_insert(1);
true
}
pub fn acquire_port(&mut self, port: u16) {
*self.ports.entry(port).or_insert(0) += 1;
}
pub fn release_port(&mut self, port: u16) {
if let Entry::Occupied(mut entry) = self.ports.entry(port) {
*entry.get_mut() -= 1;
if *entry.get() == 0 {
entry.remove();
}
}
}
}