MT#55283 Defuse loop detection for duplicate packets that arrive >1s apart

Fixes #2153
Closes #2155

Change-Id: I24cf69b45a5a6810a96285da41fb3c8b0416bcae
pull/2142/merge
Alexander Bakker 3 days ago committed by Richard Fuchs
parent d524f838d9
commit 8c51cbb227

@ -2740,6 +2740,17 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
continue;
dbg_int("packet dupe");
/* not a loop if duplicates arrive more than 1s apart */
if (rtpe_now - phc->mp.stream->lp_buf[i].recv_us > 1000000LL) {
dbg_int("duplicate packet too old to indicate a loop, resetting count");
phc->mp.stream->lp_count = 0;
phc->mp.stream->lp_buf[i].recv_us = rtpe_now;
return 0;
}
phc->mp.stream->lp_buf[i].recv_us = rtpe_now;
if (phc->mp.stream->lp_count >= RTP_LOOP_MAX_COUNT) {
ilog(LOG_WARNING, "More than %d duplicate packets detected, dropping packet from %s%s%s"
"to avoid potential loop",
@ -2756,6 +2767,7 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
phc->mp.stream->lp_count = 0;
phc->mp.stream->lp_buf[phc->mp.stream->lp_idx].len = phc->s.len;
memcpy(phc->mp.stream->lp_buf[phc->mp.stream->lp_idx].buf, phc->s.s, MIN(phc->s.len, RTP_LOOP_PROTECT));
phc->mp.stream->lp_buf[phc->mp.stream->lp_idx].recv_us = rtpe_now;
phc->mp.stream->lp_idx = (phc->mp.stream->lp_idx + 1) % RTP_LOOP_PACKETS;
return 0;

@ -401,6 +401,7 @@ struct endpoint_map {
struct loop_protector {
unsigned int len;
unsigned char buf[RTP_LOOP_PROTECT];
int64_t recv_us;
};

@ -29646,6 +29646,81 @@ ok(!grep {$_ eq 'loop check'} @{$resp->{tags}{ft()}{medias}[0]{flags}},
# Scenario: duplicate packets arriving >1s apart should not trigger loop detection. With loop check
# enabled, 32 rapid identical packets trigger a drop. After waiting >1s, the time-based reset allows
# the same packet through again.
($sock_a, $sock_b) = new_call([qw(198.51.100.1 6140)], [qw(198.51.100.3 6142)]);
($port_a) = offer('loop detection time reset', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.14
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio 30140 RTP/AVP 0
a=sendrecv
----------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.14
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('loop detection time reset', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.14
s=tester
c=IN IP4 198.51.100.3
t=0 0
m=audio 6142 RTP/AVP 0
a=sendrecv
----------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.14
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
my $dup_pkt = rtp(0, 1000, 3000, 0x1234, "\x00" x 160);
my $dup_match = rtpm(0, 1000, 3000, 0x1234, "\x00" x 160);
# establish the call with a different packet first
snd($sock_a, $port_b, rtp(0, 999, 2000, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 999, 2000, 0x1234, "\x00" x 160));
# send 31 identical packets
for (1..31) {
snd($sock_a, $port_b, $dup_pkt);
rcv($sock_b, $port_a, $dup_match);
}
# 32nd packet, dropped
snd($sock_a, $port_b, $dup_pkt);
rcv_no($sock_b, $port_a);
# 32nd packet, dropped again
snd($sock_a, $port_b, $dup_pkt);
rcv_no($sock_b, $port_a);
# after >1s, the 32nd packet passes through
sleep(2);
snd($sock_a, $port_b, $dup_pkt);
rcv($sock_b, $port_a, $dup_match);
#done_testing;NGCP::Rtpengine::AutoTest::terminate('f00');exit;
done_testing();

Loading…
Cancel
Save