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