#!/usr/bin/perl use strict; use warnings; use NGCP::Rtpengine::Test; use NGCP::Rtpclient::SRTP; use NGCP::Rtpengine::AutoTest; use Test::More; use POSIX; autotest_start(qw(--config-file=none -t -1 -i 203.0.113.1 -i 2001:db8:4321::1 -n 2223 -c 12345 -f -L 7 -E -u 2222 --log-level-internals=7)) or die; my ($sock_a, $sock_b, $sock_c, $sock_d, $port_a, $port_b, $port_c, $ssrc_a, $ssrc_b, $resp, $sock_ax, $sock_bx, $port_ax, $port_bx, $port_d, $sock_e, $port_e, $sock_cx, $port_cx, $srtp_ctx_a, $srtp_ctx_b, $srtp_ctx_a_rev, $srtp_ctx_b_rev, $ufrag_a, $ufrag_b, @ret1, @ret2, @ret3, @ret4, $srtp_key_a, $srtp_key_b, $ts, $seq, $tag_medias, $media_labels, $ftr, $ttr, $fts, $ttr2); use_json(1); ($sock_a, $sock_b, $sock_c, $sock_d) = new_call([qw(198.51.100.14 6150)], [qw(198.51.100.14 6152)], [qw(198.51.100.14 6154)]); ($port_a) = offer('SIPREC pause/resume', { }, < ft(), flags => ['SIPREC'] }, < $ttr }, < ft(), 'to-tag' => $ttr, flags => ['SIPREC'] }, < $ttr }, < ft(), 'to-tag' => $ttr, flags => ['SIPREC'] }, < $ttr }, < ft(), 'to-tag' => $ttr, flags => ['SIPREC', 'inactive'] }, < $ttr }, < ft(), 'to-tag' => $ttr, flags => ['SIPREC'] }, < $ttr }, < ft(), flags => ['egress'] }, < $ttr }, < {transcode => ['PCMA']} }, < ft(), flags => ['egress'] }, < $ttr }, < ft() }, < $ttr }, < ft(), flags => ['mirror RTCP'] }, < $ttr }, < ['all', 'SIPREC'] }, < tt(), medias => [ { index => 1, type => 'audio', label => '0', mode => 'sendrecv', }, ], }, { tag => ft(), medias => [ { index => 1, type => 'audio', label => '1', mode => 'sendrecv', }, ], }, ], 'tag-medias match'; is_deeply $media_labels, { '1' => { index => 1, type => 'audio', tag => ft(), mode => 'sendrecv', }, '0' => { index => 1, type => 'audio', tag => tt(), mode => 'sendrecv', }, }, 'media-labels match'; new_call; ($port_a) = offer('SIPREC sub w label', { label => 'caller' }, < 'called' }, < ['all', 'SIPREC'] }, < tt(), label => 'called', medias => [ { index => 1, type => 'audio', label => '0', mode => 'sendrecv', }, ], }, { tag => ft(), label => 'caller', medias => [ { index => 1, type => 'audio', label => '1', mode => 'sendrecv', }, ], }, ], 'tag-medias match'; is_deeply $media_labels, { '1' => { index => 1, type => 'audio', tag => ft(), label => 'caller', mode => 'sendrecv', }, '0' => { index => 1, type => 'audio', tag => tt(), label => 'called', mode => 'sendrecv', }, }, 'media-labels match'; ($sock_a, $sock_b, $sock_c, $sock_d) = new_call([qw(198.51.100.14 6080)], [qw(198.51.100.14 6082)], [qw(198.51.100.14 6084)], [qw(198.51.100.14 6086)]); ($port_a) = offer('"all" sub', { }, < ['all'] }, < $ttr, flags => ['allow transcoding'] }, < [ft(), tt()] }, < $ttr, flags => ['allow transcoding'] }, < ['from-tags-' . ft(), 'from-tags-' . tt()] }, < $ttr, flags => ['allow transcoding'] }, < [tt(), ft()] }, < $ttr, flags => ['allow transcoding'] }, < ft() }, < $ttr }, < tt(), 'to-tag' => ft() }, < tt(), 'to-tag' => ft() }, < ft(), 'to-tag' => $ttr }, < $ttr }, < tt(), 'to-tag' => ft() }, < tt(), 'to-tag' => ft() }, < ft(), 'to-tag' => $ttr }, < $ttr }, < ['all', 'SIPREC'] }, < $ttr }, < tt(), 'to-tag' => ft() }, < tt(), 'to-tag' => ft() }, < ['all', 'SIPREC'], 'to-tag' => $ttr }, < tt(), medias => [ { index => 1, type => 'audio', label => '0', mode => 'recvonly', }, ], }, { tag => ft(), medias => [ { index => 1, type => 'audio', label => '1', mode => 'sendonly', }, ], }, ], 'SIPREC sub pause/resume - tag-medias match'; is_deeply $media_labels, { '1' => { index => 1, type => 'audio', tag => ft(), mode => 'sendonly', }, '0' => { index => 1, type => 'audio', tag => tt(), mode => 'recvonly', }, }, 'SIPREC sub pause/resume - media-labels match'; subscribe_answer('SIPREC sub pause/resume', { 'to-tag' => $ttr }, < tt(), 'to-tag' => ft() }, < tt(), 'to-tag' => ft() }, < ['all', 'SIPREC'], 'to-tag' => $ttr }, < tt(), medias => [ { index => 1, type => 'audio', label => '0', mode => 'sendrecv', }, ], }, { tag => ft(), medias => [ { index => 1, type => 'audio', label => '1', mode => 'sendrecv', }, ], }, ], 'SIPREC sub pause/resume - tag-medias match'; is_deeply $media_labels, { '1' => { index => 1, type => 'audio', tag => ft(), mode => 'sendrecv', }, '0' => { index => 1, type => 'audio', tag => tt(), mode => 'sendrecv', }, }, 'SIPREC sub pause/resume - media-labels match'; subscribe_answer('SIPREC sub pause/resume', { 'to-tag' => $ttr }, < ft(), 'to-tag' => tt() }, < ft(), 'to-tag' => tt() }, < ['all', 'SIPREC'], 'to-tag' => $ttr }, < tt(), medias => [ { index => 1, type => 'audio', label => '0', mode => 'sendonly', }, ], }, { tag => ft(), medias => [ { index => 1, type => 'audio', label => '1', mode => 'recvonly', }, ], }, ], 'tag-medias match'; is_deeply $media_labels, { '1' => { index => 1, type => 'audio', tag => ft(), mode => 'recvonly', }, '0' => { index => 1, type => 'audio', tag => tt(), mode => 'sendonly', }, }, 'media-labels match'; subscribe_answer('SIPREC sub pause/resume', { 'to-tag' => $ttr }, < ft() }, < $ttr, flags => ['allow transcoding'] }, < ft(), codec => { transcode => ['PCMA'] } }, < ft(), 'to-tag' => $ttr, flags => ['allow transcoding'] }, < ft(), codec => { transcode => ['PCMA'] } }, < $ttr }, < ft(), codec => {transcode => ['PCMA', 'G722', 'G723'] } }, < $ttr }, < ft(), codec => {transcode => ['PCMA', 'G722', 'G723'] } }, < $ttr, flags => ['allow transcoding'] }, < ft(), codec => {transcode => ['PCMA', 'G722', 'G723'] } }, < $ttr, flags => ['allow transcoding'] }, < ft() }, < $ttr }, < 'foo' }, < 'bar' }, < 'foo' }, < $ttr }, < 'foo' }, < 'bar' }, < 'bar' }, < $ttr }, < ft(), 'transport-protocol' => 'RTP/SAVP', SDES => ['no-AEAD_AES_256_GCM', 'no-AEAD_AES_128_GCM'] }, < $ttr }, < $NGCP::Rtpclient::SRTP::crypto_suites{AES_256_CM_HMAC_SHA1_80}, key => $srtp_key_a, }; snd($sock_b, $port_a, rtp(0, 2001, 4160, 0x3456, "\x00" x 160)); rcv($sock_a, $port_b, rtpm(0, 2001, 4160, $ssrc_a, "\x00" x 160)); snd($sock_a, $port_b, rtp(0, 4001, 7160, 0x6543, "\x00" x 160)); rcv($sock_b, $port_a, rtpm(0, 4001, 7160, $ssrc_b, "\x00" x 160)); srtp_rcv($sock_c, $port_c, rtpm(0, 4001, 7160, $ssrc_b, "\x00" x 160), $srtp_ctx_a); ($sock_a, $sock_b, $sock_c) = new_call([qw(198.51.100.14 6012)], [qw(198.51.100.14 6014)], [qw(198.51.100.14 6016)]); ($port_a) = offer('SRTP sub', { }, < ft(), 'transport-protocol' => 'RTP/SAVP', SDES => ['no-AEAD_AES_256_GCM', 'no-AEAD_AES_128_GCM'] }, < $ttr }, < $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80}, key => $srtp_key_a, }; snd($sock_b, $port_a, rtp(0, 2001, 4160, 0x3456, "\x00" x 160)); rcv($sock_a, $port_b, rtpm(0, 2001, 4160, $ssrc_a, "\x00" x 160)); snd($sock_a, $port_b, rtp(0, 4001, 7160, 0x6543, "\x00" x 160)); rcv($sock_b, $port_a, rtpm(0, 4001, 7160, $ssrc_b, "\x00" x 160)); srtp_rcv($sock_c, $port_c, rtpm(0, 4001, 7160, $ssrc_b, "\x00" x 160), $srtp_ctx_a); ($sock_a, $sock_b, $sock_c) = new_call([qw(198.51.100.14 6018)], [qw(198.51.100.14 6020)], [qw(198.51.100.14 6022)]); ($port_a) = offer('SRTP call RTP sub', { }, < $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80}, key => 'DVM+BTeYX2UI1LaA9bgXrcBEDBxoItA9/39fSoRF', }; $srtp_ctx_b = { cs => $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80}, key => 'eMlRvW8mWU4WodT9JOvAM+pn6I0/EXOhT9n0KeKk', }; srtp_snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x3456, "\x00" x 160), $srtp_ctx_b); ($ssrc_a) = srtp_rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160), $srtp_ctx_b); srtp_snd($sock_a, $port_b, rtp(0, 4000, 7000, 0x6543, "\x00" x 160), $srtp_ctx_a); ($ssrc_b) = srtp_rcv($sock_b, $port_a, rtpm(0, 4000, 7000, -1, "\x00" x 160), $srtp_ctx_a); ($ftr, $ttr, undef, undef, undef, $port_c) = subscribe_request('SRTP call RTP sub', { 'from-tag' => ft(), 'transport-protocol' => 'RTP/AVP', }, < $ttr }, < ft(), ICE => 'force' }, < $ttr }, < ft() }, < $ttr }, < ft() }, < $ttr }, < { accept => ['PCMA'] } }, < ft() }, < $ttr }, < ft() }, < $ttr }, < ft() }, < $ttr }, < ft(), codec => { strip => ['PCMA'], transcode => ['PCMU'] } }, < $ttr, flags => ['allow transcoding'] }, < [ $ftr, $fts ] }, <