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