about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-06-24 02:52:42 +0000
committerEric Wong <e@80x24.org>2019-06-24 05:26:27 +0000
commit595854982a59f369ab605794f05c046c86253468 (patch)
treea09a07b6178fc16a80af8591f352ff9bd72bdce0
parentb3e4b3b3c67b9df7868518978e721417b0aa7c9c (diff)
downloadpublic-inbox-595854982a59f369ab605794f05c046c86253468.tar.gz
This is in accordance with TLS standards and will be needed
to support session caching/reuse in the future.  However, we
don't issue shutdown(2) since we know not to inadvertantly
share our sockets with other processes.
-rw-r--r--lib/PublicInbox/DS.pm24
-rw-r--r--lib/PublicInbox/NNTP.pm12
-rw-r--r--t/nntpd-tls.t2
3 files changed, 35 insertions, 3 deletions
diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm
index 2c886b4e..2aa9e3d2 100644
--- a/lib/PublicInbox/DS.pm
+++ b/lib/PublicInbox/DS.pm
@@ -621,6 +621,30 @@ sub accept_tls_step ($) {
     drop($self, 'BUG? EAGAIN but '.PublicInbox::TLS::err());
 }
 
+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;
+    if (my $ev = PublicInbox::TLS::epollbit()) {
+        unshift @{$self->{wbuf} ||= []}, \&shutdn_tls_step;
+        return watch($self, $ev | EPOLLONESHOT);
+    }
+    drop($self, 'BUG? EAGAIN but '.PublicInbox::TLS::err());
+}
+
+# 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;
+    }
+}
+
 package PublicInbox::DS::Timer;
 # [$abs_float_firetime, $coderef];
 sub cancel {
diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm
index 8840adbb..53de2bca 100644
--- a/lib/PublicInbox/NNTP.pm
+++ b/lib/PublicInbox/NNTP.pm
@@ -74,11 +74,17 @@ sub expire_old () {
         my $exp = $EXPTIME;
         my $old = $now - $exp;
         my $nr = 0;
+        my $closed = 0;
         my %new;
         while (my ($fd, $v) = each %$EXPMAP) {
                 my ($idle_time, $nntp) = @$v;
                 if ($idle_time < $old) {
-                        $nntp->close; # idempotent
+                        if ($nntp->shutdn) {
+                                $closed++;
+                        } else {
+                                ++$nr;
+                                $new{$fd} = $v;
+                        }
                 } else {
                         ++$nr;
                         $new{$fd} = $v;
@@ -91,7 +97,7 @@ sub expire_old () {
                 $expt = undef;
                 # noop to kick outselves out of the loop ASAP so descriptors
                 # really get closed
-                PublicInbox::EvCleanup::asap(sub {});
+                PublicInbox::EvCleanup::asap(sub {}) if $closed;
         }
 }
 
@@ -410,7 +416,7 @@ sub cmd_post ($) {
 sub cmd_quit ($) {
         my ($self) = @_;
         res($self, '205 closing connection - goodbye!');
-        $self->close;
+        $self->shutdn;
         undef;
 }
 
diff --git a/t/nntpd-tls.t b/t/nntpd-tls.t
index 4727ee5b..00b03b66 100644
--- a/t/nntpd-tls.t
+++ b/t/nntpd-tls.t
@@ -118,6 +118,8 @@ for my $args (
         my $c = Net::NNTP->new($nntps_addr, %o);
         my $list = $c->list;
         is_deeply($list, $expect, 'NNTPS LIST works');
+        is($c->command('QUIT')->response(), Net::Cmd::CMD_OK(), 'QUIT works');
+        is(0, sysread($c, my $buf, 1), 'got EOF after QUIT');
 
         # STARTTLS
         delete $o{SSL};