1#![deny(missing_debug_implementations)]
12#![deny(missing_docs)]
13#![cfg_attr(docsrs, feature(doc_cfg))]
14
15use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
47
48pub mod ffi;
49
50pub mod agent;
51pub mod candidate;
52pub mod component;
53pub mod stream;
54pub mod turn;
55
56pub use sans_io_time::Instant;
57
58pub mod prelude {
60 pub use crate::candidate::CandidateApi;
61}
62
63pub struct Address {
65 ffi: *mut crate::ffi::RiceAddress,
66}
67
68unsafe impl Send for Address {}
69unsafe impl Sync for Address {}
70
71impl core::fmt::Debug for Address {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 if self.ffi.is_null() {
74 f.debug_struct("Address").field("ffi", &self.ffi).finish()
75 } else {
76 f.debug_struct("Address")
77 .field("ffi", &self.ffi)
78 .field("value", &self.as_socket())
79 .finish()
80 }
81 }
82}
83
84impl Clone for Address {
85 fn clone(&self) -> Self {
86 Self {
87 ffi: unsafe { crate::ffi::rice_address_copy(self.ffi) },
88 }
89 }
90}
91
92impl Drop for Address {
93 fn drop(&mut self) {
94 unsafe { crate::ffi::rice_address_free(self.ffi) }
95 }
96}
97
98impl Address {
99 pub(crate) fn as_c(&self) -> *mut crate::ffi::RiceAddress {
100 self.ffi
101 }
102
103 pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceAddress {
104 let ret = self.ffi;
105 core::mem::forget(self);
106 ret
107 }
108
109 pub(crate) fn from_c_none(ffi: *const crate::ffi::RiceAddress) -> Self {
110 Self {
111 ffi: unsafe { crate::ffi::rice_address_copy(ffi) },
112 }
113 }
114
115 pub(crate) fn from_c_full(ffi: *mut crate::ffi::RiceAddress) -> Self {
116 Self { ffi }
117 }
118
119 pub fn as_socket(&self) -> SocketAddr {
121 self.into()
122 }
123}
124
125impl From<SocketAddr> for Address {
126 fn from(addr: SocketAddr) -> Self {
127 match addr.ip() {
128 IpAddr::V4(v4) => Self {
129 ffi: unsafe {
130 crate::ffi::rice_address_new_from_bytes(
131 crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
132 v4.octets().as_ptr(),
133 addr.port(),
134 )
135 },
136 },
137 IpAddr::V6(v6) => Self {
138 ffi: unsafe {
139 crate::ffi::rice_address_new_from_bytes(
140 crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
141 v6.octets().as_ptr(),
142 addr.port(),
143 )
144 },
145 },
146 }
147 }
148}
149
150impl From<&Address> for SocketAddr {
151 fn from(value: &Address) -> Self {
152 unsafe {
153 let port = crate::ffi::rice_address_get_port(value.ffi);
154 let ip = match crate::ffi::rice_address_get_family(value.ffi) {
155 crate::ffi::RICE_ADDRESS_FAMILY_IPV4 => {
156 let mut octets = [0; 4];
157 crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
158 IpAddr::V4(Ipv4Addr::from(octets))
159 }
160 crate::ffi::RICE_ADDRESS_FAMILY_IPV6 => {
161 let mut octets = [0; 16];
162 crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
163 IpAddr::V6(Ipv6Addr::from(octets))
164 }
165 val => panic!("Unknown address family value {val:x?}"),
166 };
167 SocketAddr::new(ip, port)
168 }
169 }
170}
171
172impl std::str::FromStr for Address {
173 type Err = std::net::AddrParseError;
174
175 fn from_str(s: &str) -> Result<Self, Self::Err> {
176 let addr: SocketAddr = s.parse()?;
177 Ok(Self::from(addr))
178 }
179}
180
181impl PartialEq<Address> for Address {
182 fn eq(&self, other: &Address) -> bool {
183 unsafe { crate::ffi::rice_address_cmp(self.ffi, other.ffi) == 0 }
184 }
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189#[repr(u32)]
190pub enum AddressFamily {
191 IPV4 = crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
193 IPV6 = crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
195}
196
197impl From<crate::ffi::RiceAddressFamily> for AddressFamily {
198 fn from(value: crate::ffi::RiceAddressFamily) -> Self {
199 match value {
200 crate::ffi::RICE_ADDRESS_FAMILY_IPV4 => Self::IPV4,
201 crate::ffi::RICE_ADDRESS_FAMILY_IPV6 => Self::IPV6,
202 val => panic!("Unknown address family value {val:x?}"),
203 }
204 }
205}
206
207impl From<AddressFamily> for crate::ffi::RiceAddressFamily {
208 fn from(value: AddressFamily) -> Self {
209 match value {
210 AddressFamily::IPV4 => crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
211 AddressFamily::IPV6 => crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218#[repr(u32)]
219pub enum IntegrityAlgorithm {
220 Sha1 = crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
222 Sha256 = crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
224}
225
226impl From<crate::ffi::RiceIntegrityAlgorithm> for IntegrityAlgorithm {
227 fn from(value: crate::ffi::RiceIntegrityAlgorithm) -> Self {
228 match value {
229 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1 => Self::Sha1,
230 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256 => Self::Sha256,
231 val => panic!("Unknown integrity algorithm value {val:x?}"),
232 }
233 }
234}
235
236impl From<IntegrityAlgorithm> for crate::ffi::RiceIntegrityAlgorithm {
237 fn from(value: IntegrityAlgorithm) -> Self {
238 match value {
239 IntegrityAlgorithm::Sha1 => crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
240 IntegrityAlgorithm::Sha256 => crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247#[repr(i32)]
248pub enum Feature {
249 Disabled = crate::ffi::RICE_FEATURE_DISABLED,
251 Auto = crate::ffi::RICE_FEATURE_AUTO,
253 Required = crate::ffi::RICE_FEATURE_REQUIRED,
255}
256
257impl From<crate::ffi::RiceFeature> for Feature {
258 fn from(value: crate::ffi::RiceFeature) -> Self {
259 match value {
260 crate::ffi::RICE_FEATURE_DISABLED => Self::Disabled,
261 crate::ffi::RICE_FEATURE_AUTO => Self::Auto,
262 crate::ffi::RICE_FEATURE_REQUIRED => Self::Required,
263 val => panic!("Unknown feature value {val:x?}"),
264 }
265 }
266}
267
268impl From<Feature> for crate::ffi::RiceFeature {
269 fn from(value: Feature) -> Self {
270 match value {
271 Feature::Disabled => crate::ffi::RICE_FEATURE_DISABLED,
272 Feature::Auto => crate::ffi::RICE_FEATURE_AUTO,
273 Feature::Required => crate::ffi::RICE_FEATURE_REQUIRED,
274 }
275 }
276}
277
278fn mut_override<T>(val: *const T) -> *mut T {
279 val as *mut T
280}
281
282fn const_override<T>(val: *mut T) -> *const T {
283 val as *const T
284}
285
286pub fn random_string(len: usize) -> String {
288 if len == 0 {
289 return String::new();
290 }
291 unsafe {
292 let ptr = crate::ffi::rice_random_string(len);
293 let s = core::ffi::CStr::from_ptr(ptr).to_str().unwrap();
294 let ret = s.to_string();
295 crate::ffi::rice_string_free(ptr);
296 ret
297 }
298}
299
300#[cfg(test)]
301pub(crate) mod tests {
302 use tracing::subscriber::DefaultGuard;
303 use tracing_subscriber::Layer;
304 use tracing_subscriber::layer::SubscriberExt;
305
306 use super::*;
307
308 pub fn test_init_log() -> DefaultGuard {
309 let level_filter = std::env::var("RICE_LOG")
310 .or(std::env::var("RUST_LOG"))
311 .ok()
312 .and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
313 .unwrap_or(
314 tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
315 );
316 let registry = tracing_subscriber::registry().with(
317 tracing_subscriber::fmt::layer()
318 .with_file(true)
319 .with_line_number(true)
320 .with_level(true)
321 .with_target(false)
322 .with_test_writer()
323 .with_filter(level_filter),
324 );
325 tracing::subscriber::set_default(registry)
326 }
327
328 #[test]
329 fn random_string() {
330 assert!(crate::random_string(0).is_empty());
331 assert_eq!(crate::random_string(4).len(), 4);
332 println!("{}", crate::random_string(128));
333 }
334
335 #[test]
336 fn enums() {
337 let _log = test_init_log();
338
339 for (c, r) in [
340 (crate::ffi::RICE_ADDRESS_FAMILY_IPV4, AddressFamily::IPV4),
341 (crate::ffi::RICE_ADDRESS_FAMILY_IPV6, AddressFamily::IPV6),
342 ] {
343 assert_eq!(AddressFamily::from(c), r);
344 assert_eq!(crate::ffi::RiceAddressFamily::from(r), c);
345 }
346
347 for (c, r) in [
348 (
349 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
350 IntegrityAlgorithm::Sha1,
351 ),
352 (
353 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
354 IntegrityAlgorithm::Sha256,
355 ),
356 ] {
357 assert_eq!(IntegrityAlgorithm::from(c), r);
358 assert_eq!(crate::ffi::RiceIntegrityAlgorithm::from(r), c);
359 }
360
361 for (c, r) in [
362 (
363 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
364 IntegrityAlgorithm::Sha1,
365 ),
366 (
367 crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
368 IntegrityAlgorithm::Sha256,
369 ),
370 ] {
371 assert_eq!(IntegrityAlgorithm::from(c), r);
372 assert_eq!(crate::ffi::RiceIntegrityAlgorithm::from(r), c);
373 }
374
375 for (c, r) in [
376 (crate::ffi::RICE_FEATURE_DISABLED, Feature::Disabled),
377 (crate::ffi::RICE_FEATURE_AUTO, Feature::Auto),
378 (crate::ffi::RICE_FEATURE_REQUIRED, Feature::Required),
379 ] {
380 assert_eq!(Feature::from(c), r);
381 assert_eq!(crate::ffi::RiceFeature::from(r), c);
382 }
383 }
384
385 #[test]
386 #[should_panic = "Unknown feature value"]
387 fn feature_out_of_range() {
388 let _ = Feature::from(i32::MAX);
389 }
390
391 #[test]
392 #[should_panic = "Unknown address family value"]
393 fn address_family_out_of_range() {
394 let _ = AddressFamily::from(u32::MAX);
395 }
396
397 #[test]
398 #[should_panic = "Unknown integrity algorithm value"]
399 fn integrity_algorithm_out_of_range() {
400 let _ = IntegrityAlgorithm::from(u32::MAX);
401 }
402}