Skip to content

Commit

Permalink
Merge pull request #165 from emqx/ssl-gc
Browse files Browse the repository at this point in the history
feat: add option to run gc after TLS/SSL handshake
  • Loading branch information
HJianBo authored Aug 3, 2022
2 parents 3ba3a8a + dfdc6ca commit 26fffb6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/esockd.app.src
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{application, esockd,
[{description, "General Non-blocking TCP/SSL and UDP/DTLS Server"},
{id, "esockd"},
{vsn, "5.9.3"},
{vsn, "5.9.4"},
{modules, []},
{registered, []},
{applications, [kernel, stdlib, sasl, ssl]},
Expand Down
18 changes: 14 additions & 4 deletions src/esockd.appup.src
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
%%-*-: erlang -*-
%%-*- mode: erlang; -*-

{"5.9.3",
[{"5.9.2",
{"5.9.4",
[{"5.9.3",
[ {load_module,esockd_transport,brutal_purge,soft_purge,[]}
]
},
{"5.9.2",
[ {load_module,esockd_udp,brutal_purge,soft_purge,[]}
, {load_module,esockd_transport,brutal_purge,soft_purge,[]}
]
},
{"5.9.1",
Expand All @@ -23,8 +28,13 @@
},
{<<".*">>, []}
],
[{"5.9.2",
[{"5.9.3",
[ {load_module,esockd_transport,brutal_purge,soft_purge,[]}
]
},
{"5.9.2",
[ {load_module,esockd_udp,brutal_purge,soft_purge,[]}
, {load_module,esockd_transport,brutal_purge,soft_purge,[]}
]
},
{"5.9.1",
Expand Down
34 changes: 29 additions & 5 deletions src/esockd_transport.erl
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,15 @@ shutdown(#proxy_socket{socket = Sock}, How) ->
-spec(ssl_upgrade_fun([ssl:ssl_option()]) -> esockd:sock_fun()).
ssl_upgrade_fun(SslOpts) ->
{Timeout, SslOpts1} = take_handshake_timeout(SslOpts),
{fun ?MODULE:ssl_upgrade/3, [SslOpts1, Timeout]}.
{GCAfterHandshake, SslOpts2} = take_gc_after_handshake(SslOpts1),
{fun ?MODULE:ssl_upgrade/3, [SslOpts2, #{timeout => Timeout,
gc_after_handshake => GCAfterHandshake}]}.

ssl_upgrade(Sock, SslOpts1, Timeout) ->
ssl_upgrade(Sock, SslOpts1, #{timeout := Timeout,
gc_after_handshake := GCAfterHandshake}) ->
try do_ssl_handshake(Sock, SslOpts1, Timeout) of
{ok, NSock} ->
GCAfterHandshake andalso gc(NSock),
{ok, NSock};
{error, Reason} when Reason =:= closed; Reason =:= timeout ->
{error, Reason};
Expand Down Expand Up @@ -395,6 +399,10 @@ take_handshake_timeout(SslOpts) ->
{?SSL_HANDSHAKE_TIMEOUT, SslOpts}
end.

take_gc_after_handshake(SslOpts) ->
{proplists:get_bool(gc_after_handshake, SslOpts),
proplists:delete(gc_after_handshake, SslOpts)}.

%% @doc TCP | SSL -> ProxySocket
proxy_upgrade_fun(Opts) ->
Timeout = proxy_protocol_timeout(Opts),
Expand Down Expand Up @@ -422,12 +430,28 @@ ensure_ok_or_exit(Fun, Args = [Sock|_]) when is_atom(Fun), is_list(Args) ->
end.

gc(Sock) when is_port(Sock) ->
ok;
case erlang:port_info(Sock, connected) of
{connected, Pid} ->
erlang:garbage_collect(Pid),
ok;
undefined ->
ok
end;
%% Defined in ssl/src/ssl_api.hrl:
%% -record(sslsocket, {fd = nil, pid = nil}).
gc(#ssl_socket{ssl = {sslsocket, _, Pid}}) when is_pid(Pid) ->
erlang:garbage_collect(Pid);
erlang:garbage_collect(Pid),
ok;
%% In OTP 24+, the last element is a list of PIDs The first is spawned
%% by `ssl_gen_statem:init/1', the second by `tls_sender:init/1`.
gc(#ssl_socket{ssl = {sslsocket, _, Pids}}) when is_list(Pids) ->
lists:foreach(
fun(Pid) when is_pid(Pid) ->
erlang:garbage_collect(Pid);
(_) ->
ok
end,
Pids);
gc(#proxy_socket{socket = Sock}) ->
gc(Sock);
gc(_Sock) -> ok.

22 changes: 19 additions & 3 deletions test/esockd_transport_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ t_send_ssl(Config) ->
ok = esockd_transport:close(#ssl_socket{ssl = SslSock}),
ok = esockd:close(echo, 8883).

t_send_ssl_gc_after_handshake(Config) ->
ssl:start(),
SslOpts = [{certfile, esockd_ct:certfile(Config)},
{keyfile, esockd_ct:keyfile(Config)},
{gc_after_handshake, true}],
{ok, _} = esockd:open(echo, 8883, [{ssl_options, SslOpts}], {echo_server, start_link, []}),
{ok, SslSock} = ssl:connect({127,0,0,1}, 8883, [], 3000),
ok = esockd_transport:send(#ssl_socket{ssl = SslSock}, <<"Hello">>),
ok = esockd_transport:close(#ssl_socket{ssl = SslSock}),
ok = esockd:close(echo, 8883).

t_send_proxy(_) ->
{ok, _} = esockd:open(echo, 5000, [{tcp_options, [binary]},
proxy_protocol,
Expand Down Expand Up @@ -188,11 +199,16 @@ t_proxy_upgrade_fun(_) ->
?assert(is_function(Fun)).

t_ssl_upgrade_fun(_) ->
{Fun, [[], 1000]} = esockd_transport:ssl_upgrade_fun([{handshake_timeout, 1000}]),
?assert(is_function(Fun)).
{Fun0, [[], #{timeout := 1000, gc_after_handshake := false}]}
= esockd_transport:ssl_upgrade_fun([{handshake_timeout, 1000}]),
?assert(is_function(Fun0, 3)),
{Fun1, [[], #{timeout := 1000, gc_after_handshake := true}]}
= esockd_transport:ssl_upgrade_fun([{handshake_timeout, 1000},
{gc_after_handshake, true}]),
?assert(is_function(Fun1, 3)),
ok.

t_fast_close(_) ->
{ok, LSock} = esockd_transport:listen(3000, [{reuseaddr, true}]),
ok = esockd_transport:fast_close(LSock),
ok = esockd_transport:close(LSock).

0 comments on commit 26fffb6

Please sign in to comment.