- my $fd = fileno($sock);
- if ($HaveEpoll) {
- epoll_ctl($Epoll, EPOLL_CTL_MOD, $fd, $ev) and
- confess("EPOLL_CTL_MOD $!");
- } elsif ($HaveKQueue) {
- $KQueue->EV_SET($fd, EVFILT_READ(), kq_flag(EPOLLIN, $ev));
- $KQueue->EV_SET($fd, EVFILT_WRITE(), kq_flag(EPOLLOUT, $ev));
+ return 1 if $sock->accept_SSL;
+ return $self->close if $! != EAGAIN;
+ epwait($sock, PublicInbox::TLS::epollbit() | EPOLLONESHOT);
+ unshift(@{$self->{wbuf}}, \&accept_tls_step); # autovivifies
+ 0;
+}
+
+# return true if complete, false if incomplete (or failure)
+sub shutdn_tls_step ($) {
+ my ($self) = @_;
+ my $sock = $self->{sock} or return;
+ return $self->close if $sock->stop_SSL(SSL_fast_shutdown => 1);
+ return $self->close if $! != EAGAIN;
+ epwait($sock, PublicInbox::TLS::epollbit() | EPOLLONESHOT);
+ unshift(@{$self->{wbuf}}, \&shutdn_tls_step); # autovivifies
+ 0;
+}
+
+# don't bother with shutdown($sock, 2), we don't fork+exec w/o CLOEXEC
+# or fork w/o exec, so no inadvertant socket sharing
+sub shutdn ($) {
+ my ($self) = @_;
+ my $sock = $self->{sock} or return;
+ if (ref($sock) eq 'IO::Socket::SSL') {
+ shutdn_tls_step($self);
+ } else {
+ $self->close;
+ }
+}
+
+# must be called with eval, PublicInbox::DS may not be loaded (see t/qspawn.t)
+sub dwaitpid ($$$) {
+ my ($pid, $cb, $arg) = @_;
+ if ($in_loop) {
+ push @$WaitPids, [ $pid, $cb, $arg ];
+
+ # We could've just missed our SIGCHLD, cover it, here:
+ requeue(\&reap_pids);
+ } else {
+ die "Not in EventLoop\n";
+ }
+}
+
+sub _run_later () {
+ my $run = $later_queue;
+ $later_timer = undef;
+ $later_queue = [];
+ $_->() for @$run;
+}
+
+sub later ($) {
+ my ($cb) = @_;
+ push @$later_queue, $cb;
+ $later_timer //= add_timer(60, \&_run_later);
+}
+
+sub expire_old () {
+ my $now = now();
+ my $exp = $EXPTIME;
+ my $old = $now - $exp;
+ my %new;
+ while (my ($fd, $v) = each %$EXPMAP) {
+ my ($idle_time, $ds_obj) = @$v;
+ if ($idle_time < $old) {
+ if (!$ds_obj->shutdn) {
+ $new{$fd} = $v;
+ }
+ } else {
+ $new{$fd} = $v;
+ }