1use crate::candidate::TransportType;
14use crate::{AddressFamily, Feature, IntegrityAlgorithm, 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(
48 client_transport: TransportType,
49 turn_server: crate::Address,
50 credentials: TurnCredentials,
51 ) -> Self {
52 unsafe {
53 let ffi = crate::ffi::rice_turn_config_new(
54 client_transport.into(),
55 const_override(turn_server.as_c()),
56 credentials.into_c_none(),
57 );
58 Self { ffi }
59 }
60 }
61
62 pub fn tls_config(&self) -> Option<TurnTlsConfig> {
64 unsafe {
65 let ret = crate::ffi::rice_turn_config_get_tls_config(self.ffi);
66 if ret.is_null() {
67 None
68 } else {
69 match crate::ffi::rice_tls_config_variant(ret) {
70 #[cfg(feature = "openssl")]
71 crate::ffi::RICE_TLS_VARIANT_OPENSSL => Some(TurnTlsConfig::Openssl(ret)),
72 #[cfg(feature = "rustls")]
73 crate::ffi::RICE_TLS_VARIANT_RUSTLS => Some(TurnTlsConfig::Rustls(ret)),
74 _ => None,
75 }
76 }
77 }
78 }
79
80 pub fn set_tls_config(&mut self, tls_config: TurnTlsConfig) {
82 unsafe {
83 crate::ffi::rice_turn_config_set_tls_config(self.ffi, tls_config.as_c());
84 }
85 }
86
87 pub fn addr(&self) -> crate::Address {
89 unsafe { crate::Address::from_c_full(crate::ffi::rice_turn_config_get_addr(self.ffi)) }
90 }
91
92 pub fn client_transport(&self) -> TransportType {
94 unsafe { crate::ffi::rice_turn_config_get_client_transport(self.ffi).into() }
95 }
96
97 pub fn set_allocation_transport(&mut self, allocation_transport: TransportType) {
99 unsafe {
100 crate::ffi::rice_turn_config_set_allocation_transport(
101 self.ffi,
102 allocation_transport.into(),
103 );
104 }
105 }
106
107 pub fn allocation_transport(&self) -> TransportType {
109 unsafe { crate::ffi::rice_turn_config_get_allocation_transport(self.ffi).into() }
110 }
111
112 pub fn add_address_family(&mut self, family: AddressFamily) {
116 unsafe {
117 crate::ffi::rice_turn_config_add_address_family(self.ffi, family.into());
118 }
119 }
120
121 pub fn set_address_family(&mut self, family: AddressFamily) {
125 unsafe {
126 crate::ffi::rice_turn_config_set_address_family(self.ffi, family.into());
127 }
128 }
129
130 pub fn address_families(&self) -> Vec<AddressFamily> {
132 unsafe {
133 let mut len = 0;
134 crate::ffi::rice_turn_config_get_address_families(
135 self.ffi,
136 &mut len,
137 core::ptr::null_mut(),
138 );
139 let mut ret = vec![AddressFamily::IPV4; len];
140 crate::ffi::rice_turn_config_get_address_families(
141 self.ffi,
142 &mut len,
143 ret.as_mut_ptr() as _,
144 );
145 ret.resize(len, AddressFamily::IPV4);
146 ret
147 }
148 }
149
150 pub fn credentials(&self) -> TurnCredentials {
152 unsafe {
153 TurnCredentials::from_c_full(crate::ffi::rice_turn_config_get_credentials(self.ffi))
154 }
155 }
156
157 pub fn add_supported_integrity(&mut self, integrity: IntegrityAlgorithm) {
159 unsafe {
160 crate::ffi::rice_turn_config_add_supported_integrity(self.ffi, integrity.into());
161 }
162 }
163
164 pub fn set_supported_integrity(&mut self, integrity: IntegrityAlgorithm) {
166 unsafe {
167 crate::ffi::rice_turn_config_set_supported_integrity(self.ffi, integrity.into());
168 }
169 }
170
171 pub fn supported_integrity(&self) -> Vec<IntegrityAlgorithm> {
173 unsafe {
174 let mut len = 0;
175 crate::ffi::rice_turn_config_get_supported_integrity(
176 self.ffi,
177 &mut len,
178 core::ptr::null_mut(),
179 );
180 let mut ret = vec![IntegrityAlgorithm::Sha1; len];
181 crate::ffi::rice_turn_config_get_supported_integrity(
182 self.ffi,
183 &mut len,
184 ret.as_mut_ptr() as _,
185 );
186 ret.resize(len, IntegrityAlgorithm::Sha1);
187 ret
188 }
189 }
190
191 pub fn set_anonymous_username(&mut self, anon: Feature) {
195 unsafe {
196 crate::ffi::rice_turn_config_set_anonymous_username(self.ffi, anon as _);
197 }
198 }
199
200 pub fn anonymous_username(&self) -> Feature {
204 unsafe { crate::ffi::rice_turn_config_get_anonymous_username(self.ffi).into() }
205 }
206
207 pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceTurnConfig {
208 let ret = self.ffi;
209 core::mem::forget(self);
210 ret
211 }
212}
213
214impl Clone for TurnConfig {
215 fn clone(&self) -> Self {
216 unsafe {
217 Self {
218 ffi: crate::ffi::rice_turn_config_copy(self.ffi),
219 }
220 }
221 }
222}
223
224impl Drop for TurnConfig {
225 fn drop(&mut self) {
226 unsafe {
227 crate::ffi::rice_turn_config_free(self.ffi);
228 }
229 }
230}
231
232#[derive(Debug)]
234pub enum TurnTlsConfig {
235 #[cfg(feature = "rustls")]
237 Rustls(*mut crate::ffi::RiceTlsConfig),
238 #[cfg(feature = "openssl")]
240 Openssl(*mut crate::ffi::RiceTlsConfig),
241 #[cfg(feature = "dimpl")]
243 Dimpl(*mut crate::ffi::RiceTlsConfig),
244}
245
246impl Clone for TurnTlsConfig {
247 fn clone(&self) -> Self {
248 match self {
249 #[cfg(feature = "dimpl")]
250 Self::Dimpl(cfg) => unsafe { Self::Rustls(crate::ffi::rice_tls_config_ref(*cfg)) },
251 #[cfg(feature = "rustls")]
252 Self::Rustls(cfg) => unsafe { Self::Rustls(crate::ffi::rice_tls_config_ref(*cfg)) },
253 #[cfg(feature = "openssl")]
254 Self::Openssl(cfg) => unsafe { Self::Openssl(crate::ffi::rice_tls_config_ref(*cfg)) },
255 }
256 }
257}
258
259impl Drop for TurnTlsConfig {
260 fn drop(&mut self) {
261 match self {
262 #[cfg(feature = "dimpl")]
263 Self::Dimpl(cfg) => unsafe { crate::ffi::rice_tls_config_unref(*cfg) },
264 #[cfg(feature = "rustls")]
265 Self::Rustls(cfg) => unsafe { crate::ffi::rice_tls_config_unref(*cfg) },
266 #[cfg(feature = "openssl")]
267 Self::Openssl(cfg) => unsafe { crate::ffi::rice_tls_config_unref(*cfg) },
268 }
269 }
270}
271
272impl TurnTlsConfig {
273 #[cfg(feature = "rustls")]
275 pub fn new_rustls_with_dns(server_name: &str) -> Self {
276 let server_str = std::ffi::CString::new(server_name).unwrap();
277 unsafe {
278 Self::Rustls(crate::ffi::rice_tls_config_new_rustls_with_dns(
279 server_str.as_ptr(),
280 ))
281 }
282 }
283
284 #[cfg(feature = "rustls")]
286 pub fn new_rustls_with_ip(addr: &crate::Address) -> Self {
287 unsafe { Self::Rustls(crate::ffi::rice_tls_config_new_rustls_with_ip(addr.as_c())) }
288 }
289
290 #[cfg(feature = "openssl")]
292 pub fn new_openssl(transport: TransportType) -> Self {
293 unsafe { Self::Openssl(crate::ffi::rice_tls_config_new_openssl(transport.into())) }
294 }
295
296 #[cfg(feature = "dimpl")]
298 pub fn new_dimpl() -> Self {
299 unsafe { Self::Dimpl(crate::ffi::rice_tls_config_new_dimpl()) }
300 }
301
302 pub(crate) fn as_c(&self) -> *mut crate::ffi::RiceTlsConfig {
303 #[allow(unreachable_patterns)]
304 let ret = match self {
305 #[cfg(feature = "dimpl")]
306 Self::Dimpl(cfg) => *cfg,
307 #[cfg(feature = "rustls")]
308 Self::Rustls(cfg) => *cfg,
309 #[cfg(feature = "openssl")]
310 Self::Openssl(cfg) => *cfg,
311 _ => core::ptr::null_mut(),
312 };
313 ret
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 use core::net::SocketAddr;
322
323 fn turn_server_address() -> crate::Address {
324 "127.0.0.1:3478".parse::<SocketAddr>().unwrap().into()
325 }
326
327 fn turn_credentials() -> TurnCredentials {
328 TurnCredentials::new("tuser", "tpass")
329 }
330
331 #[test]
332 fn test_config_getter() {
333 let mut cfg = TurnConfig::new(
334 TransportType::Udp,
335 turn_server_address(),
336 turn_credentials(),
337 );
338 assert_eq!(cfg.addr(), turn_server_address());
339 assert_eq!(cfg.client_transport(), TransportType::Udp);
340 assert_eq!(&cfg.address_families(), &[AddressFamily::IPV4]);
343 assert_eq!(cfg.allocation_transport(), TransportType::Udp);
344 assert_eq!(&cfg.supported_integrity(), &[IntegrityAlgorithm::Sha1]);
345 assert_eq!(cfg.anonymous_username(), Feature::Auto);
346 assert!(cfg.tls_config().is_none());
347
348 for transport in [TransportType::Udp, TransportType::Tcp] {
349 cfg.set_allocation_transport(transport);
350 assert_eq!(cfg.allocation_transport(), transport);
351 }
352
353 cfg.add_address_family(AddressFamily::IPV6);
354 assert_eq!(
355 &cfg.address_families(),
356 &[AddressFamily::IPV4, AddressFamily::IPV6]
357 );
358 cfg.set_address_family(AddressFamily::IPV6);
359 assert_eq!(&cfg.address_families(), &[AddressFamily::IPV6]);
360
361 cfg.add_supported_integrity(IntegrityAlgorithm::Sha256);
362 assert_eq!(
363 &cfg.supported_integrity(),
364 &[IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256]
365 );
366 cfg.set_supported_integrity(IntegrityAlgorithm::Sha256);
367 assert_eq!(&cfg.supported_integrity(), &[IntegrityAlgorithm::Sha256]);
368
369 for feat in [Feature::Disabled, Feature::Auto, Feature::Required] {
370 cfg.set_anonymous_username(feat);
371 assert_eq!(cfg.anonymous_username(), feat);
372 }
373 }
374
375 #[cfg(feature = "rustls")]
376 mod rustls {
377 use super::*;
378 #[test]
379 fn test_rustls_roundtrip() {
380 let dns = "turn.example.com";
381 let cfg = TurnTlsConfig::new_rustls_with_dns(dns);
382 drop(cfg);
383 let addr = "127.0.0.1:3478".parse::<SocketAddr>().unwrap();
384 let _cfg = TurnTlsConfig::new_rustls_with_ip(&addr.into());
385 }
386
387 #[test]
388 fn test_rustls_getter() {
389 let dns = "turn.example.com";
390 let tls = TurnTlsConfig::new_rustls_with_dns(dns);
391 let mut cfg = TurnConfig::new(
392 TransportType::Tcp,
393 turn_server_address(),
394 turn_credentials(),
395 );
396 cfg.set_tls_config(tls.clone());
397 let retrieved = cfg.tls_config().unwrap();
398 assert!(matches!(retrieved, TurnTlsConfig::Rustls(_)));
399 }
400 }
401
402 #[cfg(feature = "openssl")]
403 mod openssl {
404 use super::*;
405 #[test]
406 fn test_openssl_roundtrip() {
407 let _cfg = TurnTlsConfig::new_openssl(TransportType::Udp);
408 }
409
410 #[test]
411 fn test_openssl_getter() {
412 let tls = TurnTlsConfig::new_openssl(TransportType::Udp);
413 let mut cfg = TurnConfig::new(
414 TransportType::Udp,
415 turn_server_address(),
416 turn_credentials(),
417 );
418 cfg.set_tls_config(tls.clone());
419 let retrieved = cfg.tls_config().unwrap();
420 assert!(matches!(retrieved, TurnTlsConfig::Openssl(_)));
421 }
422 }
423}