#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
pub mod ffi;
pub mod agent;
pub mod candidate;
pub mod component;
pub mod stream;
pub mod turn;
pub use sans_io_time::Instant;
pub mod prelude {
pub use crate::candidate::CandidateApi;
}
pub struct Address {
ffi: *mut crate::ffi::RiceAddress,
}
unsafe impl Send for Address {}
unsafe impl Sync for Address {}
impl core::fmt::Debug for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.ffi.is_null() {
f.debug_struct("Address").field("ffi", &self.ffi).finish()
} else {
f.debug_struct("Address")
.field("ffi", &self.ffi)
.field("value", &self.as_socket())
.finish()
}
}
}
impl Clone for Address {
fn clone(&self) -> Self {
Self {
ffi: unsafe { crate::ffi::rice_address_copy(self.ffi) },
}
}
}
impl Drop for Address {
fn drop(&mut self) {
unsafe { crate::ffi::rice_address_free(self.ffi) }
}
}
impl Address {
pub(crate) fn as_c(&self) -> *mut crate::ffi::RiceAddress {
self.ffi
}
pub(crate) fn into_c_full(self) -> *mut crate::ffi::RiceAddress {
let ret = self.ffi;
core::mem::forget(self);
ret
}
pub(crate) fn from_c_none(ffi: *const crate::ffi::RiceAddress) -> Self {
Self {
ffi: unsafe { crate::ffi::rice_address_copy(ffi) },
}
}
pub(crate) fn from_c_full(ffi: *mut crate::ffi::RiceAddress) -> Self {
Self { ffi }
}
pub fn as_socket(&self) -> SocketAddr {
self.into()
}
}
impl From<SocketAddr> for Address {
fn from(addr: SocketAddr) -> Self {
match addr.ip() {
IpAddr::V4(v4) => Self {
ffi: unsafe {
crate::ffi::rice_address_new_from_bytes(
crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
v4.octets().as_ptr(),
addr.port(),
)
},
},
IpAddr::V6(v6) => Self {
ffi: unsafe {
crate::ffi::rice_address_new_from_bytes(
crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
v6.octets().as_ptr(),
addr.port(),
)
},
},
}
}
}
impl From<&Address> for SocketAddr {
fn from(value: &Address) -> Self {
unsafe {
let port = crate::ffi::rice_address_get_port(value.ffi);
let ip = match crate::ffi::rice_address_get_family(value.ffi) {
crate::ffi::RICE_ADDRESS_FAMILY_IPV4 => {
let mut octets = [0; 4];
crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
IpAddr::V4(Ipv4Addr::from(octets))
}
crate::ffi::RICE_ADDRESS_FAMILY_IPV6 => {
let mut octets = [0; 16];
crate::ffi::rice_address_get_address_bytes(value.ffi, octets.as_mut_ptr());
IpAddr::V6(Ipv6Addr::from(octets))
}
val => panic!("Unknown address family value {val:x?}"),
};
SocketAddr::new(ip, port)
}
}
}
impl std::str::FromStr for Address {
type Err = std::net::AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let addr: SocketAddr = s.parse()?;
Ok(Self::from(addr))
}
}
impl PartialEq<Address> for Address {
fn eq(&self, other: &Address) -> bool {
unsafe { crate::ffi::rice_address_cmp(self.ffi, other.ffi) == 0 }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum AddressFamily {
IPV4 = crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
IPV6 = crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
}
impl From<crate::ffi::RiceAddressFamily> for AddressFamily {
fn from(value: crate::ffi::RiceAddressFamily) -> Self {
match value {
crate::ffi::RICE_ADDRESS_FAMILY_IPV4 => Self::IPV4,
crate::ffi::RICE_ADDRESS_FAMILY_IPV6 => Self::IPV6,
val => panic!("Unknown address family value {val:x?}"),
}
}
}
impl From<AddressFamily> for crate::ffi::RiceAddressFamily {
fn from(value: AddressFamily) -> Self {
match value {
AddressFamily::IPV4 => crate::ffi::RICE_ADDRESS_FAMILY_IPV4,
AddressFamily::IPV6 => crate::ffi::RICE_ADDRESS_FAMILY_IPV6,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum IntegrityAlgorithm {
Sha1 = crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
Sha256 = crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
}
impl From<crate::ffi::RiceIntegrityAlgorithm> for IntegrityAlgorithm {
fn from(value: crate::ffi::RiceIntegrityAlgorithm) -> Self {
match value {
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1 => Self::Sha1,
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256 => Self::Sha256,
val => panic!("Unknown integrity algorithm value {val:x?}"),
}
}
}
impl From<IntegrityAlgorithm> for crate::ffi::RiceIntegrityAlgorithm {
fn from(value: IntegrityAlgorithm) -> Self {
match value {
IntegrityAlgorithm::Sha1 => crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
IntegrityAlgorithm::Sha256 => crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum Feature {
Disabled = crate::ffi::RICE_FEATURE_DISABLED,
Auto = crate::ffi::RICE_FEATURE_AUTO,
Required = crate::ffi::RICE_FEATURE_REQUIRED,
}
impl From<crate::ffi::RiceFeature> for Feature {
fn from(value: crate::ffi::RiceFeature) -> Self {
match value {
crate::ffi::RICE_FEATURE_DISABLED => Self::Disabled,
crate::ffi::RICE_FEATURE_AUTO => Self::Auto,
crate::ffi::RICE_FEATURE_REQUIRED => Self::Required,
val => panic!("Unknown feature value {val:x?}"),
}
}
}
impl From<Feature> for crate::ffi::RiceFeature {
fn from(value: Feature) -> Self {
match value {
Feature::Disabled => crate::ffi::RICE_FEATURE_DISABLED,
Feature::Auto => crate::ffi::RICE_FEATURE_AUTO,
Feature::Required => crate::ffi::RICE_FEATURE_REQUIRED,
}
}
}
fn mut_override<T>(val: *const T) -> *mut T {
val as *mut T
}
fn const_override<T>(val: *mut T) -> *const T {
val as *const T
}
pub fn random_string(len: usize) -> String {
if len == 0 {
return String::new();
}
unsafe {
let ptr = crate::ffi::rice_random_string(len);
let s = core::ffi::CStr::from_ptr(ptr).to_str().unwrap();
let ret = s.to_string();
crate::ffi::rice_string_free(ptr);
ret
}
}
#[cfg(test)]
pub(crate) mod tests {
use tracing::subscriber::DefaultGuard;
use tracing_subscriber::Layer;
use tracing_subscriber::layer::SubscriberExt;
use super::*;
pub fn test_init_log() -> DefaultGuard {
let level_filter = std::env::var("RICE_LOG")
.or(std::env::var("RUST_LOG"))
.ok()
.and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
.unwrap_or(
tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
);
let registry = tracing_subscriber::registry().with(
tracing_subscriber::fmt::layer()
.with_file(true)
.with_line_number(true)
.with_level(true)
.with_target(false)
.with_test_writer()
.with_filter(level_filter),
);
tracing::subscriber::set_default(registry)
}
#[test]
fn random_string() {
assert!(crate::random_string(0).is_empty());
assert_eq!(crate::random_string(4).len(), 4);
println!("{}", crate::random_string(128));
}
#[test]
fn enums() {
let _log = test_init_log();
for (c, r) in [
(crate::ffi::RICE_ADDRESS_FAMILY_IPV4, AddressFamily::IPV4),
(crate::ffi::RICE_ADDRESS_FAMILY_IPV6, AddressFamily::IPV6),
] {
assert_eq!(AddressFamily::from(c), r);
assert_eq!(crate::ffi::RiceAddressFamily::from(r), c);
}
for (c, r) in [
(
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
IntegrityAlgorithm::Sha1,
),
(
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
IntegrityAlgorithm::Sha256,
),
] {
assert_eq!(IntegrityAlgorithm::from(c), r);
assert_eq!(crate::ffi::RiceIntegrityAlgorithm::from(r), c);
}
for (c, r) in [
(
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA1,
IntegrityAlgorithm::Sha1,
),
(
crate::ffi::RICE_INTEGRITY_ALGORITHM_SHA256,
IntegrityAlgorithm::Sha256,
),
] {
assert_eq!(IntegrityAlgorithm::from(c), r);
assert_eq!(crate::ffi::RiceIntegrityAlgorithm::from(r), c);
}
for (c, r) in [
(crate::ffi::RICE_FEATURE_DISABLED, Feature::Disabled),
(crate::ffi::RICE_FEATURE_AUTO, Feature::Auto),
(crate::ffi::RICE_FEATURE_REQUIRED, Feature::Required),
] {
assert_eq!(Feature::from(c), r);
assert_eq!(crate::ffi::RiceFeature::from(r), c);
}
}
#[test]
#[should_panic = "Unknown feature value"]
fn feature_out_of_range() {
let _ = Feature::from(i32::MAX);
}
#[test]
#[should_panic = "Unknown address family value"]
fn address_family_out_of_range() {
let _ = AddressFamily::from(u32::MAX);
}
#[test]
#[should_panic = "Unknown integrity algorithm value"]
fn integrity_algorithm_out_of_range() {
let _ = IntegrityAlgorithm::from(u32::MAX);
}
}