Skip to content

Commit bf50db9

Browse files
authored
Merge pull request #4447 from esl/just_ssl_optimisations
Optimise just_tls with hibernate_after
2 parents 70b30f4 + 80e5e94 commit bf50db9

File tree

3 files changed

+75
-66
lines changed

3 files changed

+75
-66
lines changed

src/c2s/mongoose_c2s_ranch.erl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,16 @@ socket_peername(#state{ip = Ip}) ->
4848

4949
-spec tcp_to_tls(state(), mongoose_listener:options()) ->
5050
{ok, state()} | {error, term()}.
51-
tcp_to_tls(#state{socket = TcpSocket} = State, #{tls := #{module := TlsMod} = TlsConfig}) ->
52-
case tcp_to_tls(TlsMod, TcpSocket, TlsConfig) of
51+
tcp_to_tls(#state{socket = TcpSocket} = State,
52+
#{hibernate_after := HibernateAfter, tls := #{module := TlsMod} = TlsConfig}) ->
53+
case tcp_to_tls(TlsMod, TcpSocket, TlsConfig, HibernateAfter) of
5354
{ok, TlsSocket} ->
5455
{ok, State#state{transport = TlsMod, socket = TlsSocket}};
5556
{error, Reason} ->
5657
{error, Reason}
5758
end.
5859

59-
tcp_to_tls(fast_tls, TcpSocket, TlsConfig) ->
60+
tcp_to_tls(fast_tls, TcpSocket, TlsConfig, _HibernateAfter) ->
6061
PreparedOpts = mongoose_tls:prepare_options(fast_tls, maps:remove(module, TlsConfig)),
6162
ranch_tcp:setopts(TcpSocket, [{active, false}]),
6263
case fast_tls:tcp_to_tls(TcpSocket, PreparedOpts) of
@@ -65,8 +66,8 @@ tcp_to_tls(fast_tls, TcpSocket, TlsConfig) ->
6566
{ok, TlsSocket};
6667
Other -> Other
6768
end;
68-
tcp_to_tls(just_tls, TcpSocket, TlsConfig) ->
69-
case just_tls:tcp_to_tls(TcpSocket, TlsConfig) of
69+
tcp_to_tls(just_tls, TcpSocket, TlsConfig, HibernateAfter) ->
70+
case just_tls:tcp_to_tls(TcpSocket, TlsConfig#{hibernate_after => HibernateAfter}) of
7071
{ok, TlsSocket} -> {ok, TlsSocket};
7172
Other -> Other
7273
end.

src/just_tls.erl

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ tcp_to_tls(TCPSocket, Options) ->
5050
{Ref, SSLOpts} = format_opts_with_ref(Options, false),
5151
{Ref, ssl:connect(TCPSocket, SSLOpts)};
5252
#{} ->
53-
FailIfNoPeerCert = fail_if_no_peer_cert_opt(Options),
54-
{Ref, SSLOpts} = format_opts_with_ref(Options, FailIfNoPeerCert),
53+
{Ref, SSLOpts} = format_opts_with_ref(Options, fail_if_no_peer_cert),
5554
{Ref, ssl:handshake(TCPSocket, SSLOpts, 5000)}
5655
end,
5756
VerifyResults = receive_verify_results(Ref1),
@@ -61,42 +60,36 @@ tcp_to_tls(TCPSocket, Options) ->
6160
_ -> Ret
6261
end.
6362

64-
%% -callback send(tls_socket(), binary()) -> ok | {error, any()}.
63+
-spec send(tls_socket(), binary()) -> ok | {error, any()}.
6564
send(#tls_socket{ssl_socket = SSLSocket}, Packet) -> ssl:send(SSLSocket, Packet).
6665

67-
%% -callback recv_data(tls_socket(), binary()) -> {ok, binary()} | {error, any()}.
68-
recv_data(_, <<"">>) ->
66+
-spec recv_data(tls_socket(), binary()) -> {ok, binary()} | {error, any()}.
67+
recv_data(_, <<>>) ->
6968
%% such call is required for fast_tls to accomplish
7069
%% tls handshake, for just_tls we can ignore it
71-
{ok, <<"">>};
70+
{ok, <<>>};
7271
recv_data(#tls_socket{ssl_socket = SSLSocket}, Data1) ->
7372
case ssl:recv(SSLSocket, 0, 0) of
7473
{ok, Data2} -> {ok, <<Data1/binary, Data2/binary>>};
7574
_ -> {ok, Data1}
7675
end.
7776

78-
%% -callback controlling_process(tls_socket(), pid()) -> ok | {error, any()}.
77+
-spec controlling_process(tls_socket(), pid()) -> ok | {error, any()}.
7978
controlling_process(#tls_socket{ssl_socket = SSLSocket}, Pid) ->
8079
ssl:controlling_process(SSLSocket, Pid).
8180

82-
83-
%% -callback sockname(tls_socket()) -> {ok, {inet:ip_address(), inet:port_number()}} |
84-
%% {error, any()}.
81+
-spec sockname(tls_socket()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, any()}.
8582
sockname(#tls_socket{ssl_socket = SSLSocket}) -> ssl:sockname(SSLSocket).
8683

87-
88-
%% -callback peername(tls_socket()) -> {ok, {inet:ip_address(), inet:port_number()}} |
89-
%% {error, any()}.
84+
-spec peername(tls_socket()) ->
85+
{ok, {inet:ip_address(), inet:port_number()}} | {error, any()}.
9086
peername(#tls_socket{ssl_socket = SSLSocket}) -> ssl:peername(SSLSocket).
9187

92-
93-
%% -callback setopts(tls_socket(), Opts::list()) -> ok | {error, any()}.
88+
-spec setopts(tls_socket(), Opts::list()) -> ok | {error, any()}.
9489
setopts(#tls_socket{ssl_socket = SSLSocket}, Opts) -> ssl:setopts(SSLSocket, Opts).
9590

96-
97-
%% -callback get_peer_certificate(tls_socket()) -> {ok, Cert::any()} |
98-
%% {bad_cert, bitstring()} |
99-
%% no_peer_cert.
91+
-spec get_peer_certificate(tls_socket()) ->
92+
{ok, Cert::any()} | {bad_cert, bitstring()} | no_peer_cert.
10093
get_peer_certificate(#tls_socket{verify_results = [], ssl_socket = SSLSocket}) ->
10194
case ssl:peercert(SSLSocket) of
10295
{ok, PeerCert} ->
@@ -107,66 +100,74 @@ get_peer_certificate(#tls_socket{verify_results = [], ssl_socket = SSLSocket}) -
107100
get_peer_certificate(#tls_socket{verify_results = [Err | _]}) ->
108101
{bad_cert, error_to_list(Err)}.
109102

110-
%% -callback close(tls_socket()) -> ok.
111-
close(#tls_socket{ssl_socket = SSLSocket}) -> ssl:close(SSLSocket).
103+
-spec close(tls_socket()) -> ok.
104+
close(#tls_socket{ssl_socket = SSLSocket}) ->
105+
ssl:close(SSLSocket).
112106

113107
%% @doc Prepare SSL options for direct use of ssl:connect/2 (client side)
114108
%% The `disconnect_on_failure' option is expected to be unset or true
115109
-spec make_ssl_opts(mongoose_tls:options()) -> [ssl:tls_option()].
116-
make_ssl_opts(Opts) ->
117-
{dummy_ref, SSLOpts} = format_opts_with_ref(Opts, false),
118-
SSLOpts.
110+
make_ssl_opts(#{verify_mode := Mode} = Opts) ->
111+
SslOpts = format_opts(Opts, false),
112+
[{verify_fun, verify_fun(Mode)} | SslOpts].
119113

120114
%% @doc Prepare SSL options for direct use of ssl:handshake/2 (server side)
121115
%% The `disconnect_on_failure' option is expected to be unset or true
122116
-spec make_cowboy_ssl_opts(mongoose_tls:options()) -> [ssl:tls_option()].
123-
make_cowboy_ssl_opts(Opts) ->
124-
FailIfNoPeerCert = fail_if_no_peer_cert_opt(Opts),
125-
{dummy_ref, SSLOpts} = format_opts_with_ref(Opts, FailIfNoPeerCert),
126-
SSLOpts.
117+
make_cowboy_ssl_opts(#{verify_mode := Mode} = Opts) ->
118+
SslOpts = format_opts(Opts, fail_if_no_peer_cert),
119+
[{verify_fun, verify_fun(Mode)} | SslOpts].
127120

128121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129122
%% local functions
130123
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131124

132125
format_opts_with_ref(Opts, FailIfNoPeerCert) ->
133-
Verify = verify_opt(Opts),
126+
SslOpts0 = format_opts(Opts, FailIfNoPeerCert),
134127
{Ref, VerifyFun} = verify_fun_opt(Opts),
135-
SNIOpts = sni_opts(Opts),
136-
SSLOpts = maps:to_list(maps:with(ssl_option_keys(), Opts)),
137-
{Ref, [{fail_if_no_peer_cert, FailIfNoPeerCert}, {verify, Verify}, {verify_fun, VerifyFun}] ++
138-
SNIOpts ++ SSLOpts}.
128+
SslOpts = [{verify_fun, VerifyFun} | SslOpts0],
129+
{Ref, SslOpts}.
130+
131+
format_opts(Opts, FailIfNoPeerCert) ->
132+
SslOpts0 = maps:to_list(maps:with(ssl_option_keys(), Opts)),
133+
SslOpts1 = sni_opts(SslOpts0, Opts),
134+
SslOpts2 = verify_opts(SslOpts1, Opts),
135+
SslOpts3 = hibernate_opts(SslOpts2, Opts),
136+
fail_if_no_peer_cert_opts(SslOpts3, Opts, FailIfNoPeerCert).
139137

140138
ssl_option_keys() ->
141139
[certfile, cacertfile, ciphers, keyfile, password, versions, dhfile].
142140

143-
sni_opts(#{server_name_indication := SNIOpts}) ->
144-
process_sni_opts(SNIOpts);
145-
sni_opts(#{}) ->
146-
[].
147-
148-
process_sni_opts(#{enabled := false}) ->
149-
[{server_name_indication, disable}];
150-
process_sni_opts(#{enabled := true, host := SNIHost, protocol := https}) ->
151-
[{server_name_indication, SNIHost},
152-
{customize_hostname_check, [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]}];
153-
process_sni_opts(#{enabled := true, host := SNIHost, protocol := default}) ->
154-
[{server_name_indication, SNIHost}];
155-
process_sni_opts(#{enabled := true}) ->
156-
[].
157-
158-
error_to_list(_Error) ->
159-
%TODO: implement later if needed
160-
"verify_fun failed".
161-
162-
verify_opt(#{verify_mode := none}) -> verify_none;
163-
verify_opt(#{}) -> verify_peer.
164-
165141
%% accept empty peer certificate if explicitly requested not to fail
166-
fail_if_no_peer_cert_opt(#{disconnect_on_failure := false}) -> false;
167-
fail_if_no_peer_cert_opt(#{verify_mode := peer}) -> true;
168-
fail_if_no_peer_cert_opt(#{verify_mode := selfsigned_peer}) -> true;
169-
fail_if_no_peer_cert_opt(#{}) -> false.
142+
fail_if_no_peer_cert_opts(Opts, #{}, false) ->
143+
[{fail_if_no_peer_cert, false} | Opts];
144+
fail_if_no_peer_cert_opts(Opts, #{disconnect_on_failure := false}, _) ->
145+
[{fail_if_no_peer_cert, false} | Opts];
146+
fail_if_no_peer_cert_opts(Opts, #{verify_mode := Mode}, _)
147+
when Mode =:= peer; Mode =:= selfsigned_peer ->
148+
[{fail_if_no_peer_cert, true} | Opts];
149+
fail_if_no_peer_cert_opts(Opts, #{}, _) ->
150+
[{fail_if_no_peer_cert, false} | Opts].
151+
152+
hibernate_opts(Opts, #{hibernate_after := Timeout}) ->
153+
[{hibernate_after, Timeout} | Opts];
154+
hibernate_opts(Opts, #{}) ->
155+
Opts.
156+
157+
verify_opts(Opts, #{verify_mode := none}) ->
158+
[{verify, verify_none} | Opts];
159+
verify_opts(Opts, #{}) ->
160+
[{verify, verify_peer} | Opts].
161+
162+
sni_opts(Opts, #{server_name_indication := #{enabled := false}}) ->
163+
[{server_name_indication, disable} | Opts];
164+
sni_opts(Opts, #{server_name_indication := #{enabled := true, host := SNIHost, protocol := default}}) ->
165+
[{server_name_indication, SNIHost} | Opts];
166+
sni_opts(Opts, #{server_name_indication := #{enabled := true, host := SNIHost, protocol := https}}) ->
167+
[{server_name_indication, SNIHost},
168+
{customize_hostname_check, [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]} | Opts];
169+
sni_opts(Opts, #{}) ->
170+
Opts.
170171

171172
%% This function translates TLS options to the function
172173
%% which will later be used when TCP socket is upgraded to TLS
@@ -226,8 +227,10 @@ verify_fun(none) ->
226227
send_verification_failure(Pid, Ref, Reason) ->
227228
Pid ! {cert_verification_failure, Ref, Reason}.
228229

229-
receive_verify_results(dummy_ref) -> [];
230-
receive_verify_results(Ref) -> receive_verify_results(Ref, []).
230+
receive_verify_results(dummy_ref) ->
231+
[];
232+
receive_verify_results(Ref) ->
233+
receive_verify_results(Ref, []).
231234

232235
receive_verify_results(Ref, Acc) ->
233236
receive
@@ -236,3 +239,7 @@ receive_verify_results(Ref, Acc) ->
236239
after 0 ->
237240
lists:reverse(Acc)
238241
end.
242+
243+
error_to_list(_Error) ->
244+
%TODO: implement later if needed
245+
"verify_fun failed".

src/mongoose_tls.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
password => string(),
5252
versions => [atom()],
5353
server_name_indication => sni_options(), % client-only
54+
hibernate_after => timeout(),
5455

5556
% only for fast_tls
5657
protocol_options => [string()]}.

0 commit comments

Comments
 (0)