diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 6ba395d25..2a8ce0501 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -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; diff --git a/include/call.h b/include/call.h index 96d03fcc4..470ff72db 100644 --- a/include/call.h +++ b/include/call.h @@ -401,6 +401,7 @@ struct endpoint_map { struct loop_protector { unsigned int len; unsigned char buf[RTP_LOOP_PROTECT]; + int64_t recv_us; }; diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 6a8cc3800..5a7a83035 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -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', { }, <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();