#![allow(clippy::missing_safety_doc)]
#![deny(improper_ctypes_definitions)]
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_void};
use core::mem::MaybeUninit;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, Mutex, Once, Weak};
use std::time::{Duration, Instant};
use crate::agent::AgentPoll;
use crate::agent::TurnCredentials;
use crate::agent::{Agent, AgentError};
use crate::candidate::{Candidate, CandidatePair, CandidateType, TransportType};
use crate::component::ComponentConnectionState;
use crate::gathering::GatheredCandidate;
use crate::stream::Credentials;
use stun_proto::agent::{StunError, Transmit};
use stun_proto::types::data::{Data, DataOwned, DataSlice};
use turn_client_proto::client::TurnClient;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::Layer;
static TRACING: Once = Once::new();
fn init_logs() {
TRACING.call_once(|| {
let level_filter = std::env::var("RICE_LOG")
.ok()
.and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
.unwrap_or(
tracing_subscriber::filter::Targets::new().with_default(tracing::Level::ERROR),
);
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),
);
let _ = tracing::subscriber::set_global_default(registry);
});
}
#[no_mangle]
pub unsafe extern "C" fn rice_version(major: *mut u32, minor: *mut u32, patch: *mut u32) {
if !major.is_null() {
*major = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap();
}
if !minor.is_null() {
*minor = env!("CARGO_PKG_VERSION_MINOR").parse().unwrap();
}
if !patch.is_null() {
*patch = env!("CARGO_PKG_VERSION_PATCH").parse().unwrap();
}
}
#[repr(i32)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum RiceError {
Success = 0,
Failed = -1,
ResourceNotFound = -2,
AlreadyInProgress = -3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RiceTransportType {
Udp,
Tcp,
}
impl From<TransportType> for RiceTransportType {
fn from(value: TransportType) -> Self {
match value {
TransportType::Udp => Self::Udp,
TransportType::Tcp => Self::Tcp,
}
}
}
impl From<RiceTransportType> for TransportType {
fn from(value: RiceTransportType) -> Self {
match value {
RiceTransportType::Udp => Self::Udp,
RiceTransportType::Tcp => Self::Tcp,
}
}
}
#[derive(Debug)]
struct RiceAgentInner {
stun_servers: Vec<(TransportType, SocketAddr)>,
turn_servers: Vec<(TransportType, SocketAddr, TurnCredentials)>,
streams: Vec<Arc<RiceStream>>,
}
#[derive(Debug)]
pub struct RiceAgent {
proto_agent: Arc<Mutex<Agent>>,
inner: Arc<Mutex<RiceAgentInner>>,
base_instant: Instant,
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_new(controlling: bool, trickle_ice: bool) -> *mut RiceAgent {
init_logs();
let proto_agent = Arc::new(Mutex::new(
Agent::builder()
.trickle_ice(trickle_ice)
.controlling(controlling)
.build(),
));
let agent = Arc::new(RiceAgent {
proto_agent,
inner: Arc::new(Mutex::new(RiceAgentInner {
stun_servers: vec![],
turn_servers: vec![],
streams: vec![],
})),
base_instant: Instant::now(),
});
mut_override(Arc::into_raw(agent))
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_ref(agent: *mut RiceAgent) -> *mut RiceAgent {
Arc::increment_strong_count(agent);
agent
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_unref(agent: *mut RiceAgent) {
Arc::decrement_strong_count(agent)
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_close(agent: *mut RiceAgent, now_micros: u64) {
let agent = Arc::from_raw(agent);
let mut proto_agent = agent.proto_agent.lock().unwrap();
let now = agent.base_instant + Duration::from_micros(now_micros);
proto_agent.close(now);
drop(proto_agent);
core::mem::forget(agent);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_id(agent: *mut RiceAgent) -> u64 {
let agent = Arc::from_raw(agent);
let proto_agent = agent.proto_agent.lock().unwrap();
let ret = proto_agent.id();
drop(proto_agent);
core::mem::forget(agent);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_get_controlling(agent: *mut RiceAgent) -> bool {
let agent = Arc::from_raw(agent);
let proto_agent = agent.proto_agent.lock().unwrap();
let ret = proto_agent.controlling();
drop(proto_agent);
core::mem::forget(agent);
ret
}
#[derive(Debug)]
#[repr(C)]
pub enum RiceAgentPoll {
Closed,
WaitUntilMicros(u64),
AllocateSocket(RiceAgentSocket),
RemoveSocket(RiceAgentSocket),
SelectedPair(RiceAgentSelectedPair),
ComponentStateChange(RiceAgentComponentStateChange),
GatheredCandidate(RiceAgentGatheredCandidate),
GatheringComplete(RiceAgentGatheringComplete),
}
impl RiceAgentPoll {
fn into_c_full(poll: AgentPoll, base_instant: Instant) -> Self {
match poll {
AgentPoll::Closed => Self::Closed,
AgentPoll::WaitUntil(instant) => Self::WaitUntilMicros(
instant.saturating_duration_since(base_instant).as_micros() as u64,
),
AgentPoll::AllocateSocket(connect) => {
Self::AllocateSocket(RiceAgentSocket::into_c_full(connect))
}
AgentPoll::RemoveSocket(connect) => {
Self::RemoveSocket(RiceAgentSocket::into_c_full(connect))
}
AgentPoll::SelectedPair(pair) => {
Self::SelectedPair(RiceAgentSelectedPair::into_c_full(pair))
}
AgentPoll::ComponentStateChange(state) => Self::ComponentStateChange(state.into()),
AgentPoll::GatheredCandidate(gathered) => {
Self::GatheredCandidate(RiceAgentGatheredCandidate::into_c_full(gathered))
}
AgentPoll::GatheringComplete(complete) => Self::GatheringComplete(complete.into()),
}
}
}
#[derive(Debug)]
#[repr(C)]
pub enum RiceData {
Borrowed(RiceDataImpl),
Owned(RiceDataImpl),
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceDataImpl {
ptr: *mut u8,
size: usize,
}
impl RiceDataImpl {
unsafe fn owned_from_c(self) -> Box<[u8]> {
Box::from_raw(core::slice::from_raw_parts_mut(self.ptr, self.size))
}
fn owned_to_c(val: Box<[u8]>) -> Self {
let size = val.len();
let ptr = Box::into_raw(val) as *mut _;
Self { ptr, size }
}
unsafe fn borrowed_from_c<'a>(self) -> &'a [u8] {
core::slice::from_raw_parts_mut(self.ptr, self.size)
}
fn borrowed_to_c(val: &[u8]) -> Self {
Self {
ptr: mut_override(val.as_ptr()),
size: val.len(),
}
}
}
impl Default for RiceDataImpl {
fn default() -> Self {
Self {
ptr: core::ptr::null_mut(),
size: 0,
}
}
}
impl<'a> From<Data<'a>> for RiceData {
fn from(value: Data<'a>) -> Self {
match value {
Data::Borrowed(slice) => Self::Borrowed(RiceDataImpl::borrowed_to_c(&slice)),
Data::Owned(owned) => Self::Owned(RiceDataImpl::owned_to_c(owned.into())),
}
}
}
impl<'a> From<RiceData> for Data<'a> {
fn from(value: RiceData) -> Self {
unsafe {
match value {
RiceData::Borrowed(imp) => Self::Borrowed(DataSlice::from(imp.borrowed_from_c())),
RiceData::Owned(imp) => Self::Owned(DataOwned::from(imp.owned_from_c())),
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_data_len(data: *const RiceData) -> usize {
match &*data {
RiceData::Borrowed(imp) => imp.size,
RiceData::Owned(imp) => imp.size,
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_data_ptr(data: *const RiceData) -> *mut u8 {
match &*data {
RiceData::Borrowed(imp) => imp.ptr,
RiceData::Owned(imp) => imp.ptr,
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceTransmit {
stream_id: usize,
transport: RiceTransportType,
from: *const RiceAddress,
to: *const RiceAddress,
data: RiceDataImpl,
}
impl Default for RiceTransmit {
fn default() -> Self {
Self {
stream_id: 0,
transport: RiceTransportType::Udp,
from: core::ptr::null(),
to: core::ptr::null(),
data: RiceDataImpl::default(),
}
}
}
impl RiceTransmit {
fn into_c_full(value: crate::agent::AgentTransmit) -> Self {
let from = Box::new(RiceAddress::new(value.transmit.from));
let to = Box::new(RiceAddress::new(value.transmit.to));
Self {
stream_id: value.stream_id,
transport: value.transmit.transport.into(),
from: Box::into_raw(from),
to: Box::into_raw(to),
data: RiceDataImpl::owned_to_c(value.transmit.data),
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_transmit_clear(transmit: *mut RiceTransmit) {
if !(*transmit).from.is_null() {
let _from = RiceAddress::into_rice_full((*transmit).from);
(*transmit).from = core::ptr::null_mut();
}
if !(*transmit).to.is_null() {
let _to = RiceAddress::into_rice_full((*transmit).to);
(*transmit).to = core::ptr::null_mut();
}
let mut data = RiceDataImpl::default();
core::mem::swap(&mut data, &mut (*transmit).data);
if !data.ptr.is_null() {
let _data = RiceDataImpl::owned_from_c(data);
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_transmit_init(transmit: *mut MaybeUninit<RiceTransmit>) {
(*transmit).write(RiceTransmit::default());
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceAgentSocket {
pub stream_id: usize,
pub component_id: usize,
pub transport: RiceTransportType,
pub from: *const RiceAddress,
pub to: *const RiceAddress,
}
impl RiceAgentSocket {
fn into_c_full(value: crate::agent::AgentSocket) -> Self {
Self {
stream_id: value.stream_id,
component_id: value.component_id,
transport: value.transport.into(),
from: Box::into_raw(Box::new(RiceAddress::new(value.from))),
to: Box::into_raw(Box::new(RiceAddress::new(value.to))),
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceAgentSelectedPair {
stream_id: usize,
component_id: usize,
local: RiceCandidate,
remote: RiceCandidate,
}
impl RiceAgentSelectedPair {
fn into_c_full(value: crate::agent::AgentSelectedPair) -> Self {
let pair = value.selected.candidate_pair().clone();
Self {
stream_id: value.stream_id,
component_id: value.component_id,
local: RiceCandidate::into_c_full(pair.local),
remote: RiceCandidate::into_c_full(pair.remote),
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceAgentComponentStateChange {
pub stream_id: usize,
pub component_id: usize,
pub state: ComponentConnectionState,
}
impl From<crate::agent::AgentComponentStateChange> for RiceAgentComponentStateChange {
fn from(value: crate::agent::AgentComponentStateChange) -> Self {
Self {
stream_id: value.stream_id,
component_id: value.component_id,
state: value.state,
}
}
}
impl From<RiceAgentComponentStateChange> for crate::agent::AgentComponentStateChange {
fn from(value: RiceAgentComponentStateChange) -> Self {
Self {
stream_id: value.stream_id,
component_id: value.component_id,
state: value.state,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceAgentGatheredCandidate {
pub stream_id: usize,
pub gathered: RiceGatheredCandidate,
}
impl RiceAgentGatheredCandidate {
fn into_c_full(value: crate::agent::AgentGatheredCandidate) -> Self {
Self {
stream_id: value.stream_id,
gathered: RiceGatheredCandidate::into_c_full(value.gathered),
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceAgentGatheringComplete {
pub stream_id: usize,
pub component_id: usize,
}
impl From<crate::agent::AgentGatheringComplete> for RiceAgentGatheringComplete {
fn from(value: crate::agent::AgentGatheringComplete) -> Self {
Self {
stream_id: value.stream_id,
component_id: value.component_id,
}
}
}
impl From<RiceAgentGatheringComplete> for crate::agent::AgentGatheringComplete {
fn from(value: RiceAgentGatheringComplete) -> Self {
Self {
stream_id: value.stream_id,
component_id: value.component_id,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_poll_init(poll: *mut MaybeUninit<RiceAgentPoll>) {
(*poll).write(RiceAgentPoll::Closed);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_poll_clear(poll: *mut RiceAgentPoll) {
let mut other = RiceAgentPoll::Closed;
core::ptr::swap(&mut other, poll);
match other {
RiceAgentPoll::Closed
| RiceAgentPoll::ComponentStateChange(_)
| RiceAgentPoll::WaitUntilMicros(_)
| RiceAgentPoll::GatheringComplete(_) => (),
RiceAgentPoll::AllocateSocket(mut connect) => {
let mut from = core::ptr::null();
core::mem::swap(&mut from, &mut connect.from);
let _from = RiceAddress::into_rice_full(from);
let mut to = core::ptr::null();
core::mem::swap(&mut to, &mut connect.to);
let _to = RiceAddress::into_rice_full(to);
}
RiceAgentPoll::RemoveSocket(mut connect) => {
let mut from = core::ptr::null();
core::mem::swap(&mut from, &mut connect.from);
let _from = RiceAddress::into_rice_full(from);
let mut to = core::ptr::null();
core::mem::swap(&mut to, &mut connect.to);
let _to = RiceAddress::into_rice_full(to);
}
RiceAgentPoll::SelectedPair(mut pair) => {
rice_candidate_clear(&mut pair.local);
rice_candidate_clear(&mut pair.remote);
}
RiceAgentPoll::GatheredCandidate(mut gathered) => {
let turn = gathered.gathered.turn_agent;
gathered.gathered.turn_agent = core::ptr::null_mut();
let _turn_agent = if turn.is_null() {
None
} else {
Some(Box::from_raw(turn as *mut TurnClient))
};
rice_candidate_clear(&mut gathered.gathered.candidate);
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_poll(
agent: *mut RiceAgent,
now_micros: u64,
poll: *mut RiceAgentPoll,
) {
let agent = Arc::from_raw(agent);
let mut proto_agent = agent.proto_agent.lock().unwrap();
let now = agent.base_instant + Duration::from_micros(now_micros);
let ret = proto_agent.poll(now);
if let AgentPoll::SelectedPair(ref pair) = ret {
if let Some(mut stream) = proto_agent.mut_stream(pair.stream_id) {
if let Some(mut component) = stream.mut_component(pair.component_id) {
component.set_selected_pair_with_agent((*pair.selected).clone());
}
}
}
*poll = RiceAgentPoll::into_c_full(ret, agent.base_instant);
drop(proto_agent);
core::mem::forget(agent);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_poll_transmit(
agent: *mut RiceAgent,
now_micros: u64,
transmit: *mut RiceTransmit,
) {
let agent = Arc::from_raw(agent);
let mut proto_agent = agent.proto_agent.lock().unwrap();
let now = agent.base_instant + Duration::from_micros(now_micros);
if let Some(ret) = proto_agent.poll_transmit(now) {
*transmit = RiceTransmit::into_c_full(ret);
} else {
*transmit = RiceTransmit::default();
}
drop(proto_agent);
core::mem::forget(agent);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_add_stun_server(
agent: *mut RiceAgent,
transport: RiceTransportType,
addr: *const RiceAddress,
) {
let agent = Arc::from_raw(agent);
let addr = Box::from_raw(mut_override(addr));
let mut inner = agent.inner.lock().unwrap();
inner.stun_servers.push((transport.into(), **addr));
drop(inner);
core::mem::forget(addr);
core::mem::forget(agent);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_add_turn_server(
agent: *mut RiceAgent,
transport: RiceTransportType,
addr: *const RiceAddress,
credentials: *const RiceCredentials,
) {
let creds = Box::from_raw(mut_override(credentials));
let agent = Arc::from_raw(agent);
let addr = Box::from_raw(mut_override(addr));
let mut inner = agent.inner.lock().unwrap();
inner.turn_servers.push((
transport.into(),
**addr,
TurnCredentials::new(&creds.credentials.ufrag, &creds.credentials.passwd),
));
drop(inner);
core::mem::forget(addr);
core::mem::forget(agent);
core::mem::forget(creds);
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_now(agent: *mut RiceAgent) -> u64 {
let agent = Arc::from_raw(agent);
let ret = Instant::now()
.saturating_duration_since(agent.base_instant)
.as_micros() as u64;
core::mem::forget(agent);
ret
}
#[derive(Debug)]
pub struct RiceStream {
proto_agent: Arc<Mutex<Agent>>,
weak_agent: Weak<Mutex<RiceAgentInner>>,
inner: Arc<Mutex<RiceStreamInner>>,
base_instant: Instant,
stream_id: usize,
}
#[derive(Debug)]
struct RiceStreamInner {
components: Vec<Arc<RiceComponent>>,
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_add_stream(agent: *mut RiceAgent) -> *mut RiceStream {
let agent = Arc::from_raw(agent);
let mut proto_agent = agent.proto_agent.lock().unwrap();
let stream_id = proto_agent.add_stream();
let stream = Arc::new(RiceStream {
proto_agent: agent.proto_agent.clone(),
weak_agent: Arc::downgrade(&agent.inner),
inner: Arc::new(Mutex::new(RiceStreamInner { components: vec![] })),
base_instant: agent.base_instant,
stream_id,
});
drop(proto_agent);
let mut inner = agent.inner.lock().unwrap();
inner.streams.push(stream.clone());
drop(inner);
core::mem::forget(agent);
mut_override(Arc::into_raw(stream))
}
#[no_mangle]
pub unsafe extern "C" fn rice_agent_get_stream(
agent: *mut RiceAgent,
stream_id: usize,
) -> *mut RiceStream {
let agent = Arc::from_raw(agent);
let inner = agent.inner.lock().unwrap();
let ret = if let Some(stream) = inner.streams.get(stream_id) {
mut_override(Arc::into_raw(stream.clone()))
} else {
mut_override(std::ptr::null::<RiceStream>())
};
drop(inner);
core::mem::forget(agent);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_ref(stream: *mut RiceStream) -> *mut RiceStream {
Arc::increment_strong_count(stream);
stream
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_unref(stream: *mut RiceStream) {
Arc::decrement_strong_count(stream)
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_get_id(stream: *mut RiceStream) -> usize {
let stream = Arc::from_raw(stream);
let ret = stream.stream_id;
core::mem::forget(stream);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_handle_allocated_socket(
stream: *mut RiceStream,
component_id: usize,
transport: RiceTransportType,
from: *const RiceAddress,
to: *const RiceAddress,
socket_addr: *mut RiceAddress,
) {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let from = RiceAddress::into_rice_none(from);
let to = RiceAddress::into_rice_none(to);
let socket = if socket_addr.is_null() {
Err(StunError::ResourceNotFound)
} else {
Ok(**RiceAddress::into_rice_full(socket_addr))
};
proto_stream.allocated_socket(component_id, transport.into(), from.0, to.0, socket);
drop(proto_agent);
core::mem::forget(stream);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_now(stream: *mut RiceStream) -> u64 {
let stream = Arc::from_raw(stream);
let ret = Instant::now()
.saturating_duration_since(stream.base_instant)
.as_micros() as u64;
core::mem::forget(stream);
ret
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct RiceCredentials {
credentials: Credentials,
}
#[no_mangle]
pub unsafe extern "C" fn rice_credentials_new(
ufrag: *const c_char,
passwd: *const c_char,
) -> *mut RiceCredentials {
let ufrag = string_from_c(ufrag);
let passwd = string_from_c(passwd);
Box::into_raw(Box::new(RiceCredentials {
credentials: Credentials::new(ufrag, passwd),
}))
}
#[no_mangle]
pub unsafe extern "C" fn rice_credentials_copy(
creds: *const RiceCredentials,
) -> *mut RiceCredentials {
let creds = Box::from_raw(mut_override(creds));
let ret = creds.clone();
core::mem::forget(creds);
Box::into_raw(ret)
}
#[no_mangle]
pub unsafe extern "C" fn rice_credentials_free(credentials: *mut RiceCredentials) {
let _ = Box::from_raw(credentials);
}
#[no_mangle]
pub unsafe extern "C" fn rice_credentials_eq(
creds1: *const RiceCredentials,
creds2: *const RiceCredentials,
) -> bool {
match (creds1.is_null(), creds2.is_null()) {
(true, true) => true,
(true, false) => false,
(false, true) => false,
(false, false) => {
let creds1 = Box::from_raw(mut_override(creds1));
let creds2 = Box::from_raw(mut_override(creds2));
let ret = creds1.credentials == creds2.credentials;
core::mem::forget(creds1);
core::mem::forget(creds2);
ret
}
}
}
fn credentials_to_c(credentials: Credentials) -> *mut RiceCredentials {
Box::into_raw(Box::new(RiceCredentials { credentials }))
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_get_local_credentials(
stream: *mut RiceStream,
) -> *mut RiceCredentials {
let stream = Arc::from_raw(stream);
let proto_agent = stream.proto_agent.lock().unwrap();
let proto_stream = proto_agent.stream(stream.stream_id).unwrap();
let ret = if let Some(credentials) = proto_stream.local_credentials() {
credentials_to_c(credentials)
} else {
mut_override(std::ptr::null::<RiceCredentials>())
};
drop(proto_agent);
core::mem::forget(stream);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_get_remote_credentials(
stream: *mut RiceStream,
) -> *mut RiceCredentials {
let stream = Arc::from_raw(stream);
let proto_agent = stream.proto_agent.lock().unwrap();
let proto_stream = proto_agent.stream(stream.stream_id).unwrap();
let ret = if let Some(credentials) = proto_stream.remote_credentials() {
credentials_to_c(credentials)
} else {
mut_override(std::ptr::null::<RiceCredentials>())
};
drop(proto_agent);
core::mem::forget(stream);
ret
}
unsafe fn string_from_c(cstr: *const c_char) -> String {
CStr::from_ptr(cstr).to_str().unwrap().to_owned()
}
unsafe fn owned_string_from_c(cstr: *mut c_char) -> CString {
CString::from_raw(cstr)
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_set_local_credentials(
stream: *mut RiceStream,
credentials: *const RiceCredentials,
) {
let creds = Box::from_raw(mut_override(credentials));
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
proto_stream.set_local_credentials(creds.credentials.clone());
drop(proto_agent);
core::mem::forget(stream);
core::mem::forget(creds);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_set_remote_credentials(
stream: *mut RiceStream,
credentials: *const RiceCredentials,
) {
let creds = Box::from_raw(mut_override(credentials));
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
proto_stream.set_remote_credentials(creds.credentials.clone());
drop(proto_agent);
core::mem::forget(stream);
core::mem::forget(creds);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum RiceTcpType {
None,
Active,
Passive,
So,
}
impl From<Option<crate::candidate::TcpType>> for RiceTcpType {
fn from(value: Option<crate::candidate::TcpType>) -> Self {
match value {
None => RiceTcpType::None,
Some(crate::candidate::TcpType::Active) => RiceTcpType::Active,
Some(crate::candidate::TcpType::Passive) => RiceTcpType::Passive,
Some(crate::candidate::TcpType::So) => RiceTcpType::So,
}
}
}
impl From<RiceTcpType> for Option<crate::candidate::TcpType> {
fn from(value: RiceTcpType) -> Self {
match value {
RiceTcpType::None => None,
RiceTcpType::Active => Some(crate::candidate::TcpType::Active),
RiceTcpType::Passive => Some(crate::candidate::TcpType::Passive),
RiceTcpType::So => Some(crate::candidate::TcpType::So),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RiceCandidateType {
Host,
PeerReflexive,
ServerReflexive,
Relayed,
}
impl From<CandidateType> for RiceCandidateType {
fn from(value: CandidateType) -> Self {
match value {
CandidateType::Host => RiceCandidateType::Host,
CandidateType::PeerReflexive => RiceCandidateType::PeerReflexive,
CandidateType::ServerReflexive => RiceCandidateType::ServerReflexive,
CandidateType::Relayed => RiceCandidateType::Relayed,
}
}
}
impl From<RiceCandidateType> for CandidateType {
fn from(value: RiceCandidateType) -> Self {
match value {
RiceCandidateType::Host => CandidateType::Host,
RiceCandidateType::PeerReflexive => CandidateType::PeerReflexive,
RiceCandidateType::ServerReflexive => CandidateType::ServerReflexive,
RiceCandidateType::Relayed => CandidateType::Relayed,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceCandidate {
component_id: usize,
candidate_type: RiceCandidateType,
transport_type: RiceTransportType,
foundation: *const c_char,
priority: u32,
address: *const RiceAddress,
base_address: *const RiceAddress,
related_address: *const RiceAddress,
tcp_type: RiceTcpType,
extensions: *mut *mut c_char,
extensions_len: usize,
}
impl RiceCandidate {
fn zero() -> Self {
Self {
component_id: 0,
candidate_type: RiceCandidateType::Host,
transport_type: RiceTransportType::Udp,
foundation: core::ptr::null(),
priority: 0,
address: core::ptr::null(),
base_address: core::ptr::null(),
related_address: core::ptr::null(),
tcp_type: RiceTcpType::None,
extensions: core::ptr::null_mut(),
extensions_len: 0,
}
}
fn as_rice_none(&self) -> crate::candidate::Candidate {
unsafe {
let related_address = if !self.related_address.is_null() {
Some(RiceAddress::into_rice_none(self.related_address).0)
} else {
None
};
let foundation = string_from_c(self.foundation);
crate::candidate::Candidate {
component_id: self.component_id,
candidate_type: self.candidate_type.into(),
transport_type: self.transport_type.into(),
foundation,
priority: self.priority,
address: RiceAddress::into_rice_none(self.address).0,
base_address: RiceAddress::into_rice_none(self.base_address).0,
related_address,
tcp_type: self.tcp_type.into(),
extensions: vec![],
}
}
}
fn into_rice_full(self) -> crate::candidate::Candidate {
unsafe {
let related_address = if !self.related_address.is_null() {
Some(RiceAddress::into_rice_full(self.related_address).0)
} else {
None
};
let foundation = owned_string_from_c(mut_override(self.foundation));
crate::candidate::Candidate {
component_id: self.component_id,
candidate_type: self.candidate_type.into(),
transport_type: self.transport_type.into(),
foundation: foundation.to_str().unwrap().to_owned(),
priority: self.priority,
address: RiceAddress::into_rice_full(self.address).0,
base_address: RiceAddress::into_rice_full(self.base_address).0,
related_address,
tcp_type: self.tcp_type.into(),
extensions: vec![],
}
}
}
fn into_c_full(value: crate::candidate::Candidate) -> Self {
let address = Box::new(RiceAddress(value.address));
let base_address = Box::new(RiceAddress(value.base_address));
let related_address = if let Some(addr) = value.related_address {
Box::into_raw(Box::new(RiceAddress(addr)))
} else {
core::ptr::null()
};
Self {
component_id: value.component_id,
candidate_type: value.candidate_type.into(),
transport_type: value.transport_type.into(),
foundation: CString::new(value.foundation).unwrap().into_raw(),
priority: value.priority,
address: Box::into_raw(address),
base_address: Box::into_raw(base_address),
related_address,
tcp_type: value.tcp_type.into(),
extensions: std::ptr::null_mut(),
extensions_len: 0,
}
}
}
impl PartialEq<RiceCandidate> for RiceCandidate {
fn eq(&self, other: &RiceCandidate) -> bool {
unsafe {
self.component_id == other.component_id
&& self.candidate_type == other.candidate_type
&& self.transport_type == other.transport_type
&& core::ffi::CStr::from_ptr(self.foundation)
== core::ffi::CStr::from_ptr(other.foundation)
&& self.priority == other.priority
&& rice_address_cmp(self.address, other.address) == 0
&& rice_address_cmp(self.base_address, other.base_address) == 0
&& rice_address_cmp(self.related_address, other.related_address) == 0
&& self.tcp_type == other.tcp_type
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_new_from_sdp_string(
cand_str: *const c_char,
) -> *mut RiceCandidate {
let candidate = mut_override(Box::into_raw(Box::new(RiceCandidate::zero())));
let ret = rice_candidate_init_from_sdp_string(candidate, cand_str);
if ret == RiceError::Success {
candidate
} else {
let _candidate = Box::from_raw(candidate);
core::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_init_from_sdp_string(
candidate: *mut RiceCandidate,
cand_str: *const c_char,
) -> RiceError {
let Ok(cand_str) = CStr::from_ptr(cand_str).to_str() else {
return RiceError::Failed;
};
let Ok(r_candidate) = Candidate::from_str(cand_str) else {
return RiceError::Failed;
};
*candidate = RiceCandidate::into_c_full(r_candidate);
RiceError::Success
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_to_sdp_string(
candidate: *const RiceCandidate,
) -> *mut c_char {
let candidate = Box::from_raw(mut_override(candidate));
let cand = (*candidate).as_rice_none();
let ret = CString::new(cand.to_sdp_string()).unwrap();
core::mem::forget(candidate);
ret.into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn rice_string_free(string: *mut c_char) {
let _s = CString::from_raw(string);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_new(
component_id: usize,
ctype: RiceCandidateType,
ttype: RiceTransportType,
foundation: *const c_char,
address: *mut RiceAddress,
) -> *mut RiceCandidate {
let candidate = mut_override(Box::into_raw(Box::new(RiceCandidate::zero())));
let ret = rice_candidate_init(candidate, component_id, ctype, ttype, foundation, address);
if ret == RiceError::Success {
candidate
} else {
let _candidate = Box::from_raw(candidate);
core::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_init(
candidate: *mut RiceCandidate,
component_id: usize,
ctype: RiceCandidateType,
ttype: RiceTransportType,
foundation: *const c_char,
address: *mut RiceAddress,
) -> RiceError {
if foundation.is_null() || address.is_null() {
return RiceError::Failed;
}
let foundation = CStr::from_ptr(foundation);
let Ok(foundation) = foundation.to_str() else {
return RiceError::Failed;
};
let Ok(foundation_s) = CString::new(foundation) else {
return RiceError::Failed;
};
let foundation = foundation_s.as_ptr();
core::mem::forget(foundation_s);
*candidate = RiceCandidate {
component_id,
candidate_type: ctype,
transport_type: ttype,
foundation,
priority: 0,
address: rice_address_copy(address),
base_address: address,
related_address: core::ptr::null_mut(),
tcp_type: RiceTcpType::None,
extensions: core::ptr::null_mut(),
extensions_len: 0,
};
RiceError::Success
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_set_priority(candidate: *mut RiceCandidate, priority: u32) {
let mut candidate = Box::from_raw(candidate);
candidate.priority = priority;
core::mem::forget(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_set_base_address(
candidate: *mut RiceCandidate,
base_address: *mut RiceAddress,
) {
let mut candidate = Box::from_raw(candidate);
let old = candidate.base_address;
candidate.base_address = base_address;
rice_address_free(mut_override(old));
core::mem::forget(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_set_related_address(
candidate: *mut RiceCandidate,
related_address: *mut RiceAddress,
) {
let mut candidate = Box::from_raw(candidate);
let old = candidate.related_address;
candidate.related_address = related_address;
rice_address_free(mut_override(old));
core::mem::forget(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_set_tcp_type(
candidate: *mut RiceCandidate,
tcp_type: RiceTcpType,
) {
let mut candidate = Box::from_raw(candidate);
candidate.tcp_type = tcp_type;
core::mem::forget(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_copy(
candidate: *const RiceCandidate,
) -> *mut RiceCandidate {
if candidate.is_null() {
return core::ptr::null_mut();
}
let ret = mut_override(Box::into_raw(Box::new(RiceCandidate::zero())));
rice_candidate_copy_into(candidate, ret);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_copy_into(
candidate: *const RiceCandidate,
ret: *mut RiceCandidate,
) {
if candidate.is_null() {
return;
}
let candidate = Box::from_raw(mut_override(candidate));
let foundation = CString::from_raw(mut_override(candidate.foundation));
*ret = RiceCandidate {
component_id: candidate.component_id,
candidate_type: candidate.candidate_type,
transport_type: candidate.transport_type,
foundation: foundation.clone().into_raw(),
priority: candidate.priority,
address: rice_address_copy(candidate.address),
base_address: rice_address_copy(candidate.base_address),
related_address: if candidate.related_address.is_null() {
core::ptr::null()
} else {
rice_address_copy(candidate.related_address)
},
tcp_type: candidate.tcp_type,
extensions: core::ptr::null_mut(),
extensions_len: candidate.extensions_len,
};
core::mem::forget(candidate);
core::mem::forget(foundation);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_clear(candidate: *mut RiceCandidate) {
if candidate.is_null() {
return;
}
if !(*candidate).foundation.is_null() {
let _foundation = CString::from_raw(mut_override((*candidate).foundation));
}
if !(*candidate).address.is_null() {
let _address = RiceAddress::into_rice_full((*candidate).address);
}
if !(*candidate).base_address.is_null() {
let _base_address = RiceAddress::into_rice_full((*candidate).base_address);
}
if !(*candidate).related_address.is_null() {
let _related_address = RiceAddress::into_rice_full((*candidate).related_address);
}
rice_candidate_zero(&mut *candidate);
}
fn rice_candidate_zero(candidate: &mut RiceCandidate) {
candidate.foundation = core::ptr::null_mut();
candidate.address = core::ptr::null_mut();
candidate.base_address = core::ptr::null_mut();
candidate.related_address = core::ptr::null_mut();
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_free(candidate: *mut RiceCandidate) {
if candidate.is_null() {
return;
}
rice_candidate_clear(candidate);
let _cand = Box::from_raw(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_candidate_eq(
candidate: *const RiceCandidate,
other: *const RiceCandidate,
) -> bool {
let cand = Box::from_raw(mut_override(candidate));
let other = Box::from_raw(mut_override(other));
let ret = *candidate == *other;
core::mem::forget(cand);
core::mem::forget(other);
ret
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceGatheredCandidate {
candidate: RiceCandidate,
turn_agent: *mut c_void,
}
impl RiceGatheredCandidate {
fn zero() -> Self {
Self {
candidate: RiceCandidate::zero(),
turn_agent: core::ptr::null_mut(),
}
}
fn into_rice_full(self) -> GatheredCandidate {
unsafe {
let candidate = self.candidate.into_rice_full();
let turn_agent = if self.turn_agent.is_null() {
None
} else {
Some(Box::from_raw(self.turn_agent as *mut TurnClient))
};
GatheredCandidate {
candidate,
turn_agent,
}
}
}
fn into_c_full(value: GatheredCandidate) -> Self {
let candidate = RiceCandidate::into_c_full(value.candidate);
let turn_agent = if let Some(turn_agent) = value.turn_agent {
Box::into_raw(turn_agent)
} else {
core::ptr::null_mut()
};
Self {
candidate,
turn_agent: turn_agent as *mut c_void,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_add_local_gathered_candidate(
stream: *mut RiceStream,
candidate: *const RiceGatheredCandidate,
) -> bool {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let candidate = mut_override(candidate);
let mut swapped = RiceGatheredCandidate::zero();
core::ptr::swap(&mut swapped, candidate);
let ret = proto_stream.add_local_gathered_candidate(swapped.into_rice_full());
drop(proto_agent);
core::mem::forget(stream);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_add_remote_candidate(
stream: *mut RiceStream,
candidate: *const RiceCandidate,
) {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let candidate = Box::from_raw(mut_override(candidate));
proto_stream.add_remote_candidate((*candidate).as_rice_none());
drop(proto_agent);
core::mem::forget(stream);
core::mem::forget(candidate);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_end_of_local_candidates(stream: *mut RiceStream) {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
proto_stream.end_of_local_candidates();
drop(proto_agent);
core::mem::forget(stream);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_end_of_remote_candidates(stream: *mut RiceStream) {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
proto_stream.end_of_remote_candidates();
drop(proto_agent);
core::mem::forget(stream);
}
#[derive(Debug)]
#[repr(C)]
pub struct RiceStreamIncomingData {
handled: bool,
have_more_data: bool,
data: RiceDataImpl,
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_handle_incoming_data(
stream: *mut RiceStream,
component_id: usize,
transport: RiceTransportType,
from: *const RiceAddress,
to: *const RiceAddress,
data: *const u8,
data_len: usize,
now_micros: u64,
ret: *mut MaybeUninit<RiceStreamIncomingData>,
) {
let stream = Arc::from_raw(stream);
let now = stream.base_instant + Duration::from_micros(now_micros);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let from = Box::from_raw(mut_override(from));
let to = Box::from_raw(mut_override(to));
let transmit = Transmit {
transport: transport.into(),
from: **from,
to: **to,
data: Data::Borrowed(DataSlice::from(std::slice::from_raw_parts(data, data_len))),
};
core::mem::forget(from);
core::mem::forget(to);
let stream_ret = proto_stream.handle_incoming_data(component_id, transmit, now);
let data = if let Some(_data_and_range) = stream_ret.data {
RiceDataImpl {
ptr: mut_override(data),
size: data_len,
}
} else {
RiceDataImpl {
ptr: core::ptr::null_mut(),
size: 0,
}
};
(*ret).write(RiceStreamIncomingData {
handled: stream_ret.handled,
have_more_data: stream_ret.have_more_data,
data,
});
drop(proto_agent);
core::mem::forget(stream);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_poll_recv(
stream: *mut RiceStream,
component_id: *mut usize,
data_len: *mut usize,
) -> *mut u8 {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let ret = if let Some(data) = proto_stream.poll_recv() {
*data_len = data.data.len();
*component_id = data.component_id;
Box::into_raw(data.data.into_boxed_slice()) as *mut _
} else {
*data_len = 0;
*component_id = 0;
core::ptr::null_mut::<u8>()
};
drop(proto_agent);
core::mem::forget(stream);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_free_data(data: *mut u8) {
let _ = Box::from_raw(data);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_component_ids(
stream: *mut RiceStream,
len: *mut usize,
ret: *mut usize,
) {
let stream = Arc::from_raw(stream);
let proto_agent = stream.proto_agent.lock().unwrap();
let proto_stream = proto_agent.stream(stream.stream_id).unwrap();
if ret.is_null() {
*len = proto_stream.component_ids_iter().count()
} else if *len > 0 {
let output = core::slice::from_raw_parts_mut(ret, *len);
*len = 0;
for component in proto_stream.component_ids_iter() {
output[*len] = component;
if *len + 1 > output.len() {
break;
}
*len += 1;
}
}
drop(proto_agent);
core::mem::forget(stream);
}
#[derive(Debug)]
pub struct RiceComponent {
proto_agent: Arc<Mutex<Agent>>,
weak_agent: Weak<Mutex<RiceAgentInner>>,
stream_id: usize,
component_id: usize,
base_instant: Instant,
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_add_component(stream: *mut RiceStream) -> *mut RiceComponent {
let stream = Arc::from_raw(stream);
let mut proto_agent = stream.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(stream.stream_id).unwrap();
let component_id = proto_stream.add_component().unwrap();
let component = Arc::new(RiceComponent {
proto_agent: stream.proto_agent.clone(),
weak_agent: stream.weak_agent.clone(),
stream_id: stream.stream_id,
component_id,
base_instant: stream.base_instant,
});
drop(proto_agent);
let mut inner = stream.inner.lock().unwrap();
inner.components.push(component.clone());
drop(inner);
core::mem::forget(stream);
mut_override(Arc::into_raw(component))
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_ref(component: *mut RiceComponent) -> *mut RiceComponent {
Arc::increment_strong_count(component);
component
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_unref(component: *mut RiceComponent) {
Arc::decrement_strong_count(component)
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_get_id(component: *const RiceComponent) -> usize {
let component = Arc::from_raw(mut_override(component));
let ret = component.component_id;
core::mem::forget(component);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_get_state(
component: *const RiceComponent,
) -> ComponentConnectionState {
let component = Arc::from_raw(mut_override(component));
let proto_agent = component.proto_agent.lock().unwrap();
let proto_stream = proto_agent.stream(component.stream_id).unwrap();
let proto_component = proto_stream.component(component.component_id).unwrap();
let ret = proto_component.state();
drop(proto_agent);
core::mem::forget(component);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_selected_pair(
component: *const RiceComponent,
local: *mut RiceCandidate,
remote: *mut RiceCandidate,
) {
let component = Arc::from_raw(mut_override(component));
let proto_agent = component.proto_agent.lock().unwrap();
let proto_stream = proto_agent.stream(component.stream_id).unwrap();
let proto_component = proto_stream.component(component.component_id).unwrap();
if let Some(pair) = proto_component.selected_pair().cloned() {
*local = RiceCandidate::into_c_full(pair.local);
*remote = RiceCandidate::into_c_full(pair.remote);
} else {
*local = RiceCandidate::zero();
*remote = RiceCandidate::zero();
};
drop(proto_agent);
core::mem::forget(component);
}
#[no_mangle]
pub unsafe extern "C" fn rice_stream_get_component(
stream: *mut RiceStream,
component_id: usize,
) -> *mut RiceComponent {
if component_id < 1 {
return mut_override(std::ptr::null::<RiceComponent>());
}
let stream = Arc::from_raw(stream);
let inner = stream.inner.lock().unwrap();
let ret = if let Some(component) = inner.components.get(component_id - 1) {
mut_override(Arc::into_raw(component.clone()))
} else {
return mut_override(std::ptr::null::<RiceComponent>());
};
drop(inner);
core::mem::forget(stream);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_gather_candidates(
component: *mut RiceComponent,
sockets_len: usize,
sockets_addr: *const *const RiceAddress,
sockets_transports: *const RiceTransportType,
) -> RiceError {
let component = Arc::from_raw(component);
let (stun_servers, turn_servers) = {
let Some(agent) = component.weak_agent.upgrade() else {
return RiceError::ResourceNotFound;
};
let agent = agent.lock().unwrap();
(agent.stun_servers.clone(), agent.turn_servers.clone())
};
debug!("stun_servers: {stun_servers:?}");
let mut proto_agent = component.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(component.stream_id).unwrap();
let mut proto_component = proto_stream.mut_component(component.component_id).unwrap();
let sockets_addr = std::slice::from_raw_parts(sockets_addr, sockets_len);
let sockets_transport = std::slice::from_raw_parts(sockets_transports, sockets_len);
let sockets = sockets_transport
.iter()
.zip(sockets_addr.iter())
.map(|(&transport, addr)| {
let socket_addr = RiceAddress::into_rice_none(*addr).0;
(transport.into(), socket_addr)
})
.collect::<Vec<_>>();
debug!("sockets: {sockets:?}");
let ret = proto_component.gather_candidates(sockets, stun_servers, turn_servers);
drop(proto_agent);
core::mem::forget(component);
match ret {
Ok(()) => RiceError::Success,
Err(AgentError::AlreadyInProgress) => RiceError::AlreadyInProgress,
Err(AgentError::ResourceNotFound) => RiceError::ResourceNotFound,
Err(_) => RiceError::Failed,
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_send(
component: *mut RiceComponent,
data: *mut u8,
len: usize,
now_micros: u64,
transmit: *mut RiceTransmit,
) -> RiceError {
let component = Arc::from_raw(component);
let now = component.base_instant + Duration::from_micros(now_micros);
let mut proto_agent = component.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(component.stream_id).unwrap();
let mut proto_component = proto_stream.mut_component(component.component_id).unwrap();
let bytes = Data::from(core::slice::from_raw_parts(data, len));
let ret = match proto_component.send(bytes, now) {
Ok(stun_transmit) => {
*transmit = RiceTransmit {
stream_id: component.stream_id,
transport: stun_transmit.transport.into(),
from: Box::into_raw(Box::new(RiceAddress::new(stun_transmit.from))),
to: Box::into_raw(Box::new(RiceAddress::new(stun_transmit.to))),
data: RiceDataImpl::owned_to_c(stun_transmit.data),
};
RiceError::Success
}
Err(e) => {
warn!("Failed to send data: {e:?}");
RiceError::Failed
}
};
drop(proto_agent);
core::mem::forget(component);
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_component_set_selected_pair(
component: *mut RiceComponent,
local: *const RiceCandidate,
remote: *const RiceCandidate,
) -> RiceError {
let component = Arc::from_raw(component);
let local = Box::from_raw(mut_override(local));
let remote = Box::from_raw(mut_override(remote));
let mut proto_agent = component.proto_agent.lock().unwrap();
let mut proto_stream = proto_agent.mut_stream(component.stream_id).unwrap();
let mut proto_component = proto_stream.mut_component(component.component_id).unwrap();
let ret = proto_component.set_selected_pair(CandidatePair::new(
(*local).as_rice_none(),
(*remote).as_rice_none(),
));
drop(proto_agent);
core::mem::forget(component);
core::mem::forget(local);
core::mem::forget(remote);
if ret.is_err() {
RiceError::Failed
} else {
RiceError::Success
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub struct RiceAddress(SocketAddr);
impl RiceAddress {
pub fn new(addr: SocketAddr) -> Self {
Self(addr)
}
pub fn into_c_full(self) -> *const RiceAddress {
const_override(Box::into_raw(Box::new(self)))
}
pub unsafe fn into_rice_full(value: *const RiceAddress) -> Box<Self> {
Box::from_raw(mut_override(value))
}
pub unsafe fn into_rice_none(value: *const RiceAddress) -> Self {
let boxed = Box::from_raw(mut_override(value));
let ret = *boxed;
core::mem::forget(boxed);
ret
}
}
impl std::ops::Deref for RiceAddress {
type Target = SocketAddr;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_new_from_string(string: *const c_char) -> *mut RiceAddress {
let Ok(string) = CStr::from_ptr(string).to_str() else {
return core::ptr::null_mut();
};
let Ok(saddr) = SocketAddr::from_str(string) else {
return core::ptr::null_mut();
};
mut_override(RiceAddress::into_c_full(RiceAddress(saddr)))
}
#[repr(u32)]
pub enum RiceAddressFamily {
Ipv4 = 1,
Ipv6,
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_new_from_bytes(
family: RiceAddressFamily,
bytes: *const u8,
port: u16,
) -> *mut RiceAddress {
let ip_addr = match family {
RiceAddressFamily::Ipv4 => {
let bytes = core::slice::from_raw_parts(bytes, 4);
IpAddr::V4(Ipv4Addr::from([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
RiceAddressFamily::Ipv6 => {
let bytes = core::slice::from_raw_parts(bytes, 16);
IpAddr::V6(Ipv6Addr::from([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
bytes[15],
]))
}
};
Box::into_raw(Box::new(RiceAddress(SocketAddr::new(ip_addr, port))))
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_get_family(addr: *const RiceAddress) -> RiceAddressFamily {
let addr = RiceAddress::into_rice_none(addr);
match addr.0 {
SocketAddr::V4(_) => RiceAddressFamily::Ipv4,
SocketAddr::V6(_) => RiceAddressFamily::Ipv6,
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_get_address_bytes(
addr: *const RiceAddress,
bytes: *mut u8,
) -> usize {
let addr = RiceAddress::into_rice_none(addr);
let ret = match addr.0.ip() {
IpAddr::V4(ip) => {
let bytes = core::slice::from_raw_parts_mut(bytes, 4);
for (i, octet) in ip.octets().into_iter().enumerate() {
bytes[i] = octet;
}
4
}
IpAddr::V6(ip) => {
let bytes = core::slice::from_raw_parts_mut(bytes, 16);
for (i, octet) in ip.octets().into_iter().enumerate() {
bytes[i] = octet;
}
16
}
};
ret
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_get_port(addr: *const RiceAddress) -> u16 {
let addr = RiceAddress::into_rice_none(addr);
addr.0.port()
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_cmp(
addr: *const RiceAddress,
other: *const RiceAddress,
) -> c_int {
match (addr.is_null(), other.is_null()) {
(true, true) => 0,
(true, false) => -1,
(false, true) => 1,
(false, false) => {
let addr = RiceAddress::into_rice_none(addr);
let other = RiceAddress::into_rice_none(other);
addr.cmp(&other) as c_int
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_copy(addr: *const RiceAddress) -> *mut RiceAddress {
if addr.is_null() {
return core::ptr::null_mut();
}
let addr = RiceAddress::into_rice_none(mut_override(addr));
mut_override(RiceAddress(addr.0).into_c_full())
}
#[no_mangle]
pub unsafe extern "C" fn rice_address_free(addr: *mut RiceAddress) {
if !addr.is_null() {
let _addr = Box::from_raw(addr);
}
}
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
}
#[cfg(test)]
mod tests {
use super::*;
use crate::candidate::{Candidate, TcpType};
#[test]
fn test_rice_version() {
unsafe {
let mut major = 0;
let mut minor = 0;
let mut patch = 0;
rice_version(&mut major, &mut minor, &mut patch);
eprintln!("Rice version: {major}.{minor}.{patch}");
}
}
#[test]
fn rice_address() {
unsafe {
let s = CString::new("127.0.0.1:2000").unwrap();
let addr = rice_address_new_from_string(s.as_ptr());
let addr2 = rice_address_copy(addr);
rice_address_free(addr);
rice_address_free(addr2);
}
}
#[test]
fn rice_candidate() {
let addr: SocketAddr = "127.0.0.1:2345".parse().unwrap();
let candidate = Candidate::builder(
1,
CandidateType::Host,
TransportType::Tcp,
"foundation",
addr,
)
.related_address(addr)
.priority(1234)
.tcp_type(TcpType::Passive)
.build();
let rcand = RiceCandidate::into_c_full(candidate.clone());
let cpy = unsafe { rice_candidate_copy(&rcand) };
let new_cand: Candidate = rcand.into_rice_full();
assert_eq!(candidate, new_cand);
unsafe { rice_candidate_free(cpy) };
}
#[test]
fn rice_agent_properties() {
unsafe {
let agent = rice_agent_new(true, false);
assert!(rice_agent_get_controlling(agent));
rice_agent_unref(agent);
}
}
#[test]
fn rice_refs() {
unsafe {
let agent = rice_agent_new(true, false);
let agent = rice_agent_ref(agent);
let stream = rice_agent_add_stream(agent);
rice_stream_unref(stream);
let stream = rice_agent_get_stream(agent, 0);
let stream = rice_stream_ref(stream);
let component = rice_stream_add_component(stream);
rice_component_unref(component);
let component = rice_stream_get_component(stream, 1);
let component = rice_component_ref(component);
rice_agent_unref(agent);
rice_agent_unref(agent);
rice_stream_unref(stream);
rice_stream_unref(stream);
rice_component_unref(component);
rice_component_unref(component);
}
}
#[test]
fn rice_agent_gather() {
unsafe {
let addr: SocketAddr = "192.168.0.1:1000".parse().unwrap();
let addr = RiceAddress::new(addr).into_c_full();
let stun_addr: SocketAddr = "102.168.0.200:2000".parse().unwrap();
let stun_addr = RiceAddress::new(stun_addr).into_c_full();
let agent = rice_agent_new(true, false);
let stream = rice_agent_add_stream(agent);
let component = rice_stream_add_component(stream);
let transport = TransportType::Tcp;
let local_credentials =
credentials_to_c(Credentials::new("luser".to_string(), "lpass".to_string()));
let remote_credentials =
credentials_to_c(Credentials::new("ruser".to_string(), "rpass".to_string()));
rice_agent_add_stun_server(agent, transport.into(), stun_addr);
rice_address_free(mut_override(stun_addr));
rice_stream_set_local_credentials(stream, local_credentials);
rice_credentials_free(local_credentials);
rice_stream_set_remote_credentials(stream, remote_credentials);
rice_credentials_free(remote_credentials);
rice_component_gather_candidates(component, 1, &addr, &transport.into());
rice_address_free(mut_override(addr));
let mut poll = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut poll);
let RiceAgentPoll::AllocateSocket(ref alloc) = poll else {
unreachable!()
};
let to = rice_address_copy(alloc.to);
let from = rice_address_copy(alloc.from);
let component_id = alloc.component_id;
rice_agent_poll_clear(&mut poll);
let mut poll = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut poll);
let RiceAgentPoll::GatheredCandidate(ref _candidate) = poll else {
unreachable!()
};
rice_agent_poll_clear(&mut poll);
let mut poll = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut poll);
let RiceAgentPoll::GatheredCandidate(ref _candidate) = poll else {
unreachable!()
};
rice_agent_poll_clear(&mut poll);
let mut poll = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut poll);
let RiceAgentPoll::WaitUntilMicros(_now) = poll else {
unreachable!()
};
rice_agent_poll_clear(&mut poll);
let tcp_from_addr = "192.168.200.4:3000".parse().unwrap();
let tcp_from_addr = mut_override(RiceAddress::new(tcp_from_addr).into_c_full());
rice_stream_handle_allocated_socket(
stream,
component_id,
RiceTransportType::Tcp,
from,
to,
tcp_from_addr,
);
rice_address_free(from);
rice_address_free(to);
let mut transmit = RiceTransmit::default();
rice_agent_poll_transmit(agent, 0, &mut transmit);
rice_transmit_clear(&mut transmit);
let mut poll = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut poll);
rice_agent_poll_clear(&mut poll);
let mut ret = RiceAgentPoll::Closed;
rice_agent_poll(agent, 0, &mut ret);
rice_agent_poll_clear(&mut ret);
rice_component_unref(component);
rice_stream_unref(stream);
rice_agent_unref(agent);
}
}
#[test]
fn rice_agent_poll_transmit_null() {
unsafe {
let agent = rice_agent_new(true, false);
let stream = rice_agent_add_stream(agent);
let mut transmit = RiceTransmit::default();
rice_agent_poll_transmit(agent, 0, &mut transmit);
assert!(transmit.from.is_null());
assert!(transmit.to.is_null());
assert!(transmit.data.ptr.is_null());
rice_agent_unref(agent);
rice_stream_unref(stream);
}
}
}