#[cfg(test)]
mod candidate_pair_test;
#[cfg(test)]
mod candidate_relay_test;
#[cfg(test)]
mod candidate_server_reflexive_test;
#[cfg(test)]
mod candidate_test;
pub mod candidate_base;
pub mod candidate_host;
pub mod candidate_peer_reflexive;
pub mod candidate_relay;
pub mod candidate_server_reflexive;
use std::fmt;
use std::net::{IpAddr, SocketAddr};
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::SystemTime;
use async_trait::async_trait;
use candidate_base::*;
use portable_atomic::{AtomicBool, AtomicU16, AtomicU8};
use serde::{Deserialize, Serialize};
use tokio::sync::{broadcast, Mutex};
use crate::error::Result;
use crate::network_type::*;
use crate::tcp_type::*;
pub(crate) const RECEIVE_MTU: usize = 8192;
pub(crate) const DEFAULT_LOCAL_PREFERENCE: u16 = 65535;
pub(crate) const COMPONENT_RTP: u16 = 1;
pub(crate) const COMPONENT_RTCP: u16 = 0;
#[async_trait]
pub trait Candidate: fmt::Display {
fn foundation(&self) -> String;
fn id(&self) -> String;
fn component(&self) -> u16;
fn set_component(&self, c: u16);
fn last_received(&self) -> SystemTime;
fn last_sent(&self) -> SystemTime;
fn network_type(&self) -> NetworkType;
fn address(&self) -> String;
fn port(&self) -> u16;
fn priority(&self) -> u32;
fn related_address(&self) -> Option<CandidateRelatedAddress>;
fn candidate_type(&self) -> CandidateType;
fn tcp_type(&self) -> TcpType;
fn marshal(&self) -> String;
fn addr(&self) -> SocketAddr;
async fn close(&self) -> Result<()>;
fn seen(&self, outbound: bool);
async fn write_to(&self, raw: &[u8], dst: &(dyn Candidate + Send + Sync)) -> Result<usize>;
fn equal(&self, other: &dyn Candidate) -> bool;
fn set_ip(&self, ip: &IpAddr) -> Result<()>;
fn get_conn(&self) -> Option<&Arc<dyn util::Conn + Send + Sync>>;
fn get_closed_ch(&self) -> Arc<Mutex<Option<broadcast::Sender<()>>>>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CandidateType {
#[serde(rename = "unspecified")]
Unspecified,
#[serde(rename = "host")]
Host,
#[serde(rename = "srflx")]
ServerReflexive,
#[serde(rename = "prflx")]
PeerReflexive,
#[serde(rename = "relay")]
Relay,
}
impl fmt::Display for CandidateType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
CandidateType::Host => "host",
CandidateType::ServerReflexive => "srflx",
CandidateType::PeerReflexive => "prflx",
CandidateType::Relay => "relay",
CandidateType::Unspecified => "Unknown candidate type",
};
write!(f, "{s}")
}
}
impl Default for CandidateType {
fn default() -> Self {
Self::Unspecified
}
}
impl CandidateType {
#[must_use]
pub const fn preference(self) -> u16 {
match self {
Self::Host => 126,
Self::PeerReflexive => 110,
Self::ServerReflexive => 100,
Self::Relay | CandidateType::Unspecified => 0,
}
}
}
pub(crate) fn contains_candidate_type(
candidate_type: CandidateType,
candidate_type_list: &[CandidateType],
) -> bool {
if candidate_type_list.is_empty() {
return false;
}
for ct in candidate_type_list {
if *ct == candidate_type {
return true;
}
}
false
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct CandidateRelatedAddress {
pub address: String,
pub port: u16,
}
impl fmt::Display for CandidateRelatedAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, " related {}:{}", self.address, self.port)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CandidatePairState {
#[serde(rename = "unspecified")]
Unspecified = 0,
#[serde(rename = "waiting")]
Waiting = 1,
#[serde(rename = "in-progress")]
InProgress = 2,
#[serde(rename = "failed")]
Failed = 3,
#[serde(rename = "succeeded")]
Succeeded = 4,
}
impl From<u8> for CandidatePairState {
fn from(v: u8) -> Self {
match v {
1 => Self::Waiting,
2 => Self::InProgress,
3 => Self::Failed,
4 => Self::Succeeded,
_ => Self::Unspecified,
}
}
}
impl Default for CandidatePairState {
fn default() -> Self {
Self::Unspecified
}
}
impl fmt::Display for CandidatePairState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Self::Waiting => "waiting",
Self::InProgress => "in-progress",
Self::Failed => "failed",
Self::Succeeded => "succeeded",
Self::Unspecified => "unspecified",
};
write!(f, "{s}")
}
}
pub struct CandidatePair {
pub(crate) ice_role_controlling: AtomicBool,
pub remote: Arc<dyn Candidate + Send + Sync>,
pub local: Arc<dyn Candidate + Send + Sync>,
pub(crate) binding_request_count: AtomicU16,
pub(crate) state: AtomicU8, pub(crate) nominated: AtomicBool,
}
impl Default for CandidatePair {
fn default() -> Self {
Self {
ice_role_controlling: AtomicBool::new(false),
remote: Arc::new(CandidateBase::default()),
local: Arc::new(CandidateBase::default()),
state: AtomicU8::new(CandidatePairState::Waiting as u8),
binding_request_count: AtomicU16::new(0),
nominated: AtomicBool::new(false),
}
}
}
impl fmt::Debug for CandidatePair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
self.priority(),
self.local.priority(),
self.local,
self.remote,
self.remote.priority()
)
}
}
impl fmt::Display for CandidatePair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
self.priority(),
self.local.priority(),
self.local,
self.remote,
self.remote.priority()
)
}
}
impl PartialEq for CandidatePair {
fn eq(&self, other: &Self) -> bool {
self.local.equal(&*other.local) && self.remote.equal(&*other.remote)
}
}
impl CandidatePair {
#[must_use]
pub fn new(
local: Arc<dyn Candidate + Send + Sync>,
remote: Arc<dyn Candidate + Send + Sync>,
controlling: bool,
) -> Self {
Self {
ice_role_controlling: AtomicBool::new(controlling),
remote,
local,
state: AtomicU8::new(CandidatePairState::Waiting as u8),
binding_request_count: AtomicU16::new(0),
nominated: AtomicBool::new(false),
}
}
pub fn priority(&self) -> u64 {
let (g, d) = if self.ice_role_controlling.load(Ordering::SeqCst) {
(self.local.priority(), self.remote.priority())
} else {
(self.remote.priority(), self.local.priority())
};
((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
+ 2 * u64::from(std::cmp::max(g, d))
+ u64::from(g > d)
}
pub async fn write(&self, b: &[u8]) -> Result<usize> {
self.local.write_to(b, &*self.remote).await
}
}