1use crate::candidate::TransportType;
14use crate::{AddressFamily, const_override};
15
16pub use crate::stream::Credentials as TurnCredentials;
17
18#[derive(Debug)]
20pub struct TurnConfig {
21 ffi: *mut crate::ffi::RiceTurnConfig,
22}
23
24unsafe impl Send for TurnConfig {}
25
26impl TurnConfig {
27 pub fn new(
51 client_transport: TransportType,
52 turn_server: crate::Address,
53 credentials: TurnCredentials,
54 allocation_transport: TransportType,
55 families: &[AddressFamily],
56 tls_config: Option<TurnTlsConfig>,
57 ) -> Self {
58 unsafe {
59 let tls_config = if let Some(tls_config) = tls_config {
60 tls_config.into_c_full()
61 } else {
62 core::ptr::null_mut()
63 };
64 let families = families
65 .iter()
66 .map(|&family| family as u32)
67 .collect::<Vec<_>>();
68 let ffi = crate::ffi::rice_turn_config_new(
69 client_transport.into(),
70 const_override(turn_server.as_c()),
71 credentials.into_c_none(),
72 allocation_transport.into(),
73 families.len(),
74 families.as_ptr(),
75 tls_config,
76 );
77 Self { ffi }
78 }
79 }
80
81 pub fn tls_config(&self) -> Option<TurnTlsConfig> {
83 unsafe {
84 let ret = crate::ffi::rice_turn_config_get_tls_config(self.ffi);
85 if ret.is_null() {
86 None
87 } else {
88 match crate::ffi::rice_tls_config_variant(ret) {
89 #[cfg(feature = "openssl")]
90 crate::ffi::RICE_TLS_VARIANT_OPENSSL => Some(TurnTlsConfig::Openssl(ret)),
91 #[cfg(feature = "rustls")]
92 crate::ffi::RICE_TLS_VARIANT_RUSTLS => Some(TurnTlsConfig::Rustls(ret)),
93 _ => None,
94 }
95 }
96 }
97 }
98
99 pub fn addr(&self) -> crate::Address {
101 unsafe { crate::Address::from_c_full(crate::ffi::rice_turn_config_get_addr(self.ffi)) }
102 }
103
104 pub fn client_transport(&self) -> TransportType {
106 unsafe { crate::ffi::rice_turn_config_get_client_transport(self.ffi).into() }
107 }
108
109 pub fn credentials(&self) -> TurnCredentials {
111 unsafe {
112 TurnCredentials::from_c_full(crate::ffi::rice_turn_config_get_credentials(self.ffi))
113 }
114 }
115
116 pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceTurnConfig {
117 let ret = self.ffi;
118 core::mem::forget(self);
119 ret
120 }
121}
122
123impl Clone for TurnConfig {
124 fn clone(&self) -> Self {
125 unsafe {
126 Self {
127 ffi: crate::ffi::rice_turn_config_ref(self.ffi),
128 }
129 }
130 }
131}
132
133impl Drop for TurnConfig {
134 fn drop(&mut self) {
135 unsafe {
136 crate::ffi::rice_turn_config_unref(self.ffi);
137 }
138 }
139}
140
141#[derive(Debug)]
143pub enum TurnTlsConfig {
144 #[cfg(feature = "rustls")]
146 Rustls(*mut crate::ffi::RiceTlsConfig),
147 #[cfg(feature = "openssl")]
149 Openssl(*mut crate::ffi::RiceTlsConfig),
150}
151
152impl Clone for TurnTlsConfig {
153 fn clone(&self) -> Self {
154 match self {
155 #[cfg(feature = "rustls")]
156 Self::Rustls(cfg) => unsafe { Self::Rustls(crate::ffi::rice_tls_config_ref(*cfg)) },
157 #[cfg(feature = "openssl")]
158 Self::Openssl(cfg) => unsafe { Self::Openssl(crate::ffi::rice_tls_config_ref(*cfg)) },
159 }
160 }
161}
162
163impl Drop for TurnTlsConfig {
164 fn drop(&mut self) {
165 match self {
166 #[cfg(feature = "rustls")]
167 Self::Rustls(cfg) => unsafe { crate::ffi::rice_tls_config_unref(*cfg) },
168 #[cfg(feature = "openssl")]
169 Self::Openssl(cfg) => unsafe { crate::ffi::rice_tls_config_unref(*cfg) },
170 }
171 }
172}
173
174impl TurnTlsConfig {
175 #[cfg(feature = "rustls")]
177 pub fn new_rustls_with_dns(server_name: &str) -> Self {
178 let server_str = std::ffi::CString::new(server_name).unwrap();
179 unsafe {
180 Self::Rustls(crate::ffi::rice_tls_config_new_rustls_with_dns(
181 server_str.as_ptr(),
182 ))
183 }
184 }
185
186 #[cfg(feature = "rustls")]
188 pub fn new_rustls_with_ip(addr: &crate::Address) -> Self {
189 unsafe { Self::Rustls(crate::ffi::rice_tls_config_new_rustls_with_ip(addr.as_c())) }
190 }
191
192 #[cfg(feature = "openssl")]
194 pub fn new_openssl(transport: TransportType) -> Self {
195 unsafe { Self::Openssl(crate::ffi::rice_tls_config_new_openssl(transport.into())) }
196 }
197
198 pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceTlsConfig {
199 #[allow(unreachable_patterns)]
200 let ret = match self {
201 #[cfg(feature = "rustls")]
202 Self::Rustls(cfg) => cfg,
203 #[cfg(feature = "openssl")]
204 Self::Openssl(cfg) => cfg,
205 _ => core::ptr::null_mut(),
206 };
207 core::mem::forget(self);
208 ret
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 use core::net::SocketAddr;
217
218 fn turn_server_address() -> crate::Address {
219 "127.0.0.1:3478".parse::<SocketAddr>().unwrap().into()
220 }
221
222 fn turn_credentials() -> TurnCredentials {
223 TurnCredentials::new("tuser", "tpass")
224 }
225
226 #[test]
227 fn test_config_getter() {
228 let cfg = TurnConfig::new(
229 TransportType::Udp,
230 turn_server_address(),
231 turn_credentials(),
232 TransportType::Udp,
233 &[AddressFamily::IPV4],
234 None,
235 );
236 assert_eq!(cfg.addr(), turn_server_address());
237 assert_eq!(cfg.client_transport(), TransportType::Udp);
238 assert!(cfg.tls_config().is_none());
241 }
242
243 #[cfg(feature = "rustls")]
244 mod rustls {
245 use super::*;
246 #[test]
247 fn test_rustls_roundtrip() {
248 let dns = "turn.example.com";
249 let cfg = TurnTlsConfig::new_rustls_with_dns(dns);
250 drop(cfg);
251 let addr = "127.0.0.1:3478".parse::<SocketAddr>().unwrap();
252 let _cfg = TurnTlsConfig::new_rustls_with_ip(&addr.into());
253 }
254
255 #[test]
256 fn test_rustls_getter() {
257 let dns = "turn.example.com";
258 let tls = TurnTlsConfig::new_rustls_with_dns(dns);
259 let cfg = TurnConfig::new(
260 TransportType::Tcp,
261 turn_server_address(),
262 turn_credentials(),
263 TransportType::Udp,
264 &[AddressFamily::IPV4],
265 Some(tls.clone()),
266 );
267 let retrieved = cfg.tls_config().unwrap();
268 assert!(matches!(retrieved, TurnTlsConfig::Rustls(_)));
269 }
270 }
271
272 #[cfg(feature = "openssl")]
273 mod openssl {
274 use super::*;
275 #[test]
276 fn test_openssl_roundtrip() {
277 let _cfg = TurnTlsConfig::new_openssl(TransportType::Udp);
278 }
279
280 #[test]
281 fn test_openssl_getter() {
282 let tls = TurnTlsConfig::new_openssl(TransportType::Udp);
283 let cfg = TurnConfig::new(
284 TransportType::Udp,
285 turn_server_address(),
286 turn_credentials(),
287 TransportType::Udp,
288 &[AddressFamily::IPV4],
289 Some(tls),
290 );
291 let retrieved = cfg.tls_config().unwrap();
292 assert!(matches!(retrieved, TurnTlsConfig::Openssl(_)));
293 }
294 }
295}