1#![deny(missing_debug_implementations)]
12#![deny(missing_docs)]
13
14use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
46
47pub mod ffi;
48
49pub mod agent;
50pub mod candidate;
51pub mod component;
52pub mod stream;
53pub mod turn;
54
55pub use sans_io_time::Instant;
56
57pub mod prelude {
59 pub use crate::candidate::CandidateApi;
60}
61
62pub struct Address {
64 ffi: *mut crate::ffi::RiceAddress,
65}
66
67unsafe impl Send for Address {}
68unsafe impl Sync for Address {}
69
70impl core::fmt::Debug for Address {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 if self.ffi.is_null() {
73 f.debug_struct("Address").field("ffi", &self.ffi).finish()
74 } else {
75 f.debug_struct("Address")
76 .field("ffi", &self.ffi)
77 .field("value", &self.as_socket())
78 .finish()
79 }
80 }
81}
82
83impl Clone for Address {
84 fn clone(&self) -> Self {
85 Self {
86 ffi: unsafe { crate::ffi::rice_address_copy(self.ffi) },
87 }
88 }
89}
90
91impl Drop for Address {
92 fn drop(&mut self) {
93 unsafe { crate::ffi::rice_address_free(self.ffi) }
94 }
95}
96
97impl Address {
98 pub(crate) fn as_c(&self) -> *mut crate::ffi::RiceAddress {
99 self.ffi
100 }
101
102 pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceAddress {
103 let ret = self.ffi;
104 core::mem::forget(self);
105 ret
106 }
107
108 pub(crate) fn from_c_none(ffi: *const crate::ffi::RiceAddress) -> Self {
109 Self {
110 ffi: unsafe { crate::ffi::rice_address_copy(ffi) },
111 }
112 }
113
114 pub(crate) fn from_c_full(ffi: *mut crate::ffi::RiceAddress) -> Self {
115 Self { ffi }
116 }
117
118 pub fn as_socket(&self) -> SocketAddr {
120 self.into()
121 }
122}
123
124impl From<SocketAddr> for Address {
125 fn from(addr: SocketAddr) -> Self {
126 match addr.ip() {
127 IpAddr::V4(v4) => Self {
128 ffi: unsafe {
129 crate::ffi::rice_address_new_from_bytes(
130 crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
131 v4.octets().as_ptr(),
132 addr.port(),
133 )
134 },
135 },
136 IpAddr::V6(v6) => Self {
137 ffi: unsafe {
138 crate::ffi::rice_address_new_from_bytes(
139 crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
140 v6.octets().as_ptr(),
141 addr.port(),
142 )
143 },
144 },
145 }
146 }
147}
148
149impl From<&Address> for SocketAddr {
150 fn from(value: &Address) -> Self {
151 unsafe {
152 let port = crate::ffi::rice_address_get_port(value.ffi);
153 let ip = match crate::ffi::rice_address_get_family(value.ffi) {
154 crate::ffi::RICE_ADDRESS_FAMILY_IPV4 => {
155 let mut octets = [0; 4];
156 crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
157 IpAddr::V4(Ipv4Addr::from(octets))
158 }
159 crate::ffi::RICE_ADDRESS_FAMILY_IPV6 => {
160 let mut octets = [0; 16];
161 crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
162 IpAddr::V6(Ipv6Addr::from(octets))
163 }
164 val => panic!("Unknown address family value {val:x?}"),
165 };
166 SocketAddr::new(ip, port)
167 }
168 }
169}
170
171impl std::str::FromStr for Address {
172 type Err = std::net::AddrParseError;
173
174 fn from_str(s: &str) -> Result<Self, Self::Err> {
175 let addr: SocketAddr = s.parse()?;
176 Ok(Self::from(addr))
177 }
178}
179
180impl PartialEq<Address> for Address {
181 fn eq(&self, other: &Address) -> bool {
182 unsafe { crate::ffi::rice_address_cmp(self.ffi, other.ffi) == 0 }
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188#[repr(u32)]
189pub enum AddressFamily {
190 IPV4 = crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
192 IPV6 = crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
194}
195
196fn mut_override<T>(val: *const T) -> *mut T {
197 val as *mut T
198}
199
200fn const_override<T>(val: *mut T) -> *const T {
201 val as *const T
202}
203
204pub fn random_string(len: usize) -> String {
206 if len == 0 {
207 return String::new();
208 }
209 unsafe {
210 let ptr = crate::ffi::rice_random_string(len);
211 let s = core::ffi::CStr::from_ptr(ptr).to_str().unwrap();
212 let ret = s.to_string();
213 crate::ffi::rice_string_free(ptr);
214 ret
215 }
216}
217
218#[cfg(test)]
219pub(crate) mod tests {
220 use tracing::subscriber::DefaultGuard;
221 use tracing_subscriber::Layer;
222 use tracing_subscriber::layer::SubscriberExt;
223
224 pub fn test_init_log() -> DefaultGuard {
225 let level_filter = std::env::var("RICE_LOG")
226 .or(std::env::var("RUST_LOG"))
227 .ok()
228 .and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
229 .unwrap_or(
230 tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
231 );
232 let registry = tracing_subscriber::registry().with(
233 tracing_subscriber::fmt::layer()
234 .with_file(true)
235 .with_line_number(true)
236 .with_level(true)
237 .with_target(false)
238 .with_test_writer()
239 .with_filter(level_filter),
240 );
241 tracing::subscriber::set_default(registry)
242 }
243
244 #[test]
245 fn random_string() {
246 assert!(crate::random_string(0).is_empty());
247 assert_eq!(crate::random_string(4).len(), 4);
248 println!("{}", crate::random_string(128));
249 }
250}