From: Eric Wong Date: Tue, 8 Apr 2025 20:49:58 +0000 (+0000) Subject: daemon: support backlog= listen parameter X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5318e2fe0438521dca6ff45ba8c151114fc08679;p=thirdparty%2Fpublic-inbox.git daemon: support backlog= listen parameter For -netd instances using multiple listeners, it's easiest for me to configure all ListenStream directives in a single systemd.socket(5) unit. Unfortunately, this seems to force all listeners to use the same Backlog= value, and juggling multiple systemd.socket(5) units for a single systemd service seems tedious. So support setting the backlog= parameter on the public-inbox-*d command-line on a per-listener basis; allowing us to override the backlog value of inherited listeners and also to set the backlog for listeners we bind ourselves. This makes it possible for non-systemd users to easily configure per-listener backlogs, as well. --- diff --git a/Documentation/public-inbox-daemon.pod b/Documentation/public-inbox-daemon.pod index 7496cfca4..a6d93e66d 100644 --- a/Documentation/public-inbox-daemon.pod +++ b/Documentation/public-inbox-daemon.pod @@ -50,7 +50,7 @@ all if relying on L or similar, Per-listener options may be specified after C as C pairs delimited by C<,>. See L for -documentation on the C, C, C, +documentation on the C, C, C, C, C, C, C, C, and C options available. diff --git a/Documentation/public-inbox-netd.pod b/Documentation/public-inbox-netd.pod index bbf0eb448..d29514a2f 100644 --- a/Documentation/public-inbox-netd.pod +++ b/Documentation/public-inbox-netd.pod @@ -58,6 +58,12 @@ is printed in the the greeting and used for generating C headers, overriding the L directive. +C may be set to an integer on a per-listener basis to set the +L backlog parameter in public-inbox 2.0+ on both inherited and bound +sockets. This parameter is a convenient way to specify per-listener backlogs +if multiple listen sockets are defined by a single L unit +but different backlog values are desired. + =item --cert /path/to/cert See L. diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index dbac51463..b8a51f30f 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -68,6 +68,11 @@ sub listener_opt ($) { # p5-io-socket-ssl/example/ssl_server.pl has this fallback: $o->{cert} //= [ $default_cert ] if defined($default_cert); $o->{key} //= defined($default_key) ? [ $default_key ] : $o->{cert}; + if ($o->{backlog}) { + grep /[^0-9]/, @{$o->{backlog}} and + die "E: non-digit backlog in $str\n"; + $o->{backlog} = $o->{backlog}->[-1]; + } $o; } @@ -246,7 +251,11 @@ EOF } elsif (defined($TLS_ONLY{$scheme})) { die "$orig specified w/o cert=\n"; } - if ($listener_names->{$l}) { # already inherited + if (my $s = $listener_names->{$l}) { # already inherited + if (defined(my $bl = $opt->{backlog})) { + listen($s, $bl) or + warn "W: listen($l, backlog=$bl): $!\n"; + } $XNETD{$l} = load_mod($scheme, $opt, $l); next; } @@ -274,7 +283,7 @@ EOF die $@ if $@; %o = (LocalAddr => $l, ReuseAddr => 1, Proto => 'tcp'); } - $o{Listen} = 2**31 - 1; # kernel will clamp + $o{Listen} = $opt->{backlog} // 2**31 - 1; # kernel will clamp my $prev = umask 0000; my $s = eval { $sock_pkg->new(%o) } or warn "error binding $l: $! ($@)\n"; diff --git a/t/netd.t b/t/netd.t index abdde1241..71f6f69e0 100644 --- a/t/netd.t +++ b/t/netd.t @@ -2,7 +2,7 @@ # Copyright (C) all contributors # License: AGPL-3.0+ use v5.12; -use Socket qw(IPPROTO_TCP SOL_SOCKET); +use Socket qw(IPPROTO_TCP SOL_SOCKET SOCK_STREAM); use PublicInbox::TestCommon; # IO::Poll and Net::NNTP are part of the standard library, but # distros may split them off... @@ -35,7 +35,8 @@ for (1..3) { pipe(my ($r, $w)) or xbail "pipe: $!"; push @pad_pipes, $r, $w; }; -my %srv = map { $_ => tcp_server() } qw(imap nntp imaps nntps); +my @srv = map { $_ => tcp_server() } qw(imap nntp imaps nntps); +my %srv = @srv; my $ibx = create_inbox 'netd', version => 2, -primary_address => $addr, indexlevel => 'basic', sub { my ($im, $ibx) = @_; @@ -55,15 +56,16 @@ $pi_config //= "$ibx->{inboxdir}/pi_config"; my @args = ("--cert=$cert", "--key=$key"); my $rdr = {}; my $fd = 3; -while (my ($k, $v) = each %srv) { +do { + my ($k, $v) = splice @srv, 0, 2; push @args, "-l$k://".tcp_host_port($v); + $args[-1] .= '?servername=override.example' if $k eq 'nntp'; $rdr->{$fd++} = $v; -} +} while (@srv); my $cmd = [ '-netd', '-W0', @args, "--stdout=$out", "--stderr=$err" ]; my $env = { PI_CONFIG => $pi_config }; my $td = start_script($cmd, $env, $rdr); @pad_pipes = (); -undef $rdr; my %o = ( SSL_hostname => 'server.local', SSL_verifycn_name => 'server.local', @@ -78,7 +80,53 @@ my %o = ( { my $c = tcp_connect($srv{nntp}); my $msg = <$c>; - like($msg, qr/^201 .*? ready - post via email/, 'connected to NNTP'); + like $msg, qr/^201 override\.example ready - post via email/, + 'connected to NNTP'; +} + +SKIP: { + skip "no ss(8), not Linux: $^O", 1 if $^O ne 'linux'; + my $ss = require_cmd 'ss', 1 or skip 'ss(8) command not found', 1; + $td->kill; + my $nr = 10; + my @exp; # (scheme, addr_port, expected backlog) + for (@$cmd) { + if (m!\A-l([a-z]+)://([^/\?]+)!) { + push @exp, $1, $2, $nr; + $_ .= /\?/ ? ',' : '?'; + $_ .= "backlog=$nr"; + $nr++; + } + } + my $usock = "$tmpdir/u.sock"; + push @$cmd, "-lnntp://$usock?backlog=$nr,servername=bogus.example"; + $td->join; + $td = start_script($cmd, $env, $rdr); + my $c = tcp_connect($srv{nntp}); + my $msg = <$c>; + like $msg, qr/^201 override\.example ready - post via email/, + 'NNTP ready after restart'; + + require IO::Socket::UNIX; + $c = IO::Socket::UNIX->new(Peer => $usock, Type => Socket::SOCK_STREAM); + $msg = <$c>; + like $msg, qr/^201 bogus\.example ready - post via email/, + 'UNIX socket bound'; + my @ss_after = xqx([$ss, '-nl']); + my @ss_u = grep /^u_str\s+LISTEN\s+\d+\s+\d+\s+\Q$usock\E\s+/, @ss_after; + xbail("multiple (or zero) `$usock' matches", \@ss_u) if @ss_u != 1; + @ss_u = split /\s+/, $ss_u[0]; + is $ss_u[3], $nr, 'newly bound listener has expected backlog in Send-Q' or + diag explain(\@ss_after); + do { + my ($scheme, $addr_port, $exp_backlog) = splice @exp, 0, 3; + my @l = grep /^tcp\s+LISTEN\s+\d+\s+\d+\s+\Q$addr_port\E\s+/, @ss_after; + xbail("multiple (or zero) `$addr_port' matches", \@l) if @l != 1; + @l = split /\s+/, $l[0]; + is $l[3], $exp_backlog, + "inherited $scheme listener has expected backlog in Send-Q" or + diag explain(\@ss_after); + } while (@exp); } # TODO: more tests