Skip to content

Commit e01be38

Browse files
author
yngrtc
committed
remove endpoint/session when dtls Error::ErrAlertFatalOrClose or idle time
1 parent d6c7c0b commit e01be38

File tree

12 files changed

+131
-27
lines changed

12 files changed

+131
-27
lines changed

examples/sync_chat.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::net::{IpAddr, UdpSocket};
88
use std::str::FromStr;
99
use std::sync::mpsc::{self};
1010
use std::sync::Arc;
11+
use std::time::Duration;
1112
use wg::WaitGroup;
1213

1314
mod sync_signal;
@@ -114,7 +115,8 @@ pub fn main() -> anyhow::Result<()> {
114115
ServerConfig::new(certificates)
115116
.with_dtls_handshake_config(dtls_handshake_config)
116117
.with_sctp_endpoint_config(sctp_endpoint_config)
117-
.with_sctp_server_config(sctp_server_config),
118+
.with_sctp_server_config(sctp_server_config)
119+
.with_idle_timeout(Duration::from_secs(30)),
118120
);
119121
let wait_group = WaitGroup::new();
120122

examples/sync_signal/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ pub fn sync_run(
107107

108108
let mut buf = vec![0; 2000];
109109

110+
pipeline.transport_active();
110111
loop {
111112
match stop_rx.try_recv() {
112113
Ok(_) => break,
@@ -150,6 +151,7 @@ pub fn sync_run(
150151
// Drive time forward in all clients.
151152
pipeline.handle_timeout(Instant::now());
152153
}
154+
pipeline.transport_inactive();
153155

154156
println!(
155157
"media server on {} is gracefully down",
@@ -161,10 +163,9 @@ pub fn sync_run(
161163
fn write_socket_output(
162164
socket: &UdpSocket,
163165
pipeline: &Rc<Pipeline<TaggedBytesMut, TaggedBytesMut>>,
164-
) -> anyhow::Result<()>{
166+
) -> anyhow::Result<()> {
165167
while let Some(transmit) = pipeline.poll_transmit() {
166-
socket
167-
.send_to(&transmit.message, transmit.transport.peer_addr)?;
168+
socket.send_to(&transmit.message, transmit.transport.peer_addr)?;
168169
}
169170

170171
Ok(())

src/endpoint/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ impl Endpoint {
4646
self.transports.insert(*transport.four_tuple(), transport);
4747
}
4848

49-
pub(crate) fn remove_transport(&mut self, four_tuple: &FourTuple) {
50-
self.transports.remove(four_tuple);
49+
pub(crate) fn remove_transport(&mut self, four_tuple: &FourTuple) -> Option<Transport> {
50+
self.transports.remove(four_tuple)
5151
}
5252

5353
pub(crate) fn has_transport(&self, four_tuple: &FourTuple) -> bool {

src/endpoint/transport.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ use srtp::context::Context;
55
use std::collections::HashMap;
66
use std::rc::Rc;
77
use std::sync::Arc;
8+
use std::time::Instant;
89

910
pub(crate) struct Transport {
1011
four_tuple: FourTuple,
12+
last_activity: Instant,
1113

1214
// ICE
1315
candidate: Rc<Candidate>,
@@ -38,6 +40,7 @@ impl Transport {
3840
) -> Self {
3941
Self {
4042
four_tuple,
43+
last_activity: Instant::now(),
4144

4245
candidate,
4346

@@ -129,4 +132,12 @@ impl Transport {
129132
pub(crate) fn is_local_srtp_context_ready(&self) -> bool {
130133
self.local_srtp_context.is_some()
131134
}
135+
136+
pub(crate) fn keep_alive(&mut self) {
137+
self.last_activity = Instant::now();
138+
}
139+
140+
pub(crate) fn last_activity(&self) -> Instant {
141+
self.last_activity
142+
}
132143
}

src/handler/demuxer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct DemuxerHandler;
4545

4646
impl DemuxerHandler {
4747
pub fn new() -> Self {
48-
DemuxerHandler::default()
48+
DemuxerHandler
4949
}
5050
}
5151

src/handler/dtls.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,12 @@ impl Handler for DtlsHandler {
132132
}
133133
Err(err) => {
134134
error!("try_read with error {}", err);
135-
ctx.fire_exception(Box::new(err))
135+
if err == Error::ErrAlertFatalOrClose {
136+
let mut server_states = self.server_states.borrow_mut();
137+
server_states.remove_transport(four_tuple);
138+
} else {
139+
ctx.fire_exception(Box::new(err))
140+
}
136141
}
137142
};
138143
} else {

src/handler/exception.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub struct ExceptionHandler;
99

1010
impl ExceptionHandler {
1111
pub fn new() -> Self {
12-
ExceptionHandler::default()
12+
ExceptionHandler
1313
}
1414
}
1515

src/handler/gateway.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ use retty::transport::TransportContext;
1515
use shared::error::{Error, Result};
1616
use std::cell::RefCell;
1717
use std::collections::VecDeque;
18+
use std::ops::{Add, Sub};
1819
use std::rc::Rc;
1920
use std::time::Instant;
21+
use std::time::Duration;
2022
use stun::attributes::{
2123
ATTR_ICE_CONTROLLED, ATTR_ICE_CONTROLLING, ATTR_NETWORK_COST, ATTR_PRIORITY, ATTR_USERNAME,
2224
ATTR_USE_CANDIDATE,
@@ -31,13 +33,19 @@ use stun::xoraddr::XorMappedAddress;
3133
pub struct GatewayHandler {
3234
server_states: Rc<RefCell<ServerStates>>,
3335
transmits: VecDeque<TaggedMessageEvent>,
36+
next_timeout: Instant,
37+
idle_timeout: Duration,
3438
}
3539

3640
impl GatewayHandler {
3741
pub fn new(server_states: Rc<RefCell<ServerStates>>) -> Self {
42+
let idle_timeout = server_states.borrow().server_config().idle_timeout;
43+
3844
GatewayHandler {
3945
server_states,
4046
transmits: VecDeque::new(),
47+
next_timeout: Instant::now().add(idle_timeout),
48+
idle_timeout,
4149
}
4250
}
4351
}
@@ -52,6 +60,23 @@ impl Handler for GatewayHandler {
5260
"GatewayHandler"
5361
}
5462

63+
fn transport_inactive(&mut self, _ctx: &Context<Self::Rin, Self::Rout, Self::Win, Self::Wout>) {
64+
let server_states = self.server_states.borrow();
65+
let sessions = server_states.get_sessions();
66+
let mut endpoint_count = 0;
67+
for session in sessions.values() {
68+
endpoint_count += session.get_endpoints().len();
69+
}
70+
info!(
71+
"Still Active Sessions {}, Endpoints {}/{}, Candidates {} on {}",
72+
sessions.len(),
73+
endpoint_count,
74+
server_states.get_endpoints().len(),
75+
server_states.get_candidates().len(),
76+
server_states.local_addr()
77+
);
78+
}
79+
5580
fn handle_read(
5681
&mut self,
5782
ctx: &Context<Self::Rin, Self::Rout, Self::Win, Self::Wout>,
@@ -115,9 +140,34 @@ impl Handler for GatewayHandler {
115140
fn handle_timeout(
116141
&mut self,
117142
_ctx: &Context<Self::Rin, Self::Rout, Self::Win, Self::Wout>,
118-
_now: Instant,
143+
now: Instant,
119144
) {
120145
// terminate timeout here, no more ctx.fire_handle_timeout(now);
146+
if self.next_timeout <= now {
147+
let mut four_tuples = vec![];
148+
let mut server_states = self.server_states.borrow_mut();
149+
for session in server_states.get_mut_sessions().values_mut() {
150+
for endpoint in session.get_mut_endpoints().values_mut() {
151+
for transport in endpoint.get_mut_transports().values_mut() {
152+
if transport.last_activity() <= now.sub(self.idle_timeout) {
153+
four_tuples.push(*transport.four_tuple());
154+
}
155+
}
156+
}
157+
}
158+
for four_tuple in four_tuples {
159+
server_states.remove_transport(four_tuple);
160+
}
161+
162+
self.next_timeout = self.next_timeout.add(self.idle_timeout);
163+
}
164+
}
165+
166+
fn poll_timeout(&mut self, ctx: &Context<Self::Rin, Self::Rout, Self::Win, Self::Wout>, eto: &mut Instant) {
167+
if self.next_timeout < *eto {
168+
*eto = self.next_timeout;
169+
}
170+
ctx.fire_poll_timeout(eto);
121171
}
122172

123173
fn poll_write(
@@ -127,7 +177,6 @@ impl Handler for GatewayHandler {
127177
if let Some(msg) = ctx.fire_poll_write() {
128178
self.transmits.push_back(msg);
129179
}
130-
131180
self.transmits.pop_front()
132181
}
133182
}
@@ -387,6 +436,7 @@ impl GatewayHandler {
387436
rtp_packet: rtp::packet::Packet,
388437
) -> Result<Vec<TaggedMessageEvent>> {
389438
debug!("handle_rtp_message {}", transport_context.peer_addr);
439+
server_states.get_mut_transport(&(&transport_context).into())?.keep_alive();
390440

391441
//TODO: Selective Forwarding RTP Packets
392442
let peers =
@@ -411,6 +461,7 @@ impl GatewayHandler {
411461
rtcp_packets: Vec<Box<dyn rtcp::packet::Packet>>,
412462
) -> Result<Vec<TaggedMessageEvent>> {
413463
debug!("handle_rtcp_message {}", transport_context.peer_addr);
464+
server_states.get_mut_transport(&(&transport_context).into())?.keep_alive();
414465

415466
//TODO: Selective Forwarding RTCP Packets
416467
let peers =

src/handler/stun.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct StunHandler;
1111

1212
impl StunHandler {
1313
pub fn new() -> Self {
14-
StunHandler::default()
14+
StunHandler
1515
}
1616
}
1717

src/server/config.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub struct ServerConfig {
1010
pub(crate) sctp_endpoint_config: Arc<sctp::EndpointConfig>,
1111
pub(crate) sctp_server_config: Arc<sctp::ServerConfig>,
1212
pub(crate) media_config: MediaConfig,
13-
pub(crate) endpoint_idle_timeout: Duration,
14-
pub(crate) candidate_idle_timeout: Duration,
13+
pub(crate) idle_timeout: Duration,
1514
}
1615

1716
impl ServerConfig {
@@ -23,8 +22,7 @@ impl ServerConfig {
2322
sctp_endpoint_config: Arc::new(sctp::EndpointConfig::default()),
2423
sctp_server_config: Arc::new(sctp::ServerConfig::default()),
2524
dtls_handshake_config: Arc::new(dtls::config::HandshakeConfig::default()),
26-
endpoint_idle_timeout: Duration::from_secs(30),
27-
candidate_idle_timeout: Duration::from_secs(30),
25+
idle_timeout: Duration::from_secs(30),
2826
}
2927
}
3028

@@ -58,15 +56,9 @@ impl ServerConfig {
5856
self
5957
}
6058

61-
/// build with endpoint idle timeout
62-
pub fn with_endpoint_idle_timeout(mut self, endpoint_idle_timeout: Duration) -> Self {
63-
self.endpoint_idle_timeout = endpoint_idle_timeout;
64-
self
65-
}
66-
67-
/// build with candidate idle timeout
68-
pub fn with_candidate_idle_timeout(mut self, candidate_idle_timeout: Duration) -> Self {
69-
self.candidate_idle_timeout = candidate_idle_timeout;
59+
/// build with idle timeout
60+
pub fn with_idle_timeout(mut self, idle_timeout: Duration) -> Self {
61+
self.idle_timeout = idle_timeout;
7062
self
7163
}
7264
}

src/server/states.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::endpoint::{
77
use crate::server::config::ServerConfig;
88
use crate::session::{config::SessionConfig, Session};
99
use crate::types::{EndpointId, FourTuple, SessionId, UserName};
10-
use log::info;
10+
use log::{debug, info};
1111
use shared::error::{Error, Result};
1212
use std::collections::hash_map::Entry;
1313
use std::collections::HashMap;
@@ -101,7 +101,7 @@ impl ServerStates {
101101
local_conn_cred,
102102
offer,
103103
answer.clone(),
104-
Instant::now() + self.server_config.candidate_idle_timeout,
104+
Instant::now() + self.server_config.idle_timeout,
105105
)));
106106
}
107107

@@ -162,6 +162,10 @@ impl ServerStates {
162162
self.sessions.get_mut(session_id)
163163
}
164164

165+
pub(crate) fn remove_session(&mut self, session_id: &SessionId) -> Option<Session> {
166+
self.sessions.remove(session_id)
167+
}
168+
165169
pub(crate) fn add_candidate(&mut self, candidate: Rc<Candidate>) -> Option<Rc<Candidate>> {
166170
let username = candidate.username();
167171
self.candidates.insert(username, candidate)
@@ -175,6 +179,14 @@ impl ServerStates {
175179
self.candidates.get(username)
176180
}
177181

182+
pub(crate) fn get_candidates(&self) -> &HashMap<UserName, Rc<Candidate>> {
183+
&self.candidates
184+
}
185+
186+
pub(crate) fn get_endpoints(&self) -> &HashMap<FourTuple, (SessionId, EndpointId)> {
187+
&self.endpoints
188+
}
189+
178190
pub(crate) fn add_endpoint(
179191
&mut self,
180192
four_tuple: FourTuple,
@@ -242,4 +254,30 @@ impl ServerStates {
242254

243255
Ok(transport)
244256
}
257+
258+
pub(crate) fn remove_transport(&mut self, four_tuple: FourTuple) {
259+
debug!("remove idle transport {:?}", four_tuple);
260+
261+
let Some((session_id, endpoint_id)) = self.find_endpoint(&four_tuple) else {
262+
return;
263+
};
264+
let Some(session) = self.get_mut_session(&session_id) else {
265+
return;
266+
};
267+
let Some(endpoint) = session.get_mut_endpoint(&endpoint_id) else {
268+
return;
269+
};
270+
271+
let transport = endpoint.remove_transport(&four_tuple);
272+
if endpoint.get_transports().is_empty() {
273+
session.remove_endpoint(&endpoint_id);
274+
if session.get_endpoints().is_empty() {
275+
self.remove_session(&session_id);
276+
}
277+
self.remove_endpoint(&four_tuple);
278+
}
279+
if let Some(transport) = transport {
280+
self.remove_candidate(&transport.candidate().username());
281+
}
282+
}
245283
}

src/session/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ impl Session {
110110
self.endpoints.get_mut(endpoint_id)
111111
}
112112

113+
pub(crate) fn remove_endpoint(&mut self, endpoint_id: &EndpointId) -> Option<Endpoint> {
114+
self.endpoints.remove(endpoint_id)
115+
}
116+
113117
pub(crate) fn has_endpoint(&self, endpoint_id: &EndpointId) -> bool {
114118
self.endpoints.contains_key(endpoint_id)
115119
}

0 commit comments

Comments
 (0)