fix severe bug causing deadlocks

master
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
end end
function serve(h::App, context, host = ip"127.0.0.1", port = 1965; kws...) function serve(h::App, host = ip"127.0.0.1", port = 1965; kws...)
@async listen((req) -> h.warez(req), context, host, port; kws...) @async listen((req) -> h.warez(req), host, port; kws...)
end end

View File

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