fix severe bug causing deadlocks

This commit is contained in:
nixo 2020-10-28 23:45:24 +01:00
parent 4e26e066ad
commit 7b6b1f32d5
2 changed files with 42 additions and 45 deletions

View File

@ -62,6 +62,6 @@ macro app(def)
end
end
function serve(h::App, context, host = ip"127.0.0.1", port = 1965; kws...)
@async listen((req) -> h.warez(req), context, host, port; kws...)
function serve(h::App, host = ip"127.0.0.1", port = 1965; kws...)
@async listen((req) -> h.warez(req), host, port; kws...)
end

View File

@ -1,5 +1,5 @@
function listen(f,
context::SSLContext,
init_context,
host::Union{IPAddr, String} = Sockets.localhost,
port::Integer = 1965
;
@ -9,35 +9,36 @@ function listen(f,
server = Sockets.listen(Sockets.InetAddr(host, port))
verbose && @info "Listening on: $host:$port"
return listenloop(f, server, context, connection_count, readtimeout, verbose)
return listenloop(f, server, init_context, connection_count, readtimeout, verbose)
end
""""
Main server loop.
Accepts new tcp connections and spawns async tasks to handle them."
"""
function listenloop(f, server, context, connection_count, readtimeout, verbose)
function listenloop(f, server, init_context, connection_count, readtimeout, verbose)
count = 1
while isopen(server)
try
# @info "Ready to accept new connection"
verbose && @info "Ready to accept new connection"
io = accept(server)
if io === nothing
if isnothing(io)
verbose && @warn "unable to accept new connection"
continue
end
connection_count[] += 1
verbose && @info "$(connection_count[]) total connections"
@async try
handle_connection(f, server, context, io, verbose)
handle_connection(f, server, init_context, io, verbose)
catch e
if e isa Base.IOError && e.code == -54
if e isa Base.IOError && e.code in (-54, -104)
verbose && @warn "connection reset by peer (ECONNRESET)"
else
@error exception=(e, stacktrace(catch_backtrace()))
@warn exception=(e, stacktrace(catch_backtrace()))
end
finally
connection_count[] -= 1
verbose && @info "$(connection_count[]) total connections"
# handle_connection is in charge of closing the underlying io
end
catch e
@ -50,47 +51,43 @@ function listenloop(f, server, context, connection_count, readtimeout, verbose)
end
end
count += 1
verbose && @info "Responded to $(count) clients in total"
end
return
end
function handle_connection(f, server, context, io, verbose)
client = SSLClient(context, io)
while isopen(server) && isopen(io)
try
while true
if isreadable(io) && length(client.write_buf) == 0
# verbose && println("do_read")
if OpenSSL.do_sock_read(client) == -1
break
end
end
if iswritable(io) && length(client.write_buf) > 0
# verbose && println("do_write")
if OpenSSL.do_sock_write(client) == -1
break
end
end
# verbose && println("end loop")
if OpenSSL.ssl_init_finished(client)
# verbose && println("init_finished")
# TODO: add a timeout!
while isopen(server) && isopen(io) &&
(length(client.context.data) < 2 ||
client.context.data[end-1:end] != UInt8['\r', '\n'])
# println("HERE")
OpenSSL.do_sock_read(client)
end
f(GeminiRequest(Connection(server, client),
Request(String(client.context.data)),
Dict()))
function handle_connection(f, server, init_context, io, verbose)
client = SSLClient(init_context(), io)
try
while isopen(server) && isopen(io)
if isreadable(io) && length(client.write_buf) == 0
if OpenSSL.do_sock_read(client) == -1
break
end
end
catch e
rethrow(e)
finally
close(client)
if iswritable(io) && length(client.write_buf) > 0
verbose && println("do_write")
if OpenSSL.do_sock_write(client) == -1
break
end
end
if OpenSSL.ssl_init_finished(client)
verbose && println("init_finished")
# TODO: add a timeout!
while isopen(server) && isopen(io) &&
(length(client.context.data) < 2 ||
client.context.data[end-1:end] != UInt8['\r', '\n'])
OpenSSL.do_sock_read(client)
end
f(GeminiRequest(Connection(server, client),
Request(String(client.context.data)),
Dict()))
break
end
end
catch e
rethrow(e)
finally
close(client)
end
end