}
SET_NODATACOW
+# last choice for script/lei, 1st choice for lei internals
+# compatible with PublicInbox::CmdIPC4
my $fdpass = <<'FDPASS';
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#if defined(CMSG_SPACE) && defined(CMSG_LEN)
+#define SEND_FD_CAPA 3
+#define SEND_FD_SPACE (SEND_FD_CAPA * sizeof(int))
union my_cmsg {
struct cmsghdr hdr;
- char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
+ char pad[sizeof(struct cmsghdr) + 16 + SEND_FD_SPACE];
};
-int send_fd(int sockfd, int fd)
+int send_cmd4(PerlIO *s, SV *svfds, SV *data, int flags)
{
struct msghdr msg = { 0 };
- struct iovec iov;
union my_cmsg cmsg = { 0 };
+ STRLEN dlen = 0;
+ struct iovec iov;
+ AV *fds = (AV *)SvRV(svfds);
+ I32 i, nfds = av_len(fds) + 1;
+ int *fdp;
- iov.iov_base = &msg.msg_namelen;
- iov.iov_len = 1;
+ if (SvOK(data)) {
+ iov.iov_base = SvPV(data, dlen);
+ iov.iov_len = dlen;
+ }
+ if (!dlen) { /* must be non-zero */
+ iov.iov_base = &msg.msg_namelen; /* whatever */
+ iov.iov_len = 1;
+ }
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
- msg.msg_control = &cmsg.hdr;
- msg.msg_controllen = CMSG_SPACE(sizeof(int));
-
- cmsg.hdr.cmsg_level = SOL_SOCKET;
- cmsg.hdr.cmsg_type = SCM_RIGHTS;
- cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
- *(int *)CMSG_DATA(&cmsg.hdr) = fd;
-
- return sendmsg(sockfd, &msg, 0) >= 0;
+ if (nfds) {
+ if (nfds > SEND_FD_CAPA) {
+ fprintf(stderr, "FIXME: bump SEND_FD_CAPA=%d\n", nfds);
+ nfds = SEND_FD_CAPA;
+ }
+ msg.msg_control = &cmsg.hdr;
+ msg.msg_controllen = CMSG_SPACE(nfds * sizeof(int));
+ cmsg.hdr.cmsg_level = SOL_SOCKET;
+ cmsg.hdr.cmsg_type = SCM_RIGHTS;
+ 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);
+ }
+ }
+ return sendmsg(PerlIO_fileno(s), &msg, flags) >= 0;
}
-int recv_fd(int sockfd)
+void recv_cmd4(PerlIO *s, SV *buf, STRLEN n)
{
union my_cmsg cmsg = { 0 };
struct msghdr msg = { 0 };
struct iovec iov;
- int fd = -1;
-
- iov.iov_base = &msg.msg_namelen;
- iov.iov_len = 1;
+ size_t i;
+ Inline_Stack_Vars;
+ Inline_Stack_Reset;
+
+ if (!SvOK(buf))
+ sv_setpvn(buf, "", 0);
+ iov.iov_base = SvGROW(buf, n + 1);
+ iov.iov_len = n;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsg.hdr;
- msg.msg_controllen = CMSG_SPACE(sizeof(int));
-
- if (recvmsg(sockfd, &msg, 0) <= 0)
- return -1;
-
- errno = EDOM;
- if (cmsg.hdr.cmsg_level == SOL_SOCKET &&
- cmsg.hdr.cmsg_type == SCM_RIGHTS &&
- cmsg.hdr.cmsg_len == CMSG_LEN(sizeof(int)))
- fd = *(int *)CMSG_DATA(&cmsg.hdr);
-
- return fd;
+ msg.msg_controllen = CMSG_SPACE(SEND_FD_SPACE);
+
+ i = recvmsg(PerlIO_fileno(s), &msg, 0);
+ if (i < 0)
+ croak("recvmsg: %s", strerror(errno));
+ SvCUR_set(buf, i);
+ if (i > 0 && cmsg.hdr.cmsg_level == SOL_SOCKET &&
+ cmsg.hdr.cmsg_type == SCM_RIGHTS) {
+ size_t len = cmsg.hdr.cmsg_len;
+ int *fdp = (int *)CMSG_DATA(&cmsg.hdr);
+ for (i = 0; CMSG_LEN((i + 1) * sizeof(int)) <= len; i++)
+ Inline_Stack_Push(sv_2mortal(newSViv(*fdp++)));
+ }
+ Inline_Stack_Done;
}
#endif /* defined(CMSG_SPACE) && defined(CMSG_LEN) */
FDPASS
my $f = "$inline_dir/.public-inbox.lock";
open my $fh, '>', $f or die "failed to open $f: $!\n";
flock($fh, LOCK_EX) or die "LOCK_EX failed on $f: $!\n";
- eval 'use Inline C => $vfork_spawn . $fdpass . $set_nodatacow';
+ eval 'use Inline C => $vfork_spawn.$fdpass.$set_nodatacow';
+ # . ', BUILD_NOISY => 1';
my $err = $@;
my $ndc_err;
if ($err && $set_nodatacow) { # missing Linux kernel headers
*nodatacow_fd = \&PublicInbox::NDC_PP::nodatacow_fd;
*nodatacow_dir = \&PublicInbox::NDC_PP::nodatacow_dir;
}
-unless (__PACKAGE__->can('recv_fd')) {
- eval { # try the XS IO::FDPass package
- require IO::FDPass;
- no warnings 'once';
- *recv_fd = \&IO::FDPass::recv;
- *send_fd = \&IO::FDPass::send;
- };
-}
undef $set_nodatacow;
undef $vfork_spawn;