Skip to main content

rust_p2p_core/punch/
config.rs

1use crate::nat::NatInfo;
2use serde::{Deserialize, Serialize};
3use std::collections::HashSet;
4use std::ops;
5use std::str::FromStr;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum PunchRole {
9    /// Actively initiates the hole punching process
10    Initiator,
11    /// Assists the peer in hole punching (responding side)
12    Responder,
13}
14
15#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
16pub enum PunchPolicy {
17    IPv4Tcp,
18    IPv4Udp,
19    IPv6Tcp,
20    IPv6Udp,
21}
22
23impl ops::BitOr<PunchPolicy> for PunchPolicy {
24    type Output = PunchPolicySet;
25
26    fn bitor(self, rhs: PunchPolicy) -> Self::Output {
27        let mut model = PunchPolicySet::empty();
28        model.or(self);
29        model.or(rhs);
30        model
31    }
32}
33/// This is middle representation for inner
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub struct PunchPolicySet {
36    models: HashSet<PunchPolicy>,
37}
38
39impl Default for PunchPolicySet {
40    fn default() -> Self {
41        PunchPolicySet::all()
42    }
43}
44
45impl ops::BitOr<PunchPolicy> for PunchPolicySet {
46    type Output = PunchPolicySet;
47
48    fn bitor(mut self, rhs: PunchPolicy) -> Self::Output {
49        self.or(rhs);
50        self
51    }
52}
53
54impl PunchPolicySet {
55    pub fn all() -> Self {
56        PunchPolicy::IPv4Tcp | PunchPolicy::IPv4Udp | PunchPolicy::IPv6Tcp | PunchPolicy::IPv6Udp
57    }
58    pub fn ipv4() -> Self {
59        PunchPolicy::IPv4Tcp | PunchPolicy::IPv4Udp
60    }
61    pub fn ipv6() -> Self {
62        PunchPolicy::IPv6Tcp | PunchPolicy::IPv6Udp
63    }
64    pub fn empty() -> Self {
65        Self {
66            models: Default::default(),
67        }
68    }
69    pub fn or(&mut self, punch_model: PunchPolicy) {
70        self.models.insert(punch_model);
71    }
72    pub fn is_match(&self, punch_model: PunchPolicy) -> bool {
73        self.models.contains(&punch_model)
74    }
75}
76
77#[derive(Clone, Debug)]
78pub struct PunchModel {
79    set: Vec<PunchPolicySet>,
80}
81
82impl ops::BitAnd<PunchPolicySet> for PunchPolicySet {
83    type Output = PunchModel;
84
85    fn bitand(self, rhs: PunchPolicySet) -> Self::Output {
86        let mut boxes = PunchModel::empty();
87        boxes.and(self);
88        boxes.and(rhs);
89        boxes
90    }
91}
92
93impl PunchModel {
94    pub fn all() -> Self {
95        Self {
96            set: vec![PunchPolicySet::all()],
97        }
98    }
99    pub fn empty() -> Self {
100        Self { set: Vec::new() }
101    }
102    pub fn and(&mut self, punch_model_box: PunchPolicySet) {
103        self.set.push(punch_model_box)
104    }
105    pub fn is_match(&self, punch_model: PunchPolicy) -> bool {
106        if self.set.is_empty() {
107            return false;
108        }
109        for x in &self.set {
110            if !x.is_match(punch_model) {
111                return false;
112            }
113        }
114        true
115    }
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize)]
119pub struct PunchConsultInfo {
120    pub peer_punch_model: PunchPolicySet,
121    pub peer_nat_info: NatInfo,
122}
123
124impl PunchConsultInfo {
125    pub fn new(peer_punch_model: PunchPolicySet, peer_nat_info: NatInfo) -> Self {
126        Self {
127            peer_punch_model,
128            peer_nat_info,
129        }
130    }
131}
132
133#[derive(Clone, Debug)]
134pub struct PunchInfo {
135    pub(crate) punch_model: PunchModel,
136    pub(crate) peer_nat_info: NatInfo,
137}
138
139impl PunchInfo {
140    pub fn new(punch_model: PunchModel, peer_nat_info: NatInfo) -> Self {
141        Self {
142            punch_model,
143            peer_nat_info,
144        }
145    }
146}
147
148impl FromStr for PunchPolicy {
149    type Err = String;
150
151    fn from_str(s: &str) -> Result<Self, Self::Err> {
152        match s.to_lowercase().trim() {
153            "ipv4-tcp" => Ok(PunchPolicy::IPv4Tcp),
154            "ipv4-udp" => Ok(PunchPolicy::IPv4Udp),
155            "ipv6-tcp" => Ok(PunchPolicy::IPv6Tcp),
156            "ipv6-udp" => Ok(PunchPolicy::IPv6Udp),
157            _ => Err(format!(
158                "not match '{s}', enum: ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp"
159            )),
160        }
161    }
162}