From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH 06/11] ds: consolidate IO::Socket::SSL checks
Date: Sat, 29 Jun 2019 19:59:46 +0000 [thread overview]
Message-ID: <20190629195951.32160-7-e@80x24.org> (raw)
In-Reply-To: <20190629195951.32160-1-e@80x24.org>
We need to be careful about handling EAGAIN on write(2)
failures deal with SSL_WANT_READ vs SSL_WANT_WRITE as
appropriate.
---
lib/PublicInbox/DS.pm | 48 +++++++++++++++++++++++++-----------------------
lib/PublicInbox/NNTP.pm | 3 ++-
lib/PublicInbox/TLS.pm | 9 +++------
3 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm
index 6cd527e2..b2f59983 100644
--- a/lib/PublicInbox/DS.pm
+++ b/lib/PublicInbox/DS.pm
@@ -388,6 +388,10 @@ sub psendfile ($$$) {
$written;
}
+sub epbit ($$) { # (sock, default)
+ ref($_[0]) eq 'IO::Socket::SSL' ? PublicInbox::TLS::epollbit() : $_[1];
+}
+
# returns 1 if done, 0 if incomplete
sub flush_write ($) {
my ($self) = @_;
@@ -406,8 +410,8 @@ next_buf:
goto next_buf;
}
} elsif ($! == EAGAIN) {
+ epwait($sock, epbit($sock, EPOLLOUT) | EPOLLONESHOT);
$self->{wbuf_off} = $off;
- watch($self, EPOLLOUT|EPOLLONESHOT);
return 0;
} else {
return $self->close;
@@ -438,17 +442,13 @@ sub rbuf_idle ($$) {
sub do_read ($$$;$) {
my ($self, $rbuf, $len, $off) = @_;
- my $r = sysread($self->{sock}, $$rbuf, $len, $off // 0);
+ my $r = sysread(my $sock = $self->{sock}, $$rbuf, $len, $off // 0);
return ($r == 0 ? $self->close : $r) if defined $r;
# common for clients to break connections without warning,
# would be too noisy to log here:
- if (ref($self) eq 'IO::Socket::SSL') {
- my $ev = PublicInbox::TLS::epollbit() or return $self->close;
+ if ($! == EAGAIN) {
+ epwait($sock, epbit($sock, EPOLLIN) | EPOLLONESHOT);
rbuf_idle($self, $rbuf);
- watch($self, $ev | EPOLLONESHOT);
- } elsif ($! == EAGAIN) {
- rbuf_idle($self, $rbuf);
- watch($self, EPOLLIN | EPOLLONESHOT);
} else {
$self->close;
}
@@ -525,17 +525,20 @@ sub write {
if (defined $written) {
return 1 if $written == $to_write;
+ requeue($self); # runs: event_step -> flush_write
} elsif ($! == EAGAIN) {
+ epwait($sock, epbit($sock, EPOLLOUT) | EPOLLONESHOT);
$written = 0;
} else {
return $self->close;
}
+
+ # deal with EAGAIN or partial write:
my $tmpio = tmpio($self, $bref, $written) or return 0;
# wbuf may be an empty array if we're being called inside
# ->flush_write via CODE bref:
push @{$self->{wbuf} ||= []}, $tmpio;
- watch($self, EPOLLOUT|EPOLLONESHOT);
return 0;
}
}
@@ -554,32 +557,34 @@ sub msg_more ($$) {
# queue up the unwritten substring:
my $tmpio = tmpio($self, \($_[1]), $n) or return 0;
$self->{wbuf} = [ $tmpio ];
- watch($self, EPOLLOUT|EPOLLONESHOT);
+ epwait($sock, EPOLLOUT|EPOLLONESHOT);
return 0;
}
}
$self->write(\($_[1]));
}
-sub watch ($$) {
- my ($self, $ev) = @_;
- my $sock = $self->{sock} or return;
+sub epwait ($$) {
+ my ($sock, $ev) = @_;
epoll_ctl($Epoll, EPOLL_CTL_MOD, fileno($sock), $ev) and
confess("EPOLL_CTL_MOD $!");
0;
}
+sub watch ($$) {
+ my ($self, $ev) = @_;
+ my $sock = $self->{sock} or return;
+ epwait($sock, $ev);
+}
+
# return true if complete, false if incomplete (or failure)
sub accept_tls_step ($) {
my ($self) = @_;
my $sock = $self->{sock} or return;
return 1 if $sock->accept_SSL;
return $self->close if $! != EAGAIN;
- if (my $ev = PublicInbox::TLS::epollbit()) {
- unshift @{$self->{wbuf} ||= []}, \&accept_tls_step;
- return watch($self, $ev | EPOLLONESHOT);
- }
- drop($self, 'BUG? EAGAIN but '.PublicInbox::TLS::err());
+ epwait($sock, PublicInbox::TLS::epollbit() | EPOLLONESHOT);
+ unshift @{$self->{wbuf} ||= []}, \&accept_tls_step;
}
sub shutdn_tls_step ($) {
@@ -587,11 +592,8 @@ sub shutdn_tls_step ($) {
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());
+ epwait($sock, PublicInbox::TLS::epollbit() | EPOLLONESHOT);
+ unshift @{$self->{wbuf} ||= []}, \&shutdn_tls_step;
}
# don't bother with shutdown($sock, 2), we don't fork+exec w/o CLOEXEC
diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm
index 9973fcaf..82762b1a 100644
--- a/lib/PublicInbox/NNTP.pm
+++ b/lib/PublicInbox/NNTP.pm
@@ -75,7 +75,8 @@ sub new ($$$) {
my $ev = EPOLLIN;
my $wbuf;
if (ref($sock) eq 'IO::Socket::SSL' && !$sock->accept_SSL) {
- $ev = PublicInbox::TLS::epollbit() or return CORE::close($sock);
+ return CORE::close($sock) if $! != EAGAIN;
+ $ev = PublicInbox::TLS::epollbit();
$wbuf = [ \&PublicInbox::DS::accept_tls_step, \&greet ];
}
$self->SUPER::new($sock, $ev | EPOLLONESHOT);
diff --git a/lib/PublicInbox/TLS.pm b/lib/PublicInbox/TLS.pm
index 576c11d7..0b9a55df 100644
--- a/lib/PublicInbox/TLS.pm
+++ b/lib/PublicInbox/TLS.pm
@@ -13,12 +13,9 @@ sub err () { $SSL_ERROR }
# returns the EPOLL event bit which matches the existing SSL error
sub epollbit () {
- if ($! == EAGAIN) {
- return EPOLLIN if $SSL_ERROR == SSL_WANT_READ;
- return EPOLLOUT if $SSL_ERROR == SSL_WANT_WRITE;
- die "unexpected SSL error: $SSL_ERROR";
- }
- 0;
+ return EPOLLIN if $SSL_ERROR == SSL_WANT_READ;
+ return EPOLLOUT if $SSL_ERROR == SSL_WANT_WRITE;
+ die "unexpected SSL error: $SSL_ERROR";
}
1;
--
EW
next prev parent reply other threads:[~2019-06-29 19:59 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-29 19:59 [PATCH 00/11] ds: more updates Eric Wong
2019-06-29 19:59 ` [PATCH 01/11] ds: share lazy rbuf handling between HTTP and NNTP Eric Wong
2019-06-29 19:59 ` [PATCH 02/11] ds: move requeue logic over from NNTP Eric Wong
2019-06-29 19:59 ` [PATCH 03/11] http: use requeue instead of watch_in1 Eric Wong
2019-06-29 19:59 ` [PATCH 04/11] listener: use edge-triggered notifications Eric Wong
2019-06-29 19:59 ` [PATCH 05/11] ds: handle deferred DS->close after timers Eric Wong
2019-06-29 19:59 ` Eric Wong [this message]
2019-06-29 19:59 ` [PATCH 07/11] http: support HTTPS (kinda) Eric Wong
2019-06-29 19:59 ` [PATCH 08/11] parentpipe: document and use one-shot wakeups Eric Wong
2019-06-29 19:59 ` [PATCH 09/11] parentpipe: make the ->close call more obvious Eric Wong
2019-06-29 19:59 ` [PATCH 10/11] httpd/async: switch to buffering-as-fast-as-possible Eric Wong
2019-06-29 19:59 ` [PATCH 11/11] http: use bigger, but shorter-lived buffers for pipes Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://public-inbox.org/README
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190629195951.32160-7-e@80x24.org \
--to=e@80x24.org \
--cc=meta@public-inbox.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/public-inbox.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).