Skip to content

Commit

Permalink
Fix SSLServer#accept failures causing accept loop to exit.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed May 9, 2024
1 parent e82badc commit 24ad8ee
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 29 deletions.
4 changes: 3 additions & 1 deletion lib/io/endpoint/ssl_endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ def context
end

def make_server(io)
::OpenSSL::SSL::SSLServer.new(io, self.context)
::OpenSSL::SSL::SSLServer.new(io, self.context).tap do |server|
server.start_immediately = false
end
end

def make_socket(io)
Expand Down
9 changes: 8 additions & 1 deletion lib/io/endpoint/wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,14 @@ def accept(server, timeout: nil, linger: nil, **options, &block)
end

async do
# Maybe we can expose this back to the endpoint?
socket.accept if socket.respond_to?(:accept)

yield socket, address
rescue => error
socket.close

raise
end
end
end
Expand All @@ -176,7 +183,7 @@ def async(&block)
::Thread.new(&block)
end
end

class FiberWrapper < Wrapper
def async(&block)
::Fiber.schedule(&block)
Expand Down
97 changes: 70 additions & 27 deletions test/io/endpoint/ssl_endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,83 @@
require 'sus/fixtures/openssl'

describe IO::Endpoint::SSLEndpoint do
include Sus::Fixtures::OpenSSL::ValidCertificateContext
include Sus::Fixtures::OpenSSL::VerifiedCertificateContext

let(:endpoint) {IO::Endpoint.tcp("localhost", 0)}
let(:server_endpoint) {subject.new(endpoint, ssl_context: server_context)}

def client_endpoint(address)
endpoint = IO::Endpoint::AddressEndpoint.new(address)
return subject.new(endpoint, ssl_context: client_context)
with "valid certificates" do
include Sus::Fixtures::OpenSSL::ValidCertificateContext
include Sus::Fixtures::OpenSSL::VerifiedCertificateContext

let(:endpoint) {IO::Endpoint.tcp("localhost", 0)}
let(:server_endpoint) {subject.new(endpoint, ssl_context: server_context)}

def client_endpoint(address)
endpoint = IO::Endpoint::AddressEndpoint.new(address)
return subject.new(endpoint, ssl_context: client_context)
end

it "can connect to bound address" do
bound = server_endpoint.bound

bound.bind do |server|
expect(server).to be_a(::OpenSSL::SSL::SSLServer)

peer, address = server.accept
peer.accept
peer.close
end

bound.sockets.each do |server|
connect_endpoint = client_endpoint(server.local_address)

client = connect_endpoint.connect
expect(client).to be_a(::OpenSSL::SSL::SSLSocket)
expect(client).to be(:sync_close)

# Wait for the connection to be closed.
client.wait_readable

client.close
end
ensure
bound&.close
end
end

it "can connect to bound address" do
bound = server_endpoint.bound
with "invalid certificates" do
include Sus::Fixtures::OpenSSL::InvalidCertificateContext
include Sus::Fixtures::OpenSSL::VerifiedCertificateContext

bound.bind do |server|
expect(server).to be_a(::OpenSSL::SSL::SSLServer)

peer, address = server.accept
peer.close
let(:endpoint) {IO::Endpoint.tcp("localhost", 0)}
let(:server_endpoint) {subject.new(endpoint, ssl_context: server_context)}

def client_endpoint(address)
endpoint = IO::Endpoint::AddressEndpoint.new(address)
return subject.new(endpoint, ssl_context: client_context)
end

bound.sockets.each do |server|
connect_endpoint = client_endpoint(server.local_address)

client = connect_endpoint.connect
expect(client).to be_a(::OpenSSL::SSL::SSLSocket)
expect(client).to be(:sync_close)
it "doesn't cause the accept loop to exit" do
bound = server_endpoint.bound

# Wait for the connection to be closed.
client.wait_readable
bound.bind do |server|
wrapper = IO::Endpoint::Wrapper.default

wrapper.accept(server) do |peer|
peer.close
end
rescue IOError
# Normal exit from bound&.close
end

client.close
2.times do
bound.sockets.each do |server|
connect_endpoint = client_endpoint(server.local_address)
begin
connect_endpoint.connect
rescue
# Ignore.
end
end
end
ensure
bound&.close
end
ensure
bound&.close
end
end

0 comments on commit 24ad8ee

Please sign in to comment.