no warnings 'once';
# any number of FDs per-sendmsg(2) + buffer
-*send_cmd4 = sub ($$$$;$) { # (sock, fds, buf, flags) = @_;
- my ($sock, $fds, undef, $flags, $tries) = @_;
+*send_cmd4 = sub ($$$$;$) { # (sock, io, buf, flags) = @_;
+ my ($sock, $io, undef, $flags, $tries) = @_;
$tries //= -1; # infinite
my $mh = Socket::MsgHdr->new(buf => $_[2]);
- $mh->cmsghdr(SOL_SOCKET, SCM_RIGHTS, pack('i' x scalar(@$fds), @$fds));
+ $mh->cmsghdr(SOL_SOCKET, SCM_RIGHTS,
+ pack('i' x scalar(@{$io //= []}), map { fileno $_ } @$io));
my $s;
do {
$s = Socket::MsgHdr::sendmsg($sock, $mh, $flags);
}
sub stream_in_full ($$$) {
- my ($s1, $fds, $buf) = @_;
+ my ($s1, $io, $buf) = @_;
socketpair(my $r, my $w, AF_UNIX, SOCK_STREAM, 0);
- my $n = $send_cmd->($s1, [ fileno($r) ],
+ my $n = $send_cmd->($s1, [ $r ],
ipc_freeze(['do_sock_stream', length($buf)]),
MSG_EOR) // croak "sendmsg: $!";
undef $r;
- $n = $send_cmd->($w, $fds, $buf, 0) // croak "sendmsg: $!";
+ $n = $send_cmd->($w, $io, $buf, 0) // croak "sendmsg: $!";
print $w substr($buf, $n) if $n < length($buf); # need > 2G on Linux
close $w; # autodies
}
sub wq_io_do { # always async
- my ($self, $sub, $ios, @args) = @_;
+ my ($self, $sub, $io, @args) = @_;
my $s1 = $self->{-wq_s1} or Carp::confess('no -wq_s1');
- my $fds = [ map { fileno($_) } @$ios ];
my $buf = ipc_freeze([$sub, @args]);
if (length($buf) > $MY_MAX_ARG_LEN) {
- stream_in_full($s1, $fds, $buf);
+ stream_in_full($s1, $io, $buf);
} else {
- my $n = $send_cmd->($s1, $fds, $buf, MSG_EOR);
+ my $n = $send_cmd->($s1, $io, $buf, MSG_EOR);
return if defined($n); # likely
$!{ETOOMANYREFS} and croak "sendmsg: $! (check RLIMIT_NOFILE)";
- $!{EMSGSIZE} ? stream_in_full($s1, $fds, $buf) :
+ $!{EMSGSIZE} ? stream_in_full($s1, $io, $buf) :
croak("sendmsg: $!");
}
}
my ($self, $io, $cmd, $env) = @_;
$PublicInbox::IPC::send_cmd->(
$self->{sock} // die('lei client gone'),
- [ map { fileno($_) } @$io ],
- exec_buf($cmd, $env), MSG_EOR) //
+ $io, exec_buf($cmd, $env), MSG_EOR) //
Carp::croak("sendmsg: $!");
}
char pad[sizeof(struct cmsghdr) + 16 + SEND_FD_SPACE];
};
-SV *send_cmd4_(PerlIO *s, SV *svfds, SV *data, int flags, long tries)
+SV *send_cmd4_(PerlIO *s, SV *sio, SV *data, int flags, long tries)
{
struct msghdr msg = { 0 };
union my_cmsg cmsg = { 0 };
STRLEN dlen = 0;
struct iovec iov;
ssize_t sent;
- AV *fds = (AV *)SvRV(svfds);
- I32 i, nfds = av_len(fds) + 1;
+ AV *io = (AV *)SvRV(sio);
+ I32 i, nfds = io ? (av_len(io) + 1) : 0;
int *fdp;
if (SvOK(data)) {
cmsg.hdr.cmsg_len = CMSG_LEN(nfds * sizeof(int));
fdp = (int *)CMSG_DATA(&cmsg.hdr);
for (i = 0; i < nfds; i++) {
- SV **fd = av_fetch(fds, i, 0);
- *fdp++ = SvIV(*fd);
+ SV **svio = av_fetch(io, i, 0);
+ *fdp++ = PerlIO_fileno(IoIFP(sv_2io(*svio)));
}
}
do {
require PublicInbox::CmdIPC4;
*send_cmd4 = sub ($$$$;$) {
- my ($sock, $fds, undef, $flags, $tries) = @_;
+ my ($sock, $io, undef, $flags, $tries) = @_;
my $iov = pack('P'.TMPL_size_t,
$_[2] // NUL, length($_[2] // NUL) || 1);
- my $fd_space = scalar(@$fds) * SIZEOF_int;
+ my $fd_space = scalar(@{$io //= []}) * SIZEOF_int;
my $msg_controllen = CMSG_SPACE($fd_space);
my $cmsghdr = pack(TMPL_cmsg_len .
'LL' . # cmsg_level, cmsg_type,
- CMSG_DATA_off.('i' x scalar(@$fds)). # CMSG_DATA
+ CMSG_DATA_off.('i' x scalar(@$io)). # CMSG_DATA
'@'.($msg_controllen - 1).'x1', # pad to space, not len
CMSG_LEN($fd_space), # cmsg_len
SOL_SOCKET, SCM_RIGHTS, # cmsg_{level,type}
- @$fds); # CMSG_DATA
+ map { fileno $_ } @$io); # CMSG_DATA
my $mh = pack(TMPL_msghdr,
undef, 0, # msg_name, msg_namelen (unused)
$iov, 1, # msg_iov, msg_iovlen
our $tries = -1; # set to zero by read-only daemon
sub mkreq {
- my ($self, $ios, @arg) = @_;
- my @fds = map fileno($_), @$ios;
+ my ($self, $io, @arg) = @_;
my $buf = join("\0", @arg, '');
my $n = $PublicInbox::IPC::send_cmd->($self->{io},
- \@fds, $buf, MSG_EOR, $tries)
+ $io, $buf, MSG_EOR, $tries)
// die "send_cmd: $!";
$n == length($buf) or die "send_cmd: $n != ".length($buf);
}
my $buf = join("\0", scalar(@ARGV), @ARGV);
while (my ($k, $v) = each %ENV) { $buf .= "\0$k=$v" }
$buf .= "\0\0";
-$send_cmd->($sock, [0, 1, 2, fileno($dh)], $buf, MSG_EOR) or die "sendmsg: $!";
+$send_cmd->($sock, [\*STDIN, \*STDOUT, \*STDERR, $dh], $buf, MSG_EOR) or
+ die "sendmsg: $!";
$SIG{TSTP} = sub { send($sock, 'STOP', MSG_EOR); kill 'STOP', $$ };
$SIG{CONT} = sub { send($sock, 'CONT', MSG_EOR) };
my ($s1, $s2);
my $src = 'some payload' x 40;
socketpair($s1, $s2, AF_UNIX, $type, 0);
- my $sfds = [ fileno($r), fileno($w), fileno($s1) ];
- $send->($s1, $sfds, $src, $flag);
+ my $io = [ $r, $w, $s1 ];
+ $send->($s1, $io, $src, $flag);
my (@fds) = $recv->($s2, my $buf, length($src) + 1);
is($buf, $src, 'got buffer payload '.$desc);
my ($r1, $w1, $s1a);
if ($type == SOCK_SEQPACKET) {
$r1 = $w1 = $s1a = undef;
$src = (',' x 1023) . '-' .('.' x 1024);
- $send->($s1, $sfds, $src, $flag);
+ $send->($s1, $io, $src, $flag);
(@fds) = $recv->($s2, $buf, 1024);
is($buf, (',' x 1023) . '-', 'silently truncated buf');
$s1->blocking(0);
my $nsent = 0;
my $srclen = length($src);
- while (defined(my $n = $send->($s1, $sfds, $src, $flag))) {
+ while (defined(my $n = $send->($s1, $io, $src, $flag))) {
$nsent += $n;
fail "sent $n bytes of $srclen" if $n > $srclen;
}
ok($nsent > 0, 'sent some bytes');
socketpair($s1, $s2, AF_UNIX, $type, 0);
- is($send->($s1, [], $src, $flag), length($src), 'sent w/o FDs');
+ is($send->($s1, [], $src, $flag), length($src), 'sent w/o IOs');
$buf = 'nope';
@fds = $recv->($s2, $buf, length($src));
is(scalar(@fds), 0, 'no FDs received');
is($buf, $src, 'recv w/o FDs');
}
+ socketpair($s1, $s2, AF_UNIX, $type, 0);
+ is($send->($s1, undef, $src, $flag), length($src), 'sent w/ undef IO');
+ @fds = $recv->($s2, $buf = 'hi', length($src));
+ is scalar(@fds), 0, 'no FDs received';
+ is $buf, $src, 'recv w/o FDs sent buffer';
} };
my $send_ic = PublicInbox::Spawn->can('send_cmd4');
my @before = sort(glob("$d/*"));
my $addr = pack_sockaddr_un($sock);
open my $null, '<', '/dev/null' or BAIL_OUT "/dev/null: $!";
- my @fds = map { fileno($null) } (0..2);
for (0..10) {
socket(my $c, AF_UNIX, SOCK_SEQPACKET, 0) or
BAIL_OUT "socket: $!";
connect($c, $addr) or BAIL_OUT "connect: $!";
- $send_cmd->($c, \@fds, 'hi', MSG_EOR);
+ $send_cmd->($c, [ $null, $null, $null ], 'hi', MSG_EOR);
}
lei_ok('daemon-pid');
chomp($pid = $lei_out);
my $err = ref($arg[-1]) ? pop(@arg) : \*STDERR;
pipe(my $x, my $y);
my $buf = join("\0", @arg, '');
- my @fds = (fileno($y), fileno($err));
- my $n = $PublicInbox::IPC::send_cmd->($s, \@fds, $buf, MSG_EOR) //
+ my @io = ($y, $err);
+ my $n = $PublicInbox::IPC::send_cmd->($s, \@io, $buf, MSG_EOR) //
xbail "send: $!";
my $exp = length($buf);
$exp == $n or xbail "req @arg sent short ($n != $exp)";