From 08feae92c15ec127bb9038cd9615670b0824b4cd Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Mon, 8 Nov 2021 21:38:02 +0100 Subject: [PATCH 1/3] Close handle when closing the stream At the end of the connection, each side sends a close_notify alert to inform the peer that the connection is closed. IO::Socket::SSL does that, if its close method is called. --- lib/Mojo/IOLoop/Stream.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Mojo/IOLoop/Stream.pm b/lib/Mojo/IOLoop/Stream.pm index 2f191ce5ac..fdcc0c82ce 100644 --- a/lib/Mojo/IOLoop/Stream.pm +++ b/lib/Mojo/IOLoop/Stream.pm @@ -25,6 +25,7 @@ sub close { return unless my $handle = delete $self->timeout(0)->{handle}; $reactor->remove($handle); $self->emit('close'); + $handle->close; } sub close_gracefully { $_[0]->is_writing ? $_[0]{graceful}++ : $_[0]->close } From dc7bcef0aa27a5ca6c7eecc9ce0cb94e48310f45 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Thu, 1 Jun 2023 15:09:47 +0200 Subject: [PATCH 2/3] Add unit test for TSL shutdown --- t/mojo/ioloop_tls.t | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/t/mojo/ioloop_tls.t b/t/mojo/ioloop_tls.t index aa48cb8c6a..20a46002eb 100644 --- a/t/mojo/ioloop_tls.t +++ b/t/mojo/ioloop_tls.t @@ -58,6 +58,43 @@ Mojo::Promise->all($promise, $promise2)->wait; is $server, 'tset123', 'right content'; is $client, "${upgraded}321", 'right content'; +# Shutdown +$loop = Mojo::IOLoop->new; +$promise = Mojo::Promise->new->ioloop($loop); +$id = $loop->server( + {address => '127.0.0.1', tls => 1} => sub { + my ($loop, $stream) = @_; + $stream->on( + read => sub { + $stream->write("close"); + shift->close_gracefully(); + $promise->resolve; + } + ); + } +); +$promise2 = Mojo::Promise->new->ioloop($loop); +$port = $loop->acceptor($id)->port; +my ($shutdown, $handle); +$loop->client( + {port => $port, tls => 1, tls_options => {SSL_verify_mode => 0x00}} => sub { + my ($loop, $err, $stream) = @_; + $stream->write('quit'); + $stream->on( + close => sub { + my $ssl = ${*$handle}{_SSL_object}; + $shutdown = Net::SSLeay::get_shutdown($ssl); + $promise2->resolve; + } + ); + # keep a reference the IO::Socket::SSL + $handle = $stream->{handle}; + $shutdown = 0; + } +); +Mojo::Promise->all($promise, $promise2)->wait; +is $shutdown, 2, 'SSL received shutdown'; + # Valid client certificate ($server, $client) = (); my ($remove, $running, $timeout, $server_err, $server_close, $client_close); From 66c46d00e55ccabb783d7be564e4a6a8b5b62234 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Thu, 1 Jun 2023 19:11:00 +0200 Subject: [PATCH 3/3] Fix whitespace to satisfy perltidy --- t/mojo/ioloop_tls.t | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/t/mojo/ioloop_tls.t b/t/mojo/ioloop_tls.t index 20a46002eb..b896e83b51 100644 --- a/t/mojo/ioloop_tls.t +++ b/t/mojo/ioloop_tls.t @@ -59,13 +59,13 @@ is $server, 'tset123', 'right content'; is $client, "${upgraded}321", 'right content'; # Shutdown -$loop = Mojo::IOLoop->new; +$loop = Mojo::IOLoop->new; $promise = Mojo::Promise->new->ioloop($loop); -$id = $loop->server( +$id = $loop->server( {address => '127.0.0.1', tls => 1} => sub { my ($loop, $stream) = @_; $stream->on( - read => sub { + read => sub { $stream->write("close"); shift->close_gracefully(); $promise->resolve; @@ -74,7 +74,7 @@ $id = $loop->server( } ); $promise2 = Mojo::Promise->new->ioloop($loop); -$port = $loop->acceptor($id)->port; +$port = $loop->acceptor($id)->port; my ($shutdown, $handle); $loop->client( {port => $port, tls => 1, tls_options => {SSL_verify_mode => 0x00}} => sub { @@ -87,8 +87,9 @@ $loop->client( $promise2->resolve; } ); + # keep a reference the IO::Socket::SSL - $handle = $stream->{handle}; + $handle = $stream->{handle}; $shutdown = 0; } ); @@ -118,11 +119,11 @@ $id = Mojo::IOLoop->server( } ); $stream->on(error => sub { $server_err = pop }); - $stream->on(read => sub { $server .= pop }); + $stream->on(read => sub { $server .= pop }); $stream->timeout(0.5); } ); -$port = Mojo::IOLoop->acceptor($id)->port; +$port = Mojo::IOLoop->acceptor($id)->port; $promise2 = Mojo::Promise->new; Mojo::IOLoop->client( port => $port,