Skip to content
File

Blob: firmware/vendor/str0m/src/io/mod.rs

rust183 lines
1#![allow(clippy::manual_range_contains)]
2#![allow(clippy::new_without_default)]
3 
4use std::convert::TryFrom;
5use std::fmt;
6use std::io;
7use std::net::SocketAddr;
8 
9use serde::{Deserialize, Serialize};
10 
11pub use is::stun::StunMessage;
12 
13pub use str0m_proto::DATAGRAM_MTU_TARGET;
14pub use str0m_proto::DATAGRAM_MTU_TARGET_MAX;
15pub use str0m_proto::DATAGRAM_MTU_TARGET_MIN;
16pub use str0m_proto::DATAGRAM_MTU_WARN;
17 
18/// Max UDP packet size
19pub(crate) const DATAGRAM_MAX_PACKET_SIZE: usize = 2000;
20 
21/// Max expected RTP header over, with full extensions etc.
22pub const MAX_RTP_OVERHEAD: usize = 80;
23 
24/// Max expected DTLS record overhead (record header + explicit nonce + AEAD
25/// auth tag), worst case across DTLS 1.2/1.3 and common AEAD ciphers
26/// (AES-GCM, AES-CCM, CHACHA20-POLY1305).
27pub const MAX_DTLS_OVERHEAD: usize = 48;
28 
29mod error;
30pub use self::error::NetError;
31#[allow(unused_imports)]
32pub use self::error::StunError;
33 
34pub use str0m_proto::{DatagramSend, Protocol, TcpType, Transmit};
35 
36#[derive(Debug, Serialize, Deserialize)]
37/// Received incoming data.
38pub struct Receive<'a> {
39 /// The protocol the socket this received data originated from is using.
40 pub proto: Protocol,
41 
42 /// The socket this received data originated from.
43 pub source: SocketAddr,
44 
45 /// The destination ip of the datagram.
46 pub destination: SocketAddr,
47 
48 /// Parsed contents of the datagram.
49 #[serde(borrow)]
50 pub contents: DatagramRecv<'a>,
51}
52 
53impl<'a> Receive<'a> {
54 /// Creates a new instance by trying to parse the contents of `buf`.
55 pub fn new(
56 proto: Protocol,
57 source: SocketAddr,
58 destination: SocketAddr,
59 buf: &'a [u8],
60 ) -> Result<Self, NetError> {
61 let contents = DatagramRecv::try_from(buf)?;
62 Ok(Receive {
63 proto,
64 source,
65 destination,
66 contents,
67 })
68 }
69}
70 
71/// Wrapper for a parsed payload to be received.
72#[derive(Serialize, Deserialize)]
73pub struct DatagramRecv<'a> {
74 #[serde(borrow)]
75 pub(crate) inner: DatagramRecvInner<'a>,
76}
77 
78#[allow(clippy::large_enum_variant)] // We purposely don't want to allocate.
79#[derive(Serialize, Deserialize)]
80pub(crate) enum DatagramRecvInner<'a> {
81 Stun(StunMessage<'a>),
82 Dtls(&'a [u8]),
83 Rtp(&'a [u8]),
84 Rtcp(&'a [u8]),
85}
86 
87impl<'a> TryFrom<&'a [u8]> for DatagramRecv<'a> {
88 type Error = NetError;
89 
90 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
91 use DatagramRecvInner::*;
92 
93 let kind = MultiplexKind::try_from(value)?;
94 
95 let inner = match kind {
96 MultiplexKind::Stun => Stun(StunMessage::parse(value)?),
97 MultiplexKind::Dtls => Dtls(value),
98 MultiplexKind::Rtp => Rtp(value),
99 MultiplexKind::Rtcp => Rtcp(value),
100 };
101 
102 Ok(DatagramRecv { inner })
103 }
104}
105 
106#[derive(Debug, Clone, Copy, PartialEq)]
107pub(crate) enum MultiplexKind {
108 Stun,
109 Dtls,
110 Rtp,
111 Rtcp,
112}
113 
114impl<'a> TryFrom<&'a [u8]> for MultiplexKind {
115 type Error = io::Error;
116 
117 fn try_from(value: &'a [u8]) -> Result<Self, io::Error> {
118 if value.is_empty() {
119 return Err(io::Error::new(io::ErrorKind::InvalidData, "Empty datagram"));
120 }
121 
122 let byte0 = value[0];
123 let len = value.len();
124 
125 if byte0 < 2 && len >= 20 {
126 Ok(MultiplexKind::Stun)
127 } else if byte0 >= 20 && byte0 < 64 {
128 Ok(MultiplexKind::Dtls)
129 } else if byte0 >= 128 && byte0 < 192 && len > 2 {
130 let byte1 = value[1];
131 let payload_type = byte1 & 0x7f;
132 
133 Ok(if payload_type < 64 {
134 // This is kinda novel, and probably breaks, but...
135 // we can use the < 64 pt as an escape hatch if we run out
136 // of dynamic numbers >= 96
137 // https://bugs.chromium.org/p/webrtc/issues/detail?id=12194
138 MultiplexKind::Rtp
139 } else if payload_type >= 64 && payload_type < 96 {
140 MultiplexKind::Rtcp
141 } else {
142 MultiplexKind::Rtp
143 })
144 } else {
145 Err(io::Error::new(
146 io::ErrorKind::InvalidData,
147 "Unknown datagram",
148 ))
149 }
150 }
151}
152 
153impl<'a> TryFrom<&'a Transmit> for Receive<'a> {
154 type Error = NetError;
155 
156 fn try_from(t: &'a Transmit) -> Result<Self, Self::Error> {
157 Ok(Receive {
158 proto: t.proto,
159 source: t.source,
160 destination: t.destination,
161 contents: DatagramRecv::try_from(&t.contents[..])?,
162 })
163 }
164}
165 
166impl fmt::Debug for DatagramRecv<'_> {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 self.inner.fmt(f)
169 }
170}
171 
172impl fmt::Debug for DatagramRecvInner<'_> {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 match self {
175 Self::Stun(v) => f.debug_tuple("Stun").field(v).finish(),
176 Self::Dtls(v) => write!(f, "Dtls(len: {})", v.len()),
177 Self::Rtp(v) => write!(f, "Rtp(len: {})", v.len()),
178 Self::Rtcp(v) => write!(f, "Rtcp(len: {})", v.len()),
179 }
180 }
181 //
182}