Skip to content

Commit 03237d0

Browse files
authored
Bugfix/fix turn unit test memory leak (#626)
* Fix cyclic dependency in ChannelBind/Permission - Both structs have a timer-callback like mechanism to remove itself from the table which held by Allocation. In this case, cyclic dependency is created when the struct holds Arc<> pointing to the table owning it. We replace the Arc<> in the callback with Weak<> * Fix cyclic dependency in Allocation - Allocation hold Arc<> to the table of Allocations owned by AllocationManager and thus creates the cyclic dependency. We replace it with Weak<> when pointing to parent
1 parent 2ec027f commit 03237d0

File tree

6 files changed

+37
-16
lines changed

6 files changed

+37
-16
lines changed

turn/src/allocation/allocation_manager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct ManagerConfig {
2020

2121
/// `Manager` is used to hold active allocations.
2222
pub struct Manager {
23-
allocations: AllocationMap,
23+
allocations: Arc<Mutex<AllocationMap>>,
2424
reservations: Arc<Mutex<HashMap<String, u16>>>,
2525
relay_addr_generator: Box<dyn RelayAddressGenerator + Send + Sync>,
2626
alloc_close_notify: Option<mpsc::Sender<AllocationInfo>>,
@@ -107,9 +107,9 @@ impl Manager {
107107
relay_addr,
108108
five_tuple,
109109
username,
110+
Arc::downgrade(&self.allocations),
110111
self.alloc_close_notify.clone(),
111112
);
112-
a.allocations = Some(Arc::clone(&self.allocations));
113113

114114
log::debug!("listening on relay addr: {:?}", a.relay_addr);
115115
a.start(lifetime).await;

turn/src/allocation/allocation_test.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ async fn test_has_permission() -> Result<()> {
1212
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
1313
let relay_socket = Arc::clone(&turn_socket);
1414
let relay_addr = relay_socket.local_addr()?;
15+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
1516
let a = Allocation::new(
1617
turn_socket,
1718
relay_socket,
1819
relay_addr,
1920
FiveTuple::default(),
2021
TextAttribute::new(ATTR_USERNAME, "user".into()),
22+
Arc::downgrade(&allocations),
2123
None,
2224
);
2325

@@ -50,12 +52,14 @@ async fn test_add_permission() -> Result<()> {
5052
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
5153
let relay_socket = Arc::clone(&turn_socket);
5254
let relay_addr = relay_socket.local_addr()?;
55+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
5356
let a = Allocation::new(
5457
turn_socket,
5558
relay_socket,
5659
relay_addr,
5760
FiveTuple::default(),
5861
TextAttribute::new(ATTR_USERNAME, "user".into()),
62+
Arc::downgrade(&allocations),
5963
None,
6064
);
6165

@@ -74,12 +78,14 @@ async fn test_remove_permission() -> Result<()> {
7478
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
7579
let relay_socket = Arc::clone(&turn_socket);
7680
let relay_addr = relay_socket.local_addr()?;
81+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
7782
let a = Allocation::new(
7883
turn_socket,
7984
relay_socket,
8085
relay_addr,
8186
FiveTuple::default(),
8287
TextAttribute::new(ATTR_USERNAME, "user".into()),
88+
Arc::downgrade(&allocations),
8389
None,
8490
);
8591

@@ -107,12 +113,14 @@ async fn test_add_channel_bind() -> Result<()> {
107113
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
108114
let relay_socket = Arc::clone(&turn_socket);
109115
let relay_addr = relay_socket.local_addr()?;
116+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
110117
let a = Allocation::new(
111118
turn_socket,
112119
relay_socket,
113120
relay_addr,
114121
FiveTuple::default(),
115122
TextAttribute::new(ATTR_USERNAME, "user".into()),
123+
Arc::downgrade(&allocations),
116124
None,
117125
);
118126

@@ -141,12 +149,14 @@ async fn test_get_channel_by_number() -> Result<()> {
141149
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
142150
let relay_socket = Arc::clone(&turn_socket);
143151
let relay_addr = relay_socket.local_addr()?;
152+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
144153
let a = Allocation::new(
145154
turn_socket,
146155
relay_socket,
147156
relay_addr,
148157
FiveTuple::default(),
149158
TextAttribute::new(ATTR_USERNAME, "user".into()),
159+
Arc::downgrade(&allocations),
150160
None,
151161
);
152162

@@ -177,12 +187,14 @@ async fn test_get_channel_by_addr() -> Result<()> {
177187
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
178188
let relay_socket = Arc::clone(&turn_socket);
179189
let relay_addr = relay_socket.local_addr()?;
190+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
180191
let a = Allocation::new(
181192
turn_socket,
182193
relay_socket,
183194
relay_addr,
184195
FiveTuple::default(),
185196
TextAttribute::new(ATTR_USERNAME, "user".into()),
197+
Arc::downgrade(&allocations),
186198
None,
187199
);
188200

@@ -209,12 +221,14 @@ async fn test_remove_channel_bind() -> Result<()> {
209221
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
210222
let relay_socket = Arc::clone(&turn_socket);
211223
let relay_addr = relay_socket.local_addr()?;
224+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
212225
let a = Allocation::new(
213226
turn_socket,
214227
relay_socket,
215228
relay_addr,
216229
FiveTuple::default(),
217230
TextAttribute::new(ATTR_USERNAME, "user".into()),
231+
Arc::downgrade(&allocations),
218232
None,
219233
);
220234

@@ -246,12 +260,14 @@ async fn test_allocation_refresh() -> Result<()> {
246260
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
247261
let relay_socket = Arc::clone(&turn_socket);
248262
let relay_addr = relay_socket.local_addr()?;
263+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
249264
let a = Allocation::new(
250265
turn_socket,
251266
relay_socket,
252267
relay_addr,
253268
FiveTuple::default(),
254269
TextAttribute::new(ATTR_USERNAME, "user".into()),
270+
Arc::downgrade(&allocations),
255271
None,
256272
);
257273

@@ -268,12 +284,14 @@ async fn test_allocation_close() -> Result<()> {
268284
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
269285
let relay_socket = Arc::clone(&turn_socket);
270286
let relay_addr = relay_socket.local_addr()?;
287+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
271288
let a = Allocation::new(
272289
turn_socket,
273290
relay_socket,
274291
relay_addr,
275292
FiveTuple::default(),
276293
TextAttribute::new(ATTR_USERNAME, "user".into()),
294+
Arc::downgrade(&allocations),
277295
None,
278296
);
279297

turn/src/allocation/channel_bind.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
mod channel_bind_test;
33

44
use std::sync::atomic::Ordering;
5-
use std::sync::Arc;
5+
use std::sync::{Arc, Weak};
66

77
use portable_atomic::AtomicBool;
88
use tokio::sync::Mutex;
@@ -18,7 +18,7 @@ use crate::proto::channum::*;
1818
pub struct ChannelBind {
1919
pub(crate) peer: SocketAddr,
2020
pub(crate) number: ChannelNumber,
21-
pub(crate) channel_bindings: Option<Arc<Mutex<HashMap<ChannelNumber, ChannelBind>>>>,
21+
pub(crate) channel_bindings: Option<Weak<Mutex<HashMap<ChannelNumber, ChannelBind>>>>,
2222
reset_tx: Option<mpsc::Sender<Duration>>,
2323
timer_expired: Arc<AtomicBool>,
2424
}
@@ -51,7 +51,7 @@ impl ChannelBind {
5151
while !done {
5252
tokio::select! {
5353
_ = &mut timer => {
54-
if let Some(cbs) = &channel_bindings{
54+
if let Some(cbs) = &channel_bindings.clone().and_then(|x| x.upgrade()) {
5555
let mut cb = cbs.lock().await;
5656
if cb.remove(&number).is_none() {
5757
log::error!("Failed to remove ChannelBind for {}", number);

turn/src/allocation/channel_bind/channel_bind_test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ async fn create_channel_bind(lifetime: Duration) -> Result<Allocation> {
1212
let turn_socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
1313
let relay_socket = Arc::clone(&turn_socket);
1414
let relay_addr = relay_socket.local_addr()?;
15+
let allocations = Arc::new(Mutex::new(AllocationMap::new()));
1516
let a = Allocation::new(
1617
turn_socket,
1718
relay_socket,
1819
relay_addr,
1920
FiveTuple::default(),
2021
TextAttribute::new(ATTR_USERNAME, "user".into()),
22+
Arc::downgrade(&allocations),
2123
None,
2224
);
2325

turn/src/allocation/mod.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::collections::HashMap;
1010
use std::marker::{Send, Sync};
1111
use std::net::SocketAddr;
1212
use std::sync::atomic::Ordering;
13-
use std::sync::Arc;
13+
use std::sync::{Arc, Weak};
1414

1515
use channel_bind::*;
1616
use five_tuple::*;
@@ -34,7 +34,7 @@ use crate::proto::*;
3434

3535
const RTP_MTU: usize = 1500;
3636

37-
pub type AllocationMap = Arc<Mutex<HashMap<FiveTuple, Arc<Allocation>>>>;
37+
pub type AllocationMap = HashMap<FiveTuple, Arc<Allocation>>;
3838

3939
/// Information about an [`Allocation`].
4040
#[derive(Debug, Clone)]
@@ -77,7 +77,7 @@ pub struct Allocation {
7777
username: Username,
7878
permissions: Arc<Mutex<HashMap<String, Permission>>>,
7979
channel_bindings: Arc<Mutex<HashMap<ChannelNumber, ChannelBind>>>,
80-
pub(crate) allocations: Option<AllocationMap>,
80+
allocations: Weak<Mutex<AllocationMap>>,
8181
reset_tx: SyncMutex<Option<mpsc::Sender<Duration>>>,
8282
timer_expired: Arc<AtomicBool>,
8383
closed: AtomicBool, // Option<mpsc::Receiver<()>>,
@@ -98,6 +98,7 @@ impl Allocation {
9898
relay_addr: SocketAddr,
9999
five_tuple: FiveTuple,
100100
username: Username,
101+
allocation_map: Weak<Mutex<AllocationMap>>,
101102
alloc_close_notify: Option<mpsc::Sender<AllocationInfo>>,
102103
) -> Self {
103104
Allocation {
@@ -109,7 +110,7 @@ impl Allocation {
109110
username,
110111
permissions: Arc::new(Mutex::new(HashMap::new())),
111112
channel_bindings: Arc::new(Mutex::new(HashMap::new())),
112-
allocations: None,
113+
allocations: allocation_map,
113114
reset_tx: SyncMutex::new(None),
114115
timer_expired: Arc::new(AtomicBool::new(false)),
115116
closed: AtomicBool::new(false),
@@ -137,7 +138,7 @@ impl Allocation {
137138
}
138139
}
139140

140-
p.permissions = Some(Arc::clone(&self.permissions));
141+
p.permissions = Some(Arc::downgrade(&self.permissions));
141142
p.start(PERMISSION_TIMEOUT).await;
142143

143144
{
@@ -184,7 +185,7 @@ impl Allocation {
184185
let peer = c.peer;
185186

186187
// Add or refresh this channel.
187-
c.channel_bindings = Some(Arc::clone(&self.channel_bindings));
188+
c.channel_bindings = Some(Arc::downgrade(&self.channel_bindings));
188189
c.start(lifetime).await;
189190

190191
{
@@ -279,7 +280,7 @@ impl Allocation {
279280
while !done {
280281
tokio::select! {
281282
_ = &mut timer => {
282-
if let Some(allocs) = &allocations{
283+
if let Some(allocs) = &allocations.upgrade(){
283284
let mut allocs = allocs.lock().await;
284285
if let Some(a) = allocs.remove(&five_tuple) {
285286
let _ = a.close().await;
@@ -355,7 +356,7 @@ impl Allocation {
355356
match result {
356357
Ok((n, src_addr)) => (n, src_addr),
357358
Err(_) => {
358-
if let Some(allocs) = &allocations {
359+
if let Some(allocs) = &allocations.upgrade() {
359360
let mut allocs = allocs.lock().await;
360361
allocs.remove(&five_tuple);
361362
}

turn/src/allocation/permission.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::sync::atomic::Ordering;
2-
use std::sync::Arc;
2+
use std::sync::{Arc, Weak};
33

44
use portable_atomic::AtomicBool;
55
use tokio::sync::Mutex;
@@ -15,7 +15,7 @@ pub(crate) const PERMISSION_TIMEOUT: Duration = Duration::from_secs(5 * 60);
1515
/// https://tools.ietf.org/html/rfc5766#section-2.3
1616
pub struct Permission {
1717
pub(crate) addr: SocketAddr,
18-
pub(crate) permissions: Option<Arc<Mutex<HashMap<String, Permission>>>>,
18+
pub(crate) permissions: Option<Weak<Mutex<HashMap<String, Permission>>>>,
1919
reset_tx: Option<mpsc::Sender<Duration>>,
2020
timer_expired: Arc<AtomicBool>,
2121
}
@@ -47,7 +47,7 @@ impl Permission {
4747
while !done {
4848
tokio::select! {
4949
_ = &mut timer => {
50-
if let Some(perms) = &permissions{
50+
if let Some(perms) = &permissions.clone().and_then(|x| x.upgrade()) {
5151
let mut p = perms.lock().await;
5252
p.remove(&addr2ipfingerprint(&addr));
5353
}

0 commit comments

Comments
 (0)