+sub tls_start_cb ($$) {
+ my ($opt, $orig_post_accept) = @_;
+ sub {
+ my ($io, $addr, $srv) = @_;
+ my $ssl = IO::Socket::SSL->start_SSL($io, %$opt);
+ $orig_post_accept->($ssl, $addr, $srv);
+ }
+}
+
+sub defer_accept ($$) {
+ my ($s, $af_name) = @_;
+ return unless defined $af_name;
+ if ($^O eq 'linux') {
+ my $TCP_DEFER_ACCEPT = 9; # Socket::TCP_DEFER_ACCEPT is in 5.14+
+ my $x = getsockopt($s, IPPROTO_TCP, $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, $TCP_DEFER_ACCEPT, 1);
+ } elsif ($^O eq 'freebsd') {
+ my $x = getsockopt($s, SOL_SOCKET, $SO_ACCEPTFILTER);
+ return if defined $x; # don't change if set
+ my $accf_arg = pack('a16a240', $af_name, '');
+ setsockopt($s, SOL_SOCKET, $SO_ACCEPTFILTER, $accf_arg);
+ }
+}
+
+sub daemon_loop ($) {
+ my ($xnetd) = @_;
+ my $refresh = sub {
+ my ($sig) = @_;
+ for my $xn (values %$xnetd) {
+ eval { $xn->{refresh}->($sig) };
+ warn "refresh $@\n" if $@;
+ }
+ };
+ my %post_accept;
+ while (my ($k, $v) = each %tls_opt) {
+ my $l = $k;
+ $l =~ s!\A([^:]+)://!!;
+ my $scheme = $1 // '';
+ my $xn = $xnetd->{$l} // $xnetd->{''};
+ if ($scheme =~ m!\A(?:https|imaps|nntps)!) {
+ $post_accept{$l} = tls_start_cb($v, $xn->{post_accept});
+ } elsif ($xn->{tlsd}) { # STARTTLS, $k eq '' is OK
+ $xn->{tlsd}->{accept_tls} = $v;
+ }
+ }
+ my $sig = {
+ HUP => $refresh,
+ INT => \&worker_quit,
+ QUIT => \&worker_quit,
+ TERM => \&worker_quit,
+ TTIN => 'IGNORE',
+ TTOU => 'IGNORE',
+ USR1 => \&reopen_logs,
+ USR2 => 'IGNORE',
+ WINCH => 'IGNORE',
+ CHLD => \&PublicInbox::DS::enqueue_reap,
+ };