]> Sergey Matveev's repositories - public-inbox.git/blob - t/cmd_ipc.t
ipc: start supporting sending/receiving more than 3 FDs
[public-inbox.git] / t / cmd_ipc.t
1 #!perl -w
2 # Copyright (C) 2021 all contributors <meta@public-inbox.org>
3 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
4 use strict;
5 use v5.10.1;
6 use Test::More;
7 use PublicInbox::TestCommon;
8 use Socket qw(AF_UNIX SOCK_STREAM MSG_EOR);
9 pipe(my ($r, $w)) or BAIL_OUT;
10 my ($send, $recv);
11 require_ok 'PublicInbox::Spawn';
12 my $SOCK_SEQPACKET = eval { Socket::SOCK_SEQPACKET() } // undef;
13
14 my $do_test = sub { SKIP: {
15         my ($type, $flag, $desc) = @_;
16         defined $type or skip 'SOCK_SEQPACKET missing', 7;
17         my ($s1, $s2);
18         my $src = 'some payload' x 40;
19         socketpair($s1, $s2, AF_UNIX, $type, 0) or BAIL_OUT $!;
20         my $sfds = [ fileno($r), fileno($w), fileno($s1) ];
21         $send->($s1, $sfds, $src, $flag);
22         my (@fds) = $recv->($s2, my $buf, length($src) + 1);
23         is($buf, $src, 'got buffer payload '.$desc);
24         my ($r1, $w1, $s1a);
25         my $opens = sub {
26                 ok(open($r1, '<&=', $fds[0]), 'opened received $r');
27                 ok(open($w1, '>&=', $fds[1]), 'opened received $w');
28                 ok(open($s1a, '+>&=', $fds[2]), 'opened received $s1');
29         };
30         $opens->();
31         my @exp = stat $r;
32         my @cur = stat $r1;
33         is("$exp[0]\0$exp[1]", "$cur[0]\0$cur[1]", '$r dev/ino matches');
34         @exp = stat $w;
35         @cur = stat $w1;
36         is("$exp[0]\0$exp[1]", "$cur[0]\0$cur[1]", '$w dev/ino matches');
37         @exp = stat $s1;
38         @cur = stat $s1a;
39         is("$exp[0]\0$exp[1]", "$cur[0]\0$cur[1]", '$s1 dev/ino matches');
40         if (defined($SOCK_SEQPACKET) && $type == $SOCK_SEQPACKET) {
41                 $r1 = $w1 = $s1a = undef;
42                 $src = (',' x 1023) . '-' .('.' x 1024);
43                 $send->($s1, $sfds, $src, $flag);
44                 (@fds) = $recv->($s2, $buf, 1024);
45                 is($buf, (',' x 1023) . '-', 'silently truncated buf');
46                 $opens->();
47                 $r1 = $w1 = $s1a = undef;
48                 close $s1;
49                 @fds = $recv->($s2, $buf, length($src) + 1);
50                 is_deeply(\@fds, [], "no FDs on EOF $desc");
51                 is($buf, '', "buffer cleared on EOF ($desc)");
52
53         }
54 } };
55
56 my $send_ic = PublicInbox::Spawn->can('send_cmd4');
57 my $recv_ic = PublicInbox::Spawn->can('recv_cmd4');
58 SKIP: {
59         ($send_ic && $recv_ic) or skip 'Inline::C not installed/enabled', 12;
60         $send = $send_ic;
61         $recv = $recv_ic;
62         $do_test->(SOCK_STREAM, 0, 'Inline::C stream');
63         $do_test->($SOCK_SEQPACKET, MSG_EOR, 'Inline::C seqpacket');
64 }
65
66 SKIP: {
67         require_mods('Socket::MsgHdr', 13);
68         require_ok 'PublicInbox::CmdIPC4';
69         $send = PublicInbox::CmdIPC4->can('send_cmd4');
70         $recv = PublicInbox::CmdIPC4->can('recv_cmd4');
71         $do_test->(SOCK_STREAM, 0, 'MsgHdr stream');
72         $do_test->($SOCK_SEQPACKET, MSG_EOR, 'MsgHdr seqpacket');
73         SKIP: {
74                 ($send_ic && $recv_ic) or
75                         skip 'Inline::C not installed/enabled', 12;
76                 $recv = $recv_ic;
77                 $do_test->(SOCK_STREAM, 0, 'Inline::C -> MsgHdr stream');
78                 $do_test->($SOCK_SEQPACKET, 0, 'Inline::C -> MsgHdr seqpacket');
79         }
80 }
81
82 SKIP: {
83         require_mods('IO::FDPass', 13);
84         require_ok 'PublicInbox::CmdIPC1';
85         $send = PublicInbox::CmdIPC1->can('send_cmd1');
86         $recv = PublicInbox::CmdIPC1->can('recv_cmd1');
87         $do_test->(SOCK_STREAM, 0, 'IO::FDPass stream');
88         $do_test->($SOCK_SEQPACKET, MSG_EOR, 'IO::FDPass seqpacket');
89 }
90
91 done_testing;