Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions daemon/media_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ struct endpoint_map {
struct loop_protector {
unsigned int len;
unsigned char buf[RTP_LOOP_PROTECT];
int64_t recv_us;
};


Expand Down
75 changes: 75 additions & 0 deletions t/auto-daemon-tests.pl
Original file line number Diff line number Diff line change
Expand Up @@ -29646,6 +29646,81 @@



# 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