#[cfg(test)]
mod tests;
use bytes::Bytes;
use serde::de::{MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::any::Any;
use std::borrow::Cow;
use std::fmt;
use std::net::IpAddr;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct AppData(Arc<dyn Any + Send + Sync>);
impl Default for AppData {
fn default() -> Self {
Self::new(())
}
}
impl Deref for AppData {
type Target = Arc<dyn Any + Send + Sync>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AppData {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl AppData {
pub fn new<T: Any + Send + Sync>(app_data: T) -> Self {
Self(Arc::new(app_data))
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TransportListenIp {
pub ip: IpAddr,
#[serde(skip_serializing_if = "Option::is_none")]
pub announced_ip: Option<IpAddr>,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum IceRole {
Controlled,
Controlling,
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct IceParameters {
pub username_fragment: String,
pub password: String,
pub ice_lite: Option<bool>,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum IceCandidateType {
Host,
Srflx,
Prflx,
Relay,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum IceCandidateTcpType {
Passive,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum TransportProtocol {
Tcp,
Udp,
}
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct IceCandidate {
pub foundation: String,
pub priority: u32,
pub ip: IpAddr,
pub protocol: TransportProtocol,
pub port: u16,
pub r#type: IceCandidateType,
pub tcp_type: Option<IceCandidateTcpType>,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum IceState {
New,
Connected,
Completed,
Disconnected,
Closed,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(untagged)]
pub enum TransportTuple {
#[serde(rename_all = "camelCase")]
WithRemote {
local_ip: IpAddr,
local_port: u16,
remote_ip: IpAddr,
remote_port: u16,
protocol: TransportProtocol,
},
#[serde(rename_all = "camelCase")]
LocalOnly {
local_ip: IpAddr,
local_port: u16,
protocol: TransportProtocol,
},
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum DtlsState {
New,
Connecting,
Connected,
Failed,
Closed,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum SctpState {
New,
Connecting,
Connected,
Failed,
Closed,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum DtlsRole {
Auto,
Client,
Server,
}
impl Default for DtlsRole {
fn default() -> Self {
Self::Auto
}
}
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
pub enum DtlsFingerprint {
Sha1 {
value: [u8; 20],
},
Sha224 {
value: [u8; 28],
},
Sha256 {
value: [u8; 32],
},
Sha384 {
value: [u8; 48],
},
Sha512 {
value: [u8; 64],
},
}
impl Serialize for DtlsFingerprint {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
let mut rtcp_feedback = serializer.serialize_struct("DtlsFingerprint", 2)?;
match self {
DtlsFingerprint::Sha1 { value } => {
let value = format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
value[0],
value[1],
value[2],
value[3],
value[4],
value[5],
value[6],
value[7],
value[8],
value[9],
value[10],
value[11],
value[12],
value[13],
value[14],
value[15],
value[16],
value[17],
value[18],
value[19],
);
rtcp_feedback.serialize_field("algorithm", "sha-1")?;
rtcp_feedback.serialize_field("value", &value)?;
}
DtlsFingerprint::Sha224 { value } => {
let value = format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
value[0],
value[1],
value[2],
value[3],
value[4],
value[5],
value[6],
value[7],
value[8],
value[9],
value[10],
value[11],
value[12],
value[13],
value[14],
value[15],
value[16],
value[17],
value[18],
value[19],
value[20],
value[21],
value[22],
value[23],
value[24],
value[25],
value[26],
value[27],
);
rtcp_feedback.serialize_field("algorithm", "sha-224")?;
rtcp_feedback.serialize_field("value", &value)?;
}
DtlsFingerprint::Sha256 { value } => {
let value = format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}",
value[0],
value[1],
value[2],
value[3],
value[4],
value[5],
value[6],
value[7],
value[8],
value[9],
value[10],
value[11],
value[12],
value[13],
value[14],
value[15],
value[16],
value[17],
value[18],
value[19],
value[20],
value[21],
value[22],
value[23],
value[24],
value[25],
value[26],
value[27],
value[28],
value[29],
value[30],
value[31],
);
rtcp_feedback.serialize_field("algorithm", "sha-256")?;
rtcp_feedback.serialize_field("value", &value)?;
}
DtlsFingerprint::Sha384 { value } => {
let value = format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
value[0],
value[1],
value[2],
value[3],
value[4],
value[5],
value[6],
value[7],
value[8],
value[9],
value[10],
value[11],
value[12],
value[13],
value[14],
value[15],
value[16],
value[17],
value[18],
value[19],
value[20],
value[21],
value[22],
value[23],
value[24],
value[25],
value[26],
value[27],
value[28],
value[29],
value[30],
value[31],
value[32],
value[33],
value[34],
value[35],
value[36],
value[37],
value[38],
value[39],
value[40],
value[41],
value[42],
value[43],
value[44],
value[45],
value[46],
value[47],
);
rtcp_feedback.serialize_field("algorithm", "sha-384")?;
rtcp_feedback.serialize_field("value", &value)?;
}
DtlsFingerprint::Sha512 { value } => {
let value = format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:\
{:02X}:{:02X}:{:02X}:{:02X}",
value[0],
value[1],
value[2],
value[3],
value[4],
value[5],
value[6],
value[7],
value[8],
value[9],
value[10],
value[11],
value[12],
value[13],
value[14],
value[15],
value[16],
value[17],
value[18],
value[19],
value[20],
value[21],
value[22],
value[23],
value[24],
value[25],
value[26],
value[27],
value[28],
value[29],
value[30],
value[31],
value[32],
value[33],
value[34],
value[35],
value[36],
value[37],
value[38],
value[39],
value[40],
value[41],
value[42],
value[43],
value[44],
value[45],
value[46],
value[47],
value[48],
value[49],
value[50],
value[51],
value[52],
value[53],
value[54],
value[55],
value[56],
value[57],
value[58],
value[59],
value[60],
value[61],
value[62],
value[63],
);
rtcp_feedback.serialize_field("algorithm", "sha-512")?;
rtcp_feedback.serialize_field("value", &value)?;
}
}
rtcp_feedback.end()
}
}
impl<'de> Deserialize<'de> for DtlsFingerprint {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Algorithm,
Value,
}
struct DtlsFingerprintVisitor;
impl<'de> Visitor<'de> for DtlsFingerprintVisitor {
type Value = DtlsFingerprint;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(
r#"DTLS fingerprint algorithm and value like {"algorithm": "sha-256", "value": "1B:EA:BF:33:B8:11:26:6D:91:AD:1B:A0:16:FD:5D:60:59:33:F7:46:A3:BA:99:2A:1D:04:99:A6:F2:C6:2D:43"}"#,
)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut algorithm = None::<Cow<'_, str>>;
let mut value = None::<Cow<'_, str>>;
while let Some(key) = map.next_key()? {
match key {
Field::Algorithm => {
if algorithm.is_some() {
return Err(de::Error::duplicate_field("algorithm"));
}
algorithm = Some(map.next_value()?);
}
Field::Value => {
if value.is_some() {
return Err(de::Error::duplicate_field("value"));
}
value = map.next_value()?;
}
}
}
let algorithm = algorithm.ok_or_else(|| de::Error::missing_field("algorithm"))?;
let value = value.ok_or_else(|| de::Error::missing_field("value"))?;
fn parse_as_bytes(input: &str, output: &mut [u8]) -> Result<(), String> {
for (i, v) in output.iter_mut().enumerate() {
*v = u8::from_str_radix(&input[i * 3..(i * 3) + 2], 16).map_err(
|error| {
format!(
"Failed to parse value {} as series of hex bytes: {}",
input, error,
)
},
)?;
}
Ok(())
}
match algorithm.as_ref() {
"sha-1" => {
if value.len() != (20 * 3 - 1) {
Err(de::Error::custom(
"Value doesn't have correct length for SHA-1",
))
} else {
let mut value_result = [0u8; 20];
parse_as_bytes(value.as_ref(), &mut value_result)
.map_err(de::Error::custom)?;
Ok(DtlsFingerprint::Sha1 {
value: value_result,
})
}
}
"sha-224" => {
if value.len() != (28 * 3 - 1) {
Err(de::Error::custom(
"Value doesn't have correct length for SHA-224",
))
} else {
let mut value_result = [0u8; 28];
parse_as_bytes(value.as_ref(), &mut value_result)
.map_err(de::Error::custom)?;
Ok(DtlsFingerprint::Sha224 {
value: value_result,
})
}
}
"sha-256" => {
if value.len() != (32 * 3 - 1) {
Err(de::Error::custom(
"Value doesn't have correct length for SHA-256",
))
} else {
let mut value_result = [0u8; 32];
parse_as_bytes(value.as_ref(), &mut value_result)
.map_err(de::Error::custom)?;
Ok(DtlsFingerprint::Sha256 {
value: value_result,
})
}
}
"sha-384" => {
if value.len() != (48 * 3 - 1) {
Err(de::Error::custom(
"Value doesn't have correct length for SHA-384",
))
} else {
let mut value_result = [0u8; 48];
parse_as_bytes(value.as_ref(), &mut value_result)
.map_err(de::Error::custom)?;
Ok(DtlsFingerprint::Sha384 {
value: value_result,
})
}
}
"sha-512" => {
if value.len() != (64 * 3 - 1) {
Err(de::Error::custom(
"Value doesn't have correct length for SHA-512",
))
} else {
let mut value_result = [0u8; 64];
parse_as_bytes(value.as_ref(), &mut value_result)
.map_err(de::Error::custom)?;
Ok(DtlsFingerprint::Sha512 {
value: value_result,
})
}
}
algorithm => Err(de::Error::unknown_variant(
algorithm,
&["sha-1", "sha-224", "sha-256", "sha-384", "sha-512"],
)),
}
}
}
const FIELDS: &[&str] = &["algorithm", "value"];
deserializer.deserialize_struct("DtlsFingerprint", FIELDS, DtlsFingerprintVisitor)
}
}
#[derive(Debug, Clone, PartialOrd, PartialEq, Deserialize, Serialize)]
pub struct DtlsParameters {
pub role: DtlsRole,
pub fingerprints: Vec<DtlsFingerprint>,
}
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum TraceEventDirection {
In,
Out,
}
#[derive(Debug, Clone)]
pub enum WebRtcMessage {
String(String),
Binary(Bytes),
EmptyString,
EmptyBinary,
}
impl WebRtcMessage {
pub(crate) fn new(ppid: u32, payload: Bytes) -> Result<Self, u32> {
match ppid {
51 => Ok(WebRtcMessage::String(
String::from_utf8(payload.to_vec()).unwrap(),
)),
53 => Ok(WebRtcMessage::Binary(payload)),
56 => Ok(WebRtcMessage::EmptyString),
57 => Ok(WebRtcMessage::EmptyBinary),
ppid => Err(ppid),
}
}
pub(crate) fn into_ppid_and_payload(self) -> (u32, Bytes) {
match self {
WebRtcMessage::String(string) => (51_u32, Bytes::from(string)),
WebRtcMessage::Binary(binary) => (53_u32, binary),
WebRtcMessage::EmptyString => (56_u32, Bytes::from_static(b" ")),
WebRtcMessage::EmptyBinary => (57_u32, Bytes::from(vec![0u8])),
}
}
}