From 250df2af5e1d56315c86339460438528afdb0102 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 27 Jun 2026 13:05:13 +0200 Subject: [PATCH] MT#55283 Unref ports after re-subscribe Previously, the ports used for a monologue subscription would leak upon re-subscribe. ``__assign_stream_fds`` cleared the stream fd queue without decrementing the ref count. This prevented ``monologue_destroy`` from releasing the ports on unsubscribe. Closes #2125 Change-Id: Ib86290d6a35e2388e34098f2847f1e34b3db2c5d --- daemon/call.c | 8 +++++--- perl/NGCP/Rtpengine/AutoTest.pm | 6 +++++- t/auto-daemon-tests-alias.pl | 29 ++++------------------------- t/auto-daemon-tests-create.pl | 10 +++++----- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index f258b8505..1f433bd61 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -906,7 +906,7 @@ static void __assign_stream_fds(struct call_media *media, sfd_intf_list_q *intf_ // use opaque pointer to detect changes void *old_selected_sfd = ps->selected_sfd; - t_queue_clear(&ps->sfds); + t_queue_clear_full(&ps->sfds, stream_fd_dec); bool sfd_found = false; stream_fd *intf_sfd = NULL; @@ -3541,10 +3541,12 @@ static void monologue_bundle_set_fds(struct call_monologue *ml) { dtls_shutdown(ms); // XXX close sockets that are not needed? - t_queue_clear(&ms->sfds); + t_queue_clear_full(&ms->sfds, stream_fd_dec); - for (__auto_type sl = bs->sfds.head; sl; sl = sl->next) + for (__auto_type sl = bs->sfds.head; sl; sl = sl->next) { + stream_fd_inc(sl->data); t_queue_push_tail(&ms->sfds, sl->data); + } ms->selected_sfd = bs->selected_sfd; diff --git a/perl/NGCP/Rtpengine/AutoTest.pm b/perl/NGCP/Rtpengine/AutoTest.pm index 2608dc503..8a501d42b 100644 --- a/perl/NGCP/Rtpengine/AutoTest.pm +++ b/perl/NGCP/Rtpengine/AutoTest.pm @@ -23,7 +23,7 @@ our $port; BEGIN { require Exporter; @ISA = qw(Exporter); - our @EXPORT = qw(autotest_start new_call new_call_nc offer answer ft tt cid snd srtp_snd rtp rcv srtp_rcv rcv_no rcv_maybe + our @EXPORT = qw(autotest_start new_call new_call_nc offer answer ft tt cid snd snd_no srtp_snd rtp rcv srtp_rcv rcv_no rcv_maybe srtp_dec escape rtpm rtpmre reverse_tags new_ft new_tt crlf sdp_split rtpe_req offer_answer autotest_init subscribe_request subscribe_answer publish create create_answer use_json rtpe_raw_req); @@ -223,6 +223,10 @@ sub snd { my ($sock, $dest, $packet, $addr) = @_; $sock->send($packet, 0, pack_sockaddr_in($dest, inet_aton($addr // '203.0.113.1'))) or die; } +sub snd_no { + my ($sock, $dest, $packet, $addr) = @_; + ok(!$sock->send($packet, 0, pack_sockaddr_in($dest, inet_aton($addr // '203.0.113.1'))), "send to closed port fails"); +} sub srtp_snd { my ($sock, $dest, $packet, $srtp_ctx, $addr) = @_; if (!$srtp_ctx->{skey}) { diff --git a/t/auto-daemon-tests-alias.pl b/t/auto-daemon-tests-alias.pl index f6250d2c6..21f11d7a3 100755 --- a/t/auto-daemon-tests-alias.pl +++ b/t/auto-daemon-tests-alias.pl @@ -227,19 +227,8 @@ rcv_no($sock_b); rcv_no($sock_c); rcv_no($sock_d); - -snd($sock_c, $port_d, rtp (0, 5002, 7320, 0x1234, "\x33" x 160)); -rcv_no($sock_a); -rcv_no($sock_b); -rcv_no($sock_c); -rcv_no($sock_d); - -snd($sock_d, $port_c, rtp (0, 7002, 9320, 0x1a04, "\x44" x 160)); -rcv_no($sock_a); -rcv_no($sock_b); -rcv_no($sock_c); -rcv_no($sock_d); - +snd_no($sock_c, $port_d, rtp (0, 5002, 7320, 0x1234, "\x33" x 160)); +snd_no($sock_d, $port_c, rtp (0, 7002, 9320, 0x1a04, "\x44" x 160)); @@ -429,18 +418,8 @@ rcv_no($sock_d); rtpe_req('delete', 'delete alias rev', { 'call-id' => $cid1, 'delete-delay' => 0 }); -snd($sock_a, $port_b, rtp (0, 1002, 3320, 0x1234, "\x11" x 160)); -rcv_no($sock_a); -rcv_no($sock_b); -rcv_no($sock_c); -rcv_no($sock_d); - -snd($sock_b, $port_a, rtp (0, 3002, 5320, 0x1a04, "\x22" x 160)); -rcv_no($sock_a); -rcv_no($sock_b); -rcv_no($sock_c); -rcv_no($sock_d); - +snd_no($sock_a, $port_b, rtp (0, 1002, 3320, 0x1234, "\x11" x 160)); +snd_no($sock_b, $port_a, rtp (0, 3002, 5320, 0x1a04, "\x22" x 160)); snd($sock_c, $port_d, rtp (0, 5002, 7320, 0x1234, "\x33" x 160)); rcv($sock_d, $port_c, rtpm(0, 5002, 7320, 0x1234, "\x33" x 160)); diff --git a/t/auto-daemon-tests-create.pl b/t/auto-daemon-tests-create.pl index 1bef22d0c..5980ac55f 100755 --- a/t/auto-daemon-tests-create.pl +++ b/t/auto-daemon-tests-create.pl @@ -381,7 +381,7 @@ rtpe_req('unsubscribe', 'extended connect w "all" bidirectional', { flags => [], }); -snd($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); +snd_no($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); rcv_no($sock_a); rcv_no($sock_b); rcv_no($sock_c); @@ -766,7 +766,7 @@ rtpe_req('unsubscribe', 'extended connect w from-tags bidirectional', { flags => [], }); -snd($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); +snd_no($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); rcv_no($sock_a); rcv_no($sock_b); rcv_no($sock_c); @@ -1144,7 +1144,7 @@ rtpe_req('unsubscribe', 'extended connect w from-tags', { flags => [], }); -snd($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); +snd_no($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); rcv_no($sock_a); rcv_no($sock_b); rcv_no($sock_c); @@ -1703,7 +1703,7 @@ rtpe_req('unsubscribe', 'extended connect bidirectional', { flags => [], }); -snd($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); +snd_no($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); rcv_no($sock_a); rcv_no($sock_b); rcv_no($sock_c); @@ -2249,7 +2249,7 @@ rtpe_req('unsubscribe', 'extended connect', { flags => [], }); -snd($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); +snd_no($sock_a, $port_b, rtp (0, 1011, 4760, 0x1234, "\x11" x 160)); rcv_no($sock_a); rcv_no($sock_b); rcv_no($sock_c);