use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
use IO::Handle;
use IO::Socket;
+use Socket qw(IPPROTO_TCP);
use Cwd qw/abs_path/;
STDOUT->autoflush(1);
STDERR->autoflush(1);
}
}
+sub defer_accept ($) {
+ if ($^O eq 'linux') {
+ my ($s) = @_;
+ my $x = getsockopt($s, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT());
+ return unless defined $x; # may be Unix socket
+ my $sec = unpack('i', $x);
+ return if $sec > 0; # systemd users may set a higher value
+ setsockopt($s, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT(), 1);
+ }
+ # TODO FreeBSD accf_http / accf_data
+}
+
sub daemon_loop ($$$) {
my ($refresh, $post_accept, $nntpd) = @_;
PublicInbox::EvCleanup::enable(); # early for $refresh
$SIG{HUP} = $refresh;
$SIG{CHLD} = 'DEFAULT';
$SIG{$_} = 'IGNORE' for qw(USR2 TTIN TTOU WINCH);
- # this calls epoll_create:
- @listeners = map {
- PublicInbox::Listener->new($_,
- $post_accept{sockname($_)} || $post_accept)
+ @listeners = map {;
+ my $tls_cb = $post_accept{sockname($_)};
+
+ # NNTPS, HTTPS, HTTP, and POP3S are client-first traffic
+ # NNTP and POP3 are server-first
+ defer_accept($_) if $tls_cb || !$nntpd;
+
+ # this calls epoll_create:
+ PublicInbox::Listener->new($_, $tls_cb || $post_accept)
} @listeners;
PublicInbox::DS->EventLoop;
$parent_pipe = undef;
Listen => 1024,
);
my $sock = IO::Socket::INET->new(%opts);
+my $defer_accept_val;
+if ($^O eq 'linux') {
+ setsockopt($sock, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT(), 5) or die;
+ my $x = getsockopt($sock, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT());
+ defined $x or die "getsockopt: $!";
+ $defer_accept_val = unpack('i', $x);
+ if ($defer_accept_val <= 0) {
+ die "unexpected TCP_DEFER_ACCEPT value: $defer_accept_val";
+ }
+}
+
my $upath = "$tmpdir/s";
my $unix = IO::Socket::UNIX->new(
Listen => 1024,
is($body, sha1_hex(''), 'read expected body #2');
}
+SKIP: {
+ skip 'TCP_DEFER_ACCEPT is Linux-only', 1 if $^O ne 'linux';
+ my $var = Socket::TCP_DEFER_ACCEPT();
+ defined(my $x = getsockopt($sock, IPPROTO_TCP, $var)) or die;
+ is(unpack('i', $x), $defer_accept_val,
+ 'TCP_DEFER_ACCEPT unchanged if previously set');
+};
+
done_testing();
sub capture {
}
use File::Temp qw/tempdir/;
use IO::Socket::INET;
+use Socket qw(IPPROTO_TCP);
require './t/common.perl';
# FIXME: too much setup
'fsck on cloned directory successful');
}
+SKIP: {
+ skip 'TCP_DEFER_ACCEPT is Linux-only', 1 if $^O ne 'linux';
+ my $var = Socket::TCP_DEFER_ACCEPT();
+ defined(my $x = getsockopt($sock, IPPROTO_TCP, $var)) or die;
+ ok(unpack('i', $x) > 0, 'TCP_DEFER_ACCEPT set');
+};
+
done_testing();
1;
use warnings;
use Test::More;
use File::Temp qw(tempdir);
-use Socket qw(SOCK_STREAM);
+use Socket qw(SOCK_STREAM IPPROTO_TCP);
# IO::Poll and Net::NNTP are part of the standard library, but
# distros may split them off...
foreach my $mod (qw(DBD::SQLite IO::Socket::SSL Net::NNTP IO::Poll)) {
is(sysread($slow, my $eof, 4096), 0, 'got EOF');
$slow = undef;
+ SKIP: {
+ skip 'TCP_DEFER_ACCEPT is Linux-only', 2 if $^O ne 'linux';
+ my $var = Socket::TCP_DEFER_ACCEPT();
+ defined(my $x = getsockopt($nntps, IPPROTO_TCP, $var)) or die;
+ ok(unpack('i', $x) > 0, 'TCP_DEFER_ACCEPT set on NNTPS');
+ defined($x = getsockopt($starttls, IPPROTO_TCP, $var)) or die;
+ is(unpack('i', $x), 0, 'TCP_DEFER_ACCEPT is 0 on plain NNTP');
+ };
+
$c = undef;
kill('TERM', $pid);
is($pid, waitpid($pid, 0), 'nntpd exited successfully');