3 # Takes a command and arguments as arguments.
4 # Connects the command stdio to a tcp/udp/unix socket.
6 use Socket qw
/AF_UNIX AF_INET SOCK_STREAM pack_sockaddr_in inet_aton sockaddr_un/;
7 use POSIX
':sys_wait_h';
9 use Fcntl qw
/F_GETFL F_SETFL O_NONBLOCK O_RDONLY O_WRONLY/;
10 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
15 flag
($_[0], ~O_NONBLOCK
);
19 flag
($_[0], O_NONBLOCK
);
23 fcntl($_[0], F_SETFL
, fcntl($_[0], F_GETFL
, 0) | $_[1]);
27 # This handler makes select(2) interrupted, and child process reaped,
28 # and stdin excluded from watched fds.
33 if(defined $ENV{'SOCKIO_AF'})
35 $af = $ENV{'SOCKIO_AF'};
39 print STDERR
"SOCKIO_AF not given, fallback to 'tcp'\n";
42 unless($af ~~ [qw
/file abstract tcp/])
44 die "invalid SOCKIO_AF given, choose one of file, abstract, tcp\n";
47 if($af ~~ [qw
/file abstract/])
49 socket $srv, AF_UNIX
, SOCK_STREAM
, 0 or die $!;
50 setsockopt($srv, SOL_SOCKET
, SO_PASSCRED
, 1);
53 $addr = sockaddr_un
"\x00sockio-pid-$$";
57 $addr = sockaddr_un
"/tmp/sockio-pid-$$";
59 bind $srv, $addr or die $!;
63 socket $srv, AF_INET
, SOCK_STREAM
, 0 or die $!;
65 $port = int(rand() * (65_535
- 10_000
)) + 10_000
;
66 $addr = pack_sockaddr_in
($port, inet_aton
('localhost'));
67 print STDERR
"bind to tcp/$port ... ";
75 if($!{'EADDRINUSE'}) { goto BIND_TCP
; }
80 listen $srv, 1 or die $!;
86 if($af ~~ [qw
/file abstract/])
88 socket $cln, AF_UNIX
, SOCK_STREAM
, 0 or die $!;
92 socket $cln, AF_INET
, SOCK_STREAM
, 0 or die $!;
95 if(not connect $cln, $addr)
97 if($!{'ECONNREFUSED'}) { sleep 0.1; goto CONNECT
; }
100 open STDIN
, '<&=', fileno $cln or die $!;
101 open STDOUT
, '>&=', fileno $cln or die $!;
102 flag
(STDIN
, O_RDONLY
);
103 flag
(STDOUT
, O_WRONLY
);
104 exec {$ARGV[0]} @ARGV;
105 my ($errno, $errstr) = (int $!, $!);
106 warn "$0: ${ARGV[0]}: $errstr\n";
117 @watch_in = (\
*STDIN
, $clnt);
121 $SIG{'CHLD'} = \
&sigchld
;
127 if(scalar @watch_in == 0)
133 for my $fd (@watch_in)
135 vec($fds_in, fileno($fd), 1) = 1;
138 select($fds_in, undef, undef, undef);
140 if(vec($fds_in, fileno(STDIN
), 1) == 1)
143 $stdin_bytes = sysread STDIN
, $buf, 4096;
150 if($stdin_bytes eq 0)
154 @watch_in = grep {$_ ne \
*STDIN
} @watch_in;
157 if(vec($fds_in, fileno($clnt), 1) == 1)
160 $clnt_bytes = sysread $clnt, $buf, 4096;
171 @watch_in = grep {$_ ne $clnt} @watch_in;
175 if(not defined $exitcode and waitpid $pid, WNOHANG
)
181 @watch_in = grep {$_ ne \
*STDIN
} @watch_in;
186 if(not defined $exitcode)