Skip to main content

rtc_dtls/
endpoint.rs

1//! The Sans-I/O DTLS endpoint.
2//!
3//! An [`Endpoint`](crate::endpoint::Endpoint) multiplexes several DTLS associations by remote address. Feed it inbound
4//! datagrams, poll it for the datagrams to send and for [`EndpointEvent`](crate::endpoint::EndpointEvent)s, and drive its timers
5//! with `handle_timeout`/`poll_timeout`. It owns no sockets and reads no clock.
6//!
7//! [`EndpointEvent::HandshakeComplete`](crate::endpoint::EndpointEvent::HandshakeComplete) is the signal an application waits for: from that point
8//! application data can be written, and the SRTP keying material can be exported from the
9//! completed handshake.
10use crate::conn::DTLSConn;
11use shared::error::{Error, Result};
12use shared::{EcnCodepoint, TransportContext};
13use shared::{TransportMessage, TransportProtocol};
14
15use crate::config::HandshakeConfig;
16use crate::state::State;
17use bytes::BytesMut;
18use std::collections::hash_map::Keys;
19use std::collections::{HashMap, VecDeque, hash_map::Entry::Vacant};
20use std::net::SocketAddr;
21use std::sync::Arc;
22use std::time::Instant;
23
24/// What the endpoint reports to its caller.
25pub enum EndpointEvent {
26    /// The handshake finished; application data may now be sent, and SRTP keys can be exported.
27    HandshakeComplete,
28    /// Decrypted application data arrived.
29    ApplicationData(BytesMut),
30}
31
32/// The main entry point to the library
33///
34/// This object performs no I/O whatsoever. Instead, it generates a stream of packets to send via
35/// `poll_transmit`, and consumes incoming packets and connections-generated events via `handle` and
36/// `handle_event`.
37pub struct Endpoint {
38    local_addr: SocketAddr,
39    transport_protocol: TransportProtocol,
40    transmits: VecDeque<TransportMessage<BytesMut>>,
41    connections: HashMap<SocketAddr, DTLSConn>,
42    server_config: Option<Arc<HandshakeConfig>>,
43}
44
45impl Endpoint {
46    /// Create a new endpoint
47    ///
48    /// Returns `Err` if the configuration is invalid.
49    pub fn new(
50        local_addr: SocketAddr,
51        protocol: TransportProtocol,
52        server_config: Option<Arc<HandshakeConfig>>,
53    ) -> Self {
54        Self {
55            local_addr,
56            transport_protocol: protocol,
57            transmits: VecDeque::new(),
58            connections: HashMap::new(),
59            server_config,
60        }
61    }
62
63    /// Replace the server configuration, affecting new incoming associations only
64    pub fn set_server_config(&mut self, server_config: Option<Arc<HandshakeConfig>>) {
65        self.server_config = server_config;
66    }
67
68    /// Get the next packet to transmit
69    #[must_use]
70    pub fn poll_transmit(&mut self) -> Option<TransportMessage<BytesMut>> {
71        self.transmits.pop_front()
72    }
73
74    /// Get keys of Connections
75    pub fn get_connections_keys(&self) -> Keys<'_, SocketAddr, DTLSConn> {
76        self.connections.keys()
77    }
78
79    /// Get Connection State
80    pub fn get_connection_state(&self, remote: SocketAddr) -> Option<&State> {
81        if let Some(conn) = self.connections.get(&remote) {
82            Some(conn.connection_state())
83        } else {
84            None
85        }
86    }
87
88    /// Initiate an Association
89    pub fn connect(
90        &mut self,
91        remote: SocketAddr,
92        client_config: Arc<HandshakeConfig>,
93        initial_state: Option<State>,
94    ) -> Result<()> {
95        if remote.port() == 0 {
96            return Err(Error::InvalidRemoteAddress(remote));
97        }
98
99        if let Vacant(e) = self.connections.entry(remote) {
100            let mut conn = DTLSConn::new(client_config, true, initial_state);
101            conn.handshake()?;
102
103            while let Some(payload) = conn.outgoing_raw_packet() {
104                self.transmits.push_back(TransportMessage {
105                    now: Instant::now(),
106                    transport: TransportContext {
107                        local_addr: self.local_addr,
108                        peer_addr: remote,
109                        ecn: None,
110                        transport_protocol: self.transport_protocol,
111                    },
112                    message: payload,
113                });
114            }
115
116            e.insert(conn);
117        }
118
119        Ok(())
120    }
121
122    /// Process stop remote
123    pub fn stop(&mut self, remote: SocketAddr) -> Option<DTLSConn> {
124        if let Some(conn) = self.connections.get_mut(&remote) {
125            conn.close();
126            while let Some(payload) = conn.outgoing_raw_packet() {
127                self.transmits.push_back(TransportMessage {
128                    now: Instant::now(),
129                    transport: TransportContext {
130                        local_addr: self.local_addr,
131                        peer_addr: remote,
132                        ecn: None,
133                        transport_protocol: self.transport_protocol,
134                    },
135                    message: payload,
136                });
137            }
138        }
139        self.connections.remove(&remote)
140    }
141
142    /// Process close
143    pub fn close(&mut self) -> Result<()> {
144        for (remote_addr, conn) in self.connections.iter_mut() {
145            conn.close();
146            while let Some(payload) = conn.outgoing_raw_packet() {
147                self.transmits.push_back(TransportMessage {
148                    now: Instant::now(),
149                    transport: TransportContext {
150                        local_addr: self.local_addr,
151                        peer_addr: *remote_addr,
152                        ecn: None,
153                        transport_protocol: self.transport_protocol,
154                    },
155                    message: payload,
156                });
157            }
158        }
159        self.connections.clear();
160
161        Ok(())
162    }
163
164    /// Process an incoming UDP datagram
165    pub fn read(
166        &mut self,
167        now: Instant,
168        remote: SocketAddr,
169        ecn: Option<EcnCodepoint>,
170        data: BytesMut,
171    ) -> Result<Vec<EndpointEvent>> {
172        if let Vacant(e) = self.connections.entry(remote) {
173            if let Some(server_config) = &self.server_config {
174                let handshake_config = server_config.clone();
175                let conn = DTLSConn::new(handshake_config, false, None);
176                e.insert(conn);
177            } else {
178                return Err(Error::NoServerConfig);
179            }
180        }
181
182        // Handle packet on existing association, if any
183        let mut messages = vec![];
184        if let Some(conn) = self.connections.get_mut(&remote) {
185            let is_handshake_completed_before = conn.is_handshake_completed();
186            conn.read(&data)?;
187            if !conn.is_handshake_completed() {
188                conn.handshake()?;
189                // Drain any queued future-epoch packets (e.g. Finished that arrived
190                // before ChangeCipherSpec bumped remote_epoch). If draining sets
191                // handshake_rx, run handshake() again so the FSM can advance.
192                let is_handshake = conn.handle_incoming_queued_packets()?;
193                if is_handshake && !conn.is_handshake_completed() {
194                    conn.handshake()?;
195                }
196            }
197            if !is_handshake_completed_before && conn.is_handshake_completed() {
198                messages.push(EndpointEvent::HandshakeComplete)
199            }
200            while let Some(message) = conn.incoming_application_data() {
201                messages.push(EndpointEvent::ApplicationData(message));
202            }
203            while let Some(payload) = conn.outgoing_raw_packet() {
204                self.transmits.push_back(TransportMessage {
205                    now,
206                    transport: TransportContext {
207                        local_addr: self.local_addr,
208                        peer_addr: remote,
209                        ecn,
210                        transport_protocol: self.transport_protocol,
211                    },
212                    message: payload,
213                });
214            }
215        }
216
217        Ok(messages)
218    }
219
220    /// Queues application data for `remote`.
221    ///
222    /// # Errors
223    ///
224    /// Fails if there is no association with `remote`, or its handshake has not completed.
225    pub fn write(&mut self, remote: SocketAddr, data: &[u8]) -> Result<()> {
226        if let Some(conn) = self.connections.get_mut(&remote) {
227            conn.write(data)?;
228            while let Some(payload) = conn.outgoing_raw_packet() {
229                self.transmits.push_back(TransportMessage {
230                    now: Instant::now(),
231                    transport: TransportContext {
232                        local_addr: self.local_addr,
233                        peer_addr: remote,
234                        ecn: None,
235                        transport_protocol: self.transport_protocol,
236                    },
237                    message: payload,
238                });
239            }
240            Ok(())
241        } else {
242            Err(Error::InvalidRemoteAddress(remote))
243        }
244    }
245
246    /// Advances `remote`'s association to `now`, driving handshake retransmissions.
247    ///
248    /// # Errors
249    ///
250    /// Fails if the handshake has exhausted its retransmissions.
251    pub fn handle_timeout(&mut self, remote: SocketAddr, now: Instant) -> Result<()> {
252        if let Some(conn) = self.connections.get_mut(&remote) {
253            if let Some(current_retransmit_timer) = &conn.current_retransmit_timer
254                && now >= *current_retransmit_timer
255            {
256                if conn.current_retransmit_timer.take().is_some() && !conn.is_handshake_completed()
257                {
258                    conn.handshake_timeout(now)?;
259                }
260                while let Some(payload) = conn.outgoing_raw_packet() {
261                    self.transmits.push_back(TransportMessage {
262                        now,
263                        transport: TransportContext {
264                            local_addr: self.local_addr,
265                            peer_addr: remote,
266                            ecn: None,
267                            transport_protocol: self.transport_protocol,
268                        },
269                        message: payload,
270                    });
271                }
272            }
273            Ok(())
274        } else {
275            Err(Error::InvalidRemoteAddress(remote))
276        }
277    }
278
279    /// When `remote`'s association next needs [`Self::handle_timeout`].
280    pub fn poll_timeout(&self, remote: SocketAddr, eto: &mut Instant) -> Result<()> {
281        if let Some(conn) = self.connections.get(&remote) {
282            if let Some(current_retransmit_timer) = &conn.current_retransmit_timer
283                && *current_retransmit_timer < *eto
284            {
285                *eto = *current_retransmit_timer;
286            }
287            Ok(())
288        } else {
289            Err(Error::InvalidRemoteAddress(remote))
290        }
291    }
292}