rsip/common/
transport.rs

1#[doc(hidden)]
2pub use tokenizer::Tokenizer;
3
4use crate::{Error, Port, Scheme};
5
6/// Simple enum that holds the transport type used (for instance in the `Via` header).
7#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
8pub enum Transport {
9    Udp,
10    Tcp,
11    Tls,
12    TlsSctp,
13    Sctp,
14    Ws,
15    Wss,
16}
17
18impl Transport {
19    pub fn all() -> [Transport; 7] {
20        use Transport::*;
21
22        [Udp, Tcp, Tls, Sctp, TlsSctp, Ws, Wss]
23    }
24
25    pub fn protocols() -> [Transport; 4] {
26        use Transport::*;
27
28        [Udp, Tcp, Sctp, Ws]
29    }
30
31    pub fn secure_protocols() -> [Transport; 3] {
32        use Transport::*;
33
34        [Tcp, Sctp, Ws]
35    }
36
37    pub fn secure_transports() -> [Transport; 3] {
38        use Transport::*;
39
40        [Tls, TlsSctp, Wss]
41    }
42
43    pub fn default_secure_protocol() -> Self {
44        Transport::Tcp
45    }
46
47    pub fn default_insecure_protocol() -> Self {
48        Transport::Udp
49    }
50
51    pub fn default_secure_transport() -> Self {
52        Transport::Tls
53    }
54
55    pub fn default_insecure_transport() -> Self {
56        Transport::Udp
57    }
58
59    pub fn default_port(&self) -> Port {
60        match self {
61            Self::Udp => 5060.into(),
62            Self::Tcp => 5060.into(),
63            Self::Sctp => 5060.into(),
64            Self::TlsSctp => 5061.into(),
65            Self::Tls => 5061.into(),
66            Self::Ws => 80.into(),
67            Self::Wss => 443.into(),
68        }
69    }
70
71    pub fn protocol(&self) -> Self {
72        match self {
73            Self::Tls => Self::Tcp,
74            Self::TlsSctp => Self::Sctp,
75            Self::Wss => Self::Ws,
76            _ => *self,
77        }
78    }
79
80    pub fn is_secure(&self) -> bool {
81        Self::secure_transports().contains(self)
82    }
83
84    pub fn sip_scheme(&self) -> Scheme {
85        match self.is_secure() {
86            true => Scheme::Sips,
87            false => Scheme::Sip,
88        }
89    }
90}
91
92impl Default for Transport {
93    fn default() -> Self {
94        Self::Udp
95    }
96}
97
98impl std::fmt::Display for Transport {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        match self {
101            Self::Udp => write!(f, "UDP"),
102            Self::Tcp => write!(f, "TCP"),
103            Self::Tls => write!(f, "TLS"),
104            Self::Sctp => write!(f, "SCTP"),
105            Self::TlsSctp => write!(f, "TLS-SCTP"),
106            Self::Ws => write!(f, "WS"),
107            Self::Wss => write!(f, "WSS"),
108        }
109    }
110}
111
112impl std::str::FromStr for Transport {
113    type Err = crate::Error;
114
115    fn from_str(s: &str) -> Result<Self, Self::Err> {
116        use std::convert::TryFrom;
117
118        Self::try_from(Tokenizer::from(s))
119    }
120}
121
122impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a str, char>> for Transport {
123    type Error = Error;
124
125    fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a str, char>) -> Result<Self, Self::Error> {
126        match tokenizer.value {
127            part if part.eq_ignore_ascii_case("UDP") => Ok(Transport::Udp),
128            part if part.eq_ignore_ascii_case("TCP") => Ok(Transport::Tcp),
129            part if part.eq_ignore_ascii_case("TLS") => Ok(Transport::Tls),
130            part if part.eq_ignore_ascii_case("SCTP") => Ok(Transport::Sctp),
131            part if part.eq_ignore_ascii_case("TLS-SCTP") => Ok(Transport::TlsSctp),
132            part if part.eq_ignore_ascii_case("WS") => Ok(Transport::Ws),
133            part if part.eq_ignore_ascii_case("WSS") => Ok(Transport::Wss),
134            part => Err(Error::ParseError(format!("unknown transport: {}", part))),
135        }
136    }
137}
138
139impl<'a> std::convert::TryFrom<tokenizer::Tokenizer<'a, &'a [u8], u8>> for Transport {
140    type Error = Error;
141
142    fn try_from(tokenizer: tokenizer::Tokenizer<'a, &'a [u8], u8>) -> Result<Self, Self::Error> {
143        use std::str::from_utf8;
144
145        let value = from_utf8(tokenizer.value)?;
146
147        Self::try_from(Tokenizer::from(value))
148    }
149}
150
151#[doc(hidden)]
152mod tokenizer {
153    use crate::{AbstractInput, AbstractInputItem, GResult, GenericNomError, TokenizerError};
154    use std::marker::PhantomData;
155
156    #[derive(Debug, PartialEq, Eq, Clone)]
157    pub struct Tokenizer<'a, T, I>
158    where
159        T: AbstractInput<'a, I>,
160        I: AbstractInputItem<I>,
161    {
162        pub value: T,
163        phantom1: PhantomData<&'a T>,
164        phantom2: PhantomData<I>,
165    }
166
167    impl<'a, T, I> From<T> for Tokenizer<'a, T, I>
168    where
169        T: AbstractInput<'a, I>,
170        I: AbstractInputItem<I>,
171    {
172        fn from(value: T) -> Self {
173            Self {
174                value,
175                phantom1: Default::default(),
176                phantom2: Default::default(),
177            }
178        }
179    }
180
181    impl<'a, T, I> Tokenizer<'a, T, I>
182    where
183        T: AbstractInput<'a, I>,
184        I: AbstractInputItem<I>,
185    {
186        pub fn tokenize(part: T) -> GResult<T, Self> {
187            use nom::{branch::alt, bytes::complete::take_until1, combinator::rest};
188
189            let (rem, transport) =
190                alt((take_until1(" "), rest))(part).map_err(|_: GenericNomError<'a, T>| {
191                    TokenizerError::from(("transport", part)).into()
192                })?;
193
194            Ok((rem, Tokenizer::from(transport)))
195        }
196    }
197}
198
199#[cfg(feature = "test-utils")]
200impl testing_utils::Randomize for Transport {
201    fn random() -> Self {
202        testing_utils::sample(&Transport::protocols())
203    }
204}