X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FDaemon.pm;h=13cce1ec51abcf3499363e388b359db6bd7f4a1a;hb=93a7b219d58aad86438cbf3cbf4318a889831ac1;hp=70d0f1c5de1af336fae7d1c4e824ed6c9f66996d;hpb=c2d48f35b007657db7371eef1c868341afb30494;p=public-inbox.git diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index 70d0f1c5..13cce1ec 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -1,4 +1,4 @@ -# Copyright (C) 2015-2021 all contributors +# Copyright (C) all contributors # License: AGPL-3.0+ # # Contains common daemon code for the httpd, imapd, and nntpd servers @@ -20,6 +20,7 @@ use PublicInbox::EOFpipe; use PublicInbox::Sigfd; use PublicInbox::Git; use PublicInbox::GitAsyncCat; +use PublicInbox::Eml; our $SO_ACCEPTFILTER = 0x1000; my @CMD; my ($set_user, $oldset); @@ -74,18 +75,34 @@ sub accept_tls_opt ($) { { SSL_server => 1, SSL_startHandshake => 0, SSL_reuse_ctx => $ctx }; } -sub daemon_prepare ($) { - my ($default_listen) = @_; +sub load_mod ($) { + my ($scheme) = @_; + my $modc = "PublicInbox::\U$1"; + my $mod = $modc.'D'; + eval "require $mod"; # IMAPD|HTTPD|NNTPD|POP3D + die $@ if $@; + my %xn = map { $_ => $mod->can($_) } qw(refresh post_accept); + $xn{tlsd} = $mod->new if $mod->can('refresh_groups'); #!HTTPD + my $tlsd = $xn{tlsd}; + $xn{refresh} //= sub { $tlsd->refresh_groups(@_) }; + $xn{post_accept} //= sub { $modc->new($_[0], $tlsd) }; + $xn{af_default} = 'httpready' if $modc eq 'PublicInbox::HTTP'; + \%xn; +} + +sub daemon_prepare ($$) { + my ($default_listen, $xnetd) = @_; my $listener_names = {}; # sockname => IO::Handle $oldset = PublicInbox::DS::block_signals(); @CMD = ($0, @ARGV); my ($prog) = ($CMD[0] =~ m!([^/]+)\z!g); + my $dh = defined($default_listen) ? " (default: $default_listen)" : ''; my $help = <{$l} = load_mod($1); next if $listener_names->{$l}; # already inherited my (%o, $sock_pkg); @@ -270,13 +291,11 @@ sub worker_quit { # $_[0] = signal name or number (unused) my ($dmap, undef) = @_; my $n = 0; my $now = now(); - - foreach my $s (values %$dmap) { + for my $s (values %$dmap) { $s->can('busy') or next; - if ($s->busy($now)) { + if ($s->busy) { ++$n; - } else { - # close as much as possible, early as possible + } else { # close as much as possible, early as possible $s->close; } } @@ -586,14 +605,25 @@ sub defer_accept ($$) { } } -sub daemon_loop ($$$$) { - my ($refresh, $post_accept, $tlsd, $af_default) = @_; +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) { - if ($k =~ s!\A(?:https|imaps|nntps)://!!) { - $post_accept{$k} = tls_start_cb($v, $post_accept); - } elsif ($tlsd) { # STARTTLS, $k eq '' is OK - $tlsd->{accept_tls} = $v; + my $l = $k; + $l =~ s!\A([^:]+)://!!; + my $scheme = $1; + my $xn = $xnetd->{$l} // $xnetd->{''}; + if ($scheme =~ s!\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 = { @@ -621,29 +651,37 @@ sub daemon_loop ($$$$) { $uid = $gid = undef; reopen_logs(); @listeners = map {; - my $tls_cb = $post_accept{sockname($_)}; + my $l = sockname($_); + my $tls_cb = $post_accept{$l}; + my $xn = $xnetd->{$l} // $xnetd->{''}; # NNTPS, HTTPS, HTTP, IMAPS and POP3S are client-first traffic # IMAP, NNTP and POP3 are server-first - defer_accept($_, $tls_cb ? 'dataready' : $af_default); + defer_accept($_, $tls_cb ? 'dataready' : $xn->{af_default}); # this calls epoll_create: - PublicInbox::Listener->new($_, $tls_cb || $post_accept) + PublicInbox::Listener->new($_, $tls_cb || $xn->{post_accept}) } @listeners; PublicInbox::DS::event_loop($sig, $oldset); } -sub run ($$$;$) { - my ($default, $refresh, $post_accept, $tlsd) = @_; - daemon_prepare($default); - my $af_default = $default =~ /:8080\z/ ? 'httpready' : undef; +sub run { + my ($default_listen) = @_; + my $xnetd = {}; + if ($default_listen) { + $default_listen =~ /\A(http|imap|nntp|pop3)/ or + die "BUG: $default_listen"; + $xnetd->{''} = load_mod($1); + } + daemon_prepare($default_listen, $xnetd); my $for_destroy = daemonize(); # localize GCF2C for tests: local $PublicInbox::GitAsyncCat::GCF2C; local $PublicInbox::Git::async_warn = 1; + local $SIG{__WARN__} = PublicInbox::Eml::warn_ignore_cb(); - daemon_loop($refresh, $post_accept, $tlsd, $af_default); + daemon_loop($xnetd); PublicInbox::DS->Reset; # ->DESTROY runs when $for_destroy goes out-of-scope }