From 30775b53ad0c43f01ee089064541feead5468608 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 8 Jul 2026 13:48:47 -0400 Subject: [PATCH] MT#55283 add kernel API test Change-Id: I5d082fa0fc93b77eb2dae4a16722b27d7f4cdc99 --- t/Makefile | 9 +- t/auto-daemon-tests-kernel-api.pl | 682 ++++++++++++++++++++++++++++++ t/tests-preload.c | 57 ++- 3 files changed, 742 insertions(+), 6 deletions(-) create mode 100755 t/auto-daemon-tests-kernel-api.pl diff --git a/t/Makefile b/t/Makefile index 89e7cc6de..ea99aefe3 100644 --- a/t/Makefile +++ b/t/Makefile @@ -82,7 +82,8 @@ include ../lib/common.Makefile daemon-tests-transform daemon-tests-http daemon-tests-heuristic daemon-tests-asymmetric \ daemon-tests-dtx-no-shift daemon-tests-rtcp daemon-tests-redis-subscribe daemon-tests-rtp-ext \ daemon-tests-bundle daemon-tests-dtls \ - daemon-tests-recording daemon-tests-create daemon-tests-alias + daemon-tests-recording daemon-tests-create daemon-tests-alias \ + daemon-tests-kernel-api TESTS := test-bitstr aes-crypt aead-aes-crypt test-const_str_hash.strhash ifeq ($(with_transcoding),yes) @@ -133,7 +134,8 @@ daemon-tests: daemon-tests-main daemon-tests-jb daemon-tests-pubsub daemon-tests daemon-tests-bundle daemon-tests-dtls \ daemon-tests-recording daemon-tests-create \ daemon-tests-dtx daemon-tests-dtx-cn daemon-tests-dtx-no-shift \ - daemon-tests-alias + daemon-tests-alias \ + daemon-tests-kernel-api daemon-test-deps: tests-preload.so $(MAKE) -C ../daemon @@ -280,6 +282,9 @@ daemon-tests-dtls: daemon-test-deps daemon-tests-recording: daemon-test-deps ./auto-test-helper "$@" perl -I../perl auto-daemon-tests-recording.pl +daemon-tests-kernel-api: daemon-test-deps + ./auto-test-helper "$@" perl -I../perl auto-daemon-tests-kernel-api.pl + test-bitstr: test-bitstr.o test-mix-buffer: test-mix-buffer.o \ diff --git a/t/auto-daemon-tests-kernel-api.pl b/t/auto-daemon-tests-kernel-api.pl new file mode 100755 index 000000000..19ab69b64 --- /dev/null +++ b/t/auto-daemon-tests-kernel-api.pl @@ -0,0 +1,682 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use NGCP::Rtpengine::Test; +use NGCP::Rtpclient::SRTP; +use NGCP::Rtpengine::AutoTest; +use Test::More; +use Test2::Tools::Compare qw(); +use NGCP::Rtpclient::ICE; +use POSIX; +use Socket; +use IO::Socket::UNIX; +use Data::Dumper; +use Errno; + + +$ENV{RTPENGINE_EXTENDED_TESTS} or exit(); # tests only valid on amd64 + + +local $ENV{MOCK_PEER} = ($ENV{TEST_SOCKET_PATH} || '.') . '/intf.sock'; + +my $kintf = IO::Socket::UNIX->new(Type => SOCK_DGRAM(), Local => $ENV{MOCK_PEER}); + +local $ENV{MOCK_0} = '/proc/rtpengine/control'; +local $ENV{MOCK_1} = '/proc/rtpengine/42/control'; + +$NGCP::Rtpengine::AutoTest::launch_cb = sub { + my $buf; + + my ($addr) = $kintf->recv($buf, 1024); + my ($msg, $text) = unpack("i! Z*", $buf); + is($msg, 1, "open message"); + is($text, "/proc/rtpengine/control", "open control"); + $kintf->send(pack('ii', 1, 0), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + is($text, "del 42\n", "del msg"); + $kintf->send(pack('ii', 3, -Errno::ENOENT), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i!", $buf); + is($msg, 4, "close message"); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! Z*", $buf); + is($msg, 1, "open message"); + is($text, "/proc/rtpengine/42/control", "open table control"); + $kintf->send(pack('ii', 1, 0), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + my ($code, $a, $l) = unpack('i! x![L!] L!L!', $text); + is($code, 16, "pin memory msg"); + is($l, 16777216, "pin memory size"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + ($code, $l) = unpack('i! x![L!] i! x![L!] L![18] L!', $text); + is($code, 1, "init msg"); + is($l, 18, "last msg code"); + # skip verify msg lengths + $kintf->send(pack('ii', 3, length($text)), 0, $addr); +}; + +autotest_start(qw(--config-file=none -t 42 -i 203.0.113.1 -i 2001:db8:4321::1 + -n 2223 -f -L 7 -E --log-level-internals=7 --no-fallback + --nftables-chain=)) + or die; + + +my $extended_tests = $ENV{RTPENGINE_EXTENDED_TESTS}; + + +my ($sock_a, $sock_b, $sock_c, $sock_d, $port_a, $port_b, $ssrc, $ssrc_b, $resp, + $sock_ax, $sock_bx, $port_ax, $port_bx, $t_a, $t_b, $t_c, $t_d, + $sock_cx, $sock_dx, $port_c, $port_d, $port_cx, $port_dx, + $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, $has_recv, $tmp_blob, + $pwd_a, $pwd_b, $packet, $tid, $buf, $addr, $msg, $text, + $code, $lfam, $laddr, $lport, $efam, $eaddr, $eport, $mismatch, $numdest, + $intcp, @g, @decr, @ssrc, @ssrcst, @ssrci, @ptst, @ptmi, $npts, $midmap, + @mid, $iface, $stats, @rbuf, $flags, $idx, $sfam, $saddr, $sport, $dfam, $daddr, + $dport, $midx, @encr, @seqs, @pto, $nexf, $exmid, $exmidlen, $exmids, $tos, %dict); + + + +undef $NGCP::Rtpengine::AutoTest::launch_cb; + + + +sub add_target { + my $buf; + my ($addr) = $kintf->recv($buf, 4096); + my ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + my (%ret, $code); + ($code, + $ret{lfam}, $ret{laddr}, $ret{lport}, + $ret{efam}, $ret{eaddr}, $ret{eport}, + $ret{mismatch}, $ret{numdest}, $ret{intcp}, + @{$ret{g}}[0..31], + @{$ret{decr}}[0..11], + @{$ret{ssrc}}[0..3], @{$ret{ssrcst}}[0..3], @{$ret{ssrci}}[0..3], + @{$ret{ptst}}[0..31], + @{$ret{ptmi}}[0..31], + $ret{npts}, $ret{midmap}, + @{$ret{mid}}[0..15], + $ret{iface}, $ret{stats}, + @{$ret{rbuf}}[0..3], $ret{flags}) + = unpack('i! x![L!] (i! L x12 S x[S])[2] i! i! i! (i! i! i! i!)[8] (i! i! a32 i! a14 x![i!] i! i! i! a256 i! i! i!) N4 Q4 i!4 Q32 i!32 i! C (a255 x![L!] L!)[8] Q Q (i! i! Q Q) s', $text); + is($code, 2, "add target msg"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); + return %ret; +} + +sub add_destination { + my $buf; + my ($addr) = $kintf->recv($buf, 4096); + my ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + my (%ret, $code); + ($code, + $ret{lfam}, $ret{laddr}, $ret{lport}, + $ret{idx}, + $ret{sfam}, $ret{saddr}, $ret{sport}, + $ret{dfam}, $ret{daddr}, $ret{dport}, + $ret{midx}, + @{$ret{encr}}[0..11], + @{$ret{ssrc}}[0..3], @{$ret{seqs}}[0..3], @{$ret{pto}}[0..127], + $ret{nexf}, + $ret{exmid}, $ret{exmidlen}, $ret{exmids}, + $ret{iface}, $ret{stats}, @{$ret{ssrcst}}[0..3], + $ret{tos}, $ret{flags}) + = unpack('i! x![L!] (i! L x12 S x[S]) i! x![L!] (i! L x12 S x[S])[2] i! (i! i! a32 i! a14 x![i!] i! i! i! a256 i! i! i!) L4 L4 (i! a16 c i!)[32] i! c c a255 x![L!] Q Q Q4 c i!', $text); + is($code, 3, "add destination msg"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); + return %ret; +} + + +my $del_targets = sub { + my ($addr) = $kintf->recv($buf, 4096); + my ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + my ($code) = unpack('i!', $text); + is($code, 9, "del target msg"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); + + ($addr) = $kintf->recv($buf, 4096); + ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + ($code) = unpack('i!', $text); + is($code, 9, "del target msg"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); +}; + + +($sock_a, $sock_ax, $sock_b, $sock_bx) = new_call([qw(198.51.100.23 3000)], [qw(198.51.100.23 3001)], + [qw(198.51.100.23 3002)], [qw(198.51.100.23 3003)]); + + +$NGCP::Rtpengine::req_cb = sub { + my $buf; + my ($addr) = $kintf->recv($buf, 1024); + my ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + my ($code, $a, $l) = unpack('i! x![L!] L!L!', $text); + is($code, 16, "pin memory msg"); + is($l, 16777216, "pin memory size"); + $kintf->send(pack('ii', 3, length($text)), 0, $addr); +}; + + +($port_a, $port_ax) = offer('basic', { }, < 0 }); + +undef $NGCP::Rtpengine::req_cb; + + + + +($sock_a, $sock_ax, $sock_b, $sock_bx) = new_call([qw(198.51.100.23 3004)], [qw(198.51.100.23 3005)], + [qw(198.51.100.23 3006)], [qw(198.51.100.23 3007)]); + +($port_a, $port_ax) = offer('SRTP in', { 'transport-protocol' => 'RTP/AVP' }, < $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80}, + key => 'QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c', +}; +$srtp_ctx_b = { + cs => $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80}, + key => $srtp_key_b, +}; + +srtp_snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234567, "\x00" x 160), $srtp_ctx_a); + rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234567, "\x00" x 160)); + snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x7654321, "\x00" x 160)); + +%dict = add_target(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_b, "lport"); +is($dict{mismatch}, 0, "mismatch ignore"); +is($dict{numdest}, 2, "num dests"); +is($dict{g}[0], 0, "rtp start idx 0"); +is($dict{g}[1], 1, "rtp end idx 0"); +is($dict{g}[2], 1, "rtcp start idx 0"); +is($dict{g}[3], 2, "rtcp end idx 0"); +is($dict{decr}[0], 2, "cipher"); +is($dict{decr}[1], 2, "hmac"); +is($dict{ssrc}[0], 0x1234567, "ssrc 0"); +is($dict{ssrci}[0], -1, "ssrc index 0"); +is($dict{flags}, 344, "flags"); + +%dict = add_destination(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_b, "lport"); +is($dict{idx}, 0, "dest idx"); +is($dict{sfam}, 2, "saddr fam"); +is($dict{saddr}, 24182987, "saddr"); +is($dict{sport}, $port_a, "sport"); +is($dict{dfam}, 2, "daddr fam"); +is($dict{daddr}, 392442822, "daddr"); +is($dict{dport}, 3006, "dport"); +is($dict{encr}[0], 1, "null cipher"); +is($dict{encr}[1], 1, "null hmac"); +is($dict{flags}, 0, "flags"); + +%dict = add_destination(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_b, "lport"); +is($dict{idx}, 1, "dest idx"); +is($dict{sfam}, 2, "saddr fam"); +is($dict{saddr}, 24182987, "saddr"); +is($dict{sport}, $port_ax, "sport"); +is($dict{dfam}, 2, "daddr fam"); +is($dict{daddr}, 392442822, "daddr"); +is($dict{dport}, 3007, "dport"); +is($dict{encr}[0], 1, "null cipher"); +is($dict{encr}[1], 1, "null hmac"); +is($dict{flags}, 4, "flags"); + +%dict = add_target(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_a, "lport"); +is($dict{mismatch}, 0, "mismatch ignore"); +is($dict{numdest}, 2, "num dests"); +is($dict{g}[0], 0, "rtp start idx 0"); +is($dict{g}[1], 1, "rtp end idx 0"); +is($dict{g}[2], 1, "rtcp start idx 0"); +is($dict{g}[3], 2, "rtcp end idx 0"); +is($dict{decr}[0], 1, "null cipher"); +is($dict{decr}[1], 1, "null hmac"); +is($dict{ssrc}[0], 0x7654321, "ssrc 0"); +is($dict{ssrci}[0], -1, "ssrc index 0"); +is($dict{flags}, 344, "flags"); + +%dict = add_destination(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_a, "lport"); +is($dict{idx}, 0, "dest idx"); +is($dict{sfam}, 2, "saddr fam"); +is($dict{saddr}, 24182987, "saddr"); +is($dict{sport}, $port_b, "sport"); +is($dict{dfam}, 2, "daddr fam"); +is($dict{daddr}, 392442822, "daddr"); +is($dict{dport}, 3004, "dport"); +is($dict{encr}[0], 2, "cipher"); +is($dict{encr}[1], 2, "hmac"); +is($dict{flags}, 0, "flags"); + +%dict = add_destination(); +is($dict{lfam}, 2, "laddr fam"); +is($dict{laddr}, 24182987, "laddr"); +is($dict{lport}, $port_a, "lport"); +is($dict{idx}, 1, "dest idx"); +is($dict{sfam}, 2, "saddr fam"); +is($dict{saddr}, 24182987, "saddr"); +is($dict{sport}, $port_bx, "sport"); +is($dict{dfam}, 2, "daddr fam"); +is($dict{daddr}, 392442822, "daddr"); +is($dict{dport}, 3005, "dport"); +is($dict{encr}[0], 2, "cipher"); +is($dict{encr}[1], 2, "hmac"); +is($dict{flags}, 4, "flags"); + +srtp_rcv($sock_a, $port_b, rtpm(0, 2000, 4000, 0x7654321, "\x00" x 160), $srtp_ctx_b); + +$NGCP::Rtpengine::req_cb = $del_targets; + +rtpe_req('delete', 'basic', { 'delete-delay' => 0 }); + +undef $NGCP::Rtpengine::req_cb; + + + + +($sock_a, $sock_b, $sock_bx) = new_call([qw(198.51.100.23 3012)], + [qw(198.51.100.23 3014)], [qw(198.51.100.23 3015)]); + +($port_a, $port_ax) = offer('rtcp-mux', { 'rtcp-mux' => 'demux' }, < 0 }); + +undef $NGCP::Rtpengine::req_cb; + + + +my $cb = sub { + # close table control + # XXX check fd/address? + my ($addr) = $kintf->recv($buf, 1024); + my ($msg, $text) = unpack("i!", $buf); + is($msg, 4, "close message"); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! Z*", $buf); + is($msg, 1, "open message"); + is($text, "/proc/rtpengine/control", "open control"); + $kintf->send(pack('ii', 1, 0), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i! a*", $buf); + is($msg, 3, "write message"); + is($text, "del 42\n", "del msg"); + $kintf->send(pack('ii', 3, -Errno::ENOENT), 0, $addr); + + ($addr) = $kintf->recv($buf, 1024); + ($msg, $text) = unpack("i!", $buf); + is($msg, 4, "close message"); +}; + +NGCP::Rtpengine::AutoTest::shut_rtpe($cb); + +undef $kintf; +unlink($ENV{MOCK_PEER}); + +#done_testing;NGCP::Rtpengine::AutoTest::terminate('f00');exit; +done_testing(); diff --git a/t/tests-preload.c b/t/tests-preload.c index b1f48045d..d36ab898d 100644 --- a/t/tests-preload.c +++ b/t/tests-preload.c @@ -478,9 +478,20 @@ int close(int fd) { goto do_close; s->open = 0; - s->connected = 0; - if (s->used_domain == AF_UNIX && s->wanted_domain != AF_UNIX && s->unix_path[0]) - unlink(s->unix_path); + + if (!s->mock) { + s->connected = 0; + if (s->used_domain == AF_UNIX && s->wanted_domain != AF_UNIX && s->unix_path[0]) + unlink(s->unix_path); + goto do_close; + } + + s->mock = 0; + + int msg = MOCK_CLOSE; + ssize_t r = real_send(fd, &msg, sizeof(msg), 0); + assert(r == sizeof(msg)); + goto do_close; do_close_warn: @@ -959,11 +970,20 @@ found: int fd = real_socket(AF_UNIX, SOCK_DGRAM, 0); if (fd == -1) return -1; + + // bind as abstract socket + sa_family_t fam = AF_UNIX; + int ret = real_bind(fd, (struct sockaddr *) &fam, sizeof(fam)); + if (ret) { + close(fd); + return -1; + } + struct sockaddr_un sun = { .sun_family = AF_UNIX }; assert(strlen(mock_peer) < sizeof(sun.sun_path)); strcpy(sun.sun_path, mock_peer); - int ret = real_connect(fd, (struct sockaddr *) &sun, sizeof(sun)); + ret = real_connect(fd, (struct sockaddr *) &sun, sizeof(sun)); if (ret) { close(fd); return -1; @@ -1019,6 +1039,35 @@ ssize_t write(int fd, const void *buf, size_t len) { if (!s->open || !s->mock) goto do_write; + int msg = MOCK_WRITE; + struct iovec iov[2] = { + { + .iov_base = &msg, + .iov_len = sizeof(msg), + }, + { + .iov_base = (void *) buf, + .iov_len = len, + }, + }; + struct msghdr m = { + .msg_iov = iov, + .msg_iovlen = 2, + }; + ssize_t ret = real_sendmsg(fd, &m, 0); + if (ret <= 0) + return ret; + + struct { + int msg; + int code; + } n; + ret = real_recvfrom(fd, &n, sizeof(n), 0, NULL, NULL); + assert(ret == sizeof(n)); + assert(n.msg == MOCK_WRITE); + + return len; + do_write: return real_write(fd, buf, len); }