1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use std::collections::hash_map::{Entry, HashMap};
use std::net::SocketAddrV4;

pub trait PortAllocator: std::fmt::Debug + Send {
    fn next_port(&mut self, local_endpoint: SocketAddrV4) -> u16;
}

#[derive(Clone, Debug)]
pub struct SequentialPortAllocator {
    next_original_port: u16,
    next_for_local_endpoint: HashMap<SocketAddrV4, u16>,
}

impl Default for SequentialPortAllocator {
    fn default() -> Self {
        Self {
            next_original_port: 49152,
            next_for_local_endpoint: HashMap::new(),
        }
    }
}

impl PortAllocator for SequentialPortAllocator {
    fn next_port(&mut self, local_endpoint: SocketAddrV4) -> u16 {
        match self.next_for_local_endpoint.entry(local_endpoint) {
            Entry::Occupied(mut entry) => {
                let port = *entry.get();
                *entry.get_mut() = entry.get().checked_add(1).unwrap_or(49152);
                port
            }
            Entry::Vacant(entry) => {
                let port = self.next_original_port;
                self.next_original_port = self.next_original_port.wrapping_add(16);
                if self.next_original_port < 49152 {
                    self.next_original_port += 49153
                };
                entry.insert(port);
                port
            }
        }
    }
}

#[derive(Clone, Debug, Default)]
pub struct RandomPortAllocator;

impl PortAllocator for RandomPortAllocator {
    fn next_port(&mut self, _local_endpoint: SocketAddrV4) -> u16 {
        loop {
            let port = rand::random();
            if port >= 1000 {
                return port;
            }
        }
    }
}