Skip to main content

str0m_proto/
net.rs

1use std::fmt;
2use std::net::SocketAddr;
3use std::ops::Deref;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8/// Type of protocol used in [`Transmit`].
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum Protocol {
11    /// UDP
12    Udp,
13    /// TCP (See RFC 4571 for framing)
14    Tcp,
15    /// TCP with fixed SSL Hello Exchange
16    /// See AsyncSSLServerSocket implementation for exchange details:
17    /// <https://webrtc.googlesource.com/src/+/refs/heads/main/rtc_base/server_socket_adapters.cc#19>
18    SslTcp,
19    /// TLS (only used via relay)
20    Tls,
21}
22
23/// TCP connection role as defined by the `tcptype` SDP attribute.
24///
25/// This enum corresponds to the TCP connection setup modes defined in
26/// [RFC 6544 ยง4.5](https://datatracker.ietf.org/doc/html/rfc6544#section-4.5),
27/// which specifies how endpoints establish TCP connections when TCP is used
28/// as a transport for media streams.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
30pub enum TcpType {
31    /// The endpoint actively initiates the TCP connection.
32    ///
33    /// In this mode, the endpoint performs an active open (i.e., sends a SYN)
34    /// to the remote peer.
35    Active,
36
37    /// The endpoint passively waits for an incoming TCP connection.
38    ///
39    /// In this mode, the endpoint performs a passive open (i.e., listens)
40    /// and accepts a connection initiated by the remote peer.
41    Passive,
42
43    /// Simultaneous open.
44    ///
45    /// Both endpoints attempt to actively open a TCP connection to each other
46    /// at the same time. This relies on TCP simultaneous open behavior.
47    So,
48}
49
50impl fmt::Display for TcpType {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        let str = match self {
53            Self::Active => "active",
54            Self::Passive => "passive",
55            Self::So => "so",
56        };
57        f.write_str(str)
58    }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct ParseTcpTypeError;
63
64impl fmt::Display for ParseTcpTypeError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        f.write_str("invalid TCP type (expected: active, passive, or so)")
67    }
68}
69
70impl std::error::Error for ParseTcpTypeError {}
71
72impl FromStr for TcpType {
73    type Err = ParseTcpTypeError;
74
75    fn from_str(s: &str) -> Result<Self, Self::Err> {
76        match s {
77            _ if s.eq_ignore_ascii_case("active") => Ok(Self::Active),
78            _ if s.eq_ignore_ascii_case("passive") => Ok(Self::Passive),
79            _ if s.eq_ignore_ascii_case("so") => Ok(Self::So),
80            _ => Err(ParseTcpTypeError),
81        }
82    }
83}
84
85impl TryFrom<&str> for Protocol {
86    type Error = ();
87
88    fn try_from(proto: &str) -> Result<Self, Self::Error> {
89        let proto = proto.to_lowercase();
90        match proto.as_str() {
91            "udp" => Ok(Protocol::Udp),
92            "tcp" => Ok(Protocol::Tcp),
93            "ssltcp" => Ok(Protocol::SslTcp),
94            "tls" => Ok(Protocol::Tls),
95            _ => Err(()),
96        }
97    }
98}
99
100impl From<Protocol> for &str {
101    fn from(proto: Protocol) -> Self {
102        match proto {
103            Protocol::Udp => "udp",
104            Protocol::Tcp => "tcp",
105            Protocol::SslTcp => "ssltcp",
106            Protocol::Tls => "tls",
107        }
108    }
109}
110
111impl fmt::Display for Protocol {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        let x: &str = (*self).into();
114        write!(f, "{}", x)
115    }
116}
117
118/// An instruction to send an outgoing packet.
119#[derive(Serialize, Deserialize)]
120pub struct Transmit {
121    /// Protocol the transmission should use.
122    pub proto: Protocol,
123
124    /// The source IP this packet should be sent from.
125    ///
126    /// For ICE it's important to send outgoing packets from the correct IP address.
127    /// The IP could come from a local socket or relayed over a TURN server. Features like
128    /// hole-punching will only work if the packets are routed through the correct interfaces.
129    pub source: SocketAddr,
130
131    /// The destination address this datagram should be sent to.
132    pub destination: SocketAddr,
133
134    /// Contents of the datagram.
135    pub contents: DatagramSend,
136}
137
138impl fmt::Debug for Transmit {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        f.debug_struct("Transmit")
141            .field("proto", &self.proto)
142            .field("source", &self.source)
143            .field("destination", &self.destination)
144            .field("len", &self.contents.len())
145            .finish()
146    }
147}
148
149/// A wrapper for some payload that is to be sent.
150#[derive(Debug, Serialize, Deserialize)]
151pub struct DatagramSend(Vec<u8>);
152
153impl From<Vec<u8>> for DatagramSend {
154    fn from(value: Vec<u8>) -> Self {
155        DatagramSend(value)
156    }
157}
158
159impl From<DatagramSend> for Vec<u8> {
160    fn from(value: DatagramSend) -> Self {
161        value.0
162    }
163}
164
165impl Deref for DatagramSend {
166    type Target = [u8];
167
168    fn deref(&self) -> &Self::Target {
169        &self.0
170    }
171}