aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorjuhlig <[email protected]>2019-09-17 17:55:25 +0200
committerLoïc Hoguin <[email protected]>2019-10-14 12:38:29 +0200
commitd44e7a16f7d2823cc658e39b5d953ba0850e47ba (patch)
tree72ddf6100e12fa7424067262ee31b1f99ce05fff /src
parent1db8290685e9cff3dfafde62de6148246075990a (diff)
downloadranch-d44e7a16f7d2823cc658e39b5d953ba0850e47ba.tar.gz
ranch-d44e7a16f7d2823cc658e39b5d953ba0850e47ba.tar.bz2
ranch-d44e7a16f7d2823cc658e39b5d953ba0850e47ba.zip
Enable multiple steps handshake
Also fix some Protocol:start_link/4 into start_link/3 left over in the documentation.
Diffstat (limited to 'src')
-rw-r--r--src/ranch.erl74
-rw-r--r--src/ranch_ssl.erl37
-rw-r--r--src/ranch_tcp.erl20
-rw-r--r--src/ranch_transport.erl6
4 files changed, 114 insertions, 23 deletions
diff --git a/src/ranch.erl b/src/ranch.erl
index 08eebfc..89ca21e 100644
--- a/src/ranch.erl
+++ b/src/ranch.erl
@@ -22,6 +22,9 @@
-export([child_spec/5]).
-export([handshake/1]).
-export([handshake/2]).
+-export([handshake_continue/1]).
+-export([handshake_continue/2]).
+-export([handshake_cancel/1]).
-export([recv_proxy_header/2]).
-export([remove_connection/1]).
-export([get_status/1]).
@@ -197,28 +200,61 @@ child_spec(Ref, Transport, TransOpts0, Protocol, ProtoOpts) ->
Ref, Transport, TransOpts, Protocol, ProtoOpts
]}, type => supervisor}.
--spec handshake(ref()) -> {ok, ranch_transport:socket()}.
+-spec handshake(ref()) -> {ok, ranch_transport:socket()} | {continue, any()}.
handshake(Ref) ->
- handshake(Ref, []).
+ handshake1(Ref, undefined).
--spec handshake(ref(), any()) -> {ok, ranch_transport:socket()}.
+-spec handshake(ref(), any()) -> {ok, ranch_transport:socket()} | {continue, any()}.
handshake(Ref, Opts) ->
- receive {handshake, Ref, Transport, CSocket, HandshakeTimeout} ->
- case Transport:handshake(CSocket, Opts, HandshakeTimeout) of
- OK = {ok, _} ->
- OK;
- %% Garbage was most likely sent to the socket, don't error out.
- {error, {tls_alert, _}} ->
- ok = Transport:close(CSocket),
- exit(normal);
- %% Socket most likely stopped responding, don't error out.
- {error, Reason} when Reason =:= timeout; Reason =:= closed ->
- ok = Transport:close(CSocket),
- exit(normal);
- {error, Reason} ->
- ok = Transport:close(CSocket),
- error(Reason)
- end
+ handshake1(Ref, {opts, Opts}).
+
+handshake1(Ref, Opts) ->
+ receive {handshake, Ref, Transport, CSocket, Timeout} ->
+ Handshake = handshake_transport(Transport, handshake, CSocket, Opts, Timeout),
+ handshake_result(Handshake, Ref, Transport, CSocket, Timeout)
+ end.
+
+-spec handshake_continue(ref()) -> {ok, ranch_transport:socket()}.
+handshake_continue(Ref) ->
+ handshake_continue1(Ref, undefined).
+
+-spec handshake_continue(ref(), any()) -> {ok, ranch_transport:socket()}.
+handshake_continue(Ref, Opts) ->
+ handshake_continue1(Ref, {opts, Opts}).
+
+handshake_continue1(Ref, Opts) ->
+ receive {handshake_continue, Ref, Transport, CSocket, Timeout} ->
+ Handshake = handshake_transport(Transport, handshake_continue, CSocket, Opts, Timeout),
+ handshake_result(Handshake, Ref, Transport, CSocket, Timeout)
+ end.
+
+handshake_transport(Transport, Fun, CSocket, undefined, Timeout) ->
+ Transport:Fun(CSocket, Timeout);
+handshake_transport(Transport, Fun, CSocket, {opts, Opts}, Timeout) ->
+ Transport:Fun(CSocket, Opts, Timeout).
+
+handshake_result(Result, Ref, Transport, CSocket, Timeout) ->
+ case Result of
+ OK = {ok, _} ->
+ OK;
+ {ok, CSocket2, Info} ->
+ self() ! {handshake_continue, Ref, Transport, CSocket2, Timeout},
+ {continue, Info};
+ {error, {tls_alert, _}} ->
+ ok = Transport:close(CSocket),
+ exit(normal);
+ {error, Reason} when Reason =:= timeout; Reason =:= closed ->
+ ok = Transport:close(CSocket),
+ exit(normal);
+ {error, Reason} ->
+ ok = Transport:close(CSocket),
+ error(Reason)
+ end.
+
+-spec handshake_cancel(ref()) -> ok.
+handshake_cancel(Ref) ->
+ receive {handshake_continue, Ref, Transport, CSocket, _} ->
+ Transport:handshake_cancel(CSocket)
end.
%% Unlike handshake/2 this function always return errors because
diff --git a/src/ranch_ssl.erl b/src/ranch_ssl.erl
index b6ca50b..b86a35f 100644
--- a/src/ranch_ssl.erl
+++ b/src/ranch_ssl.erl
@@ -21,7 +21,11 @@
-export([listen/1]).
-export([disallowed_listen_options/0]).
-export([accept/2]).
+-export([handshake/2]).
-export([handshake/3]).
+-export([handshake_continue/2]).
+-export([handshake_continue/3]).
+-export([handshake_cancel/1]).
-export([connect/3]).
-export([connect/4]).
-export([recv/3]).
@@ -56,6 +60,7 @@
%% @todo Update when ssl exports named_curve().
| {eccs, [atom()]}
| {fail_if_no_peer_cert, boolean()}
+ | {handshake, hello | full}
| {hibernate_after, timeout()}
| {honor_cipher_order, boolean()}
| {honor_ecc_order, boolean()}
@@ -138,16 +143,42 @@ disallowed_listen_options() ->
accept(LSocket, Timeout) ->
ssl:transport_accept(LSocket, Timeout).
+-spec handshake(inet:socket() | ssl:sslsocket(), timeout())
+ -> {ok, ssl:sslsocket()} | {ok, ssl:sslsocket(), ssl:protocol_extensions()} | {error, any()}.
+handshake(CSocket, Timeout) ->
+ handshake(CSocket, [], Timeout).
+
-spec handshake(inet:socket() | ssl:sslsocket(), opts(), timeout())
- -> {ok, ssl:sslsocket()} | {error, any()}.
+ -> {ok, ssl:sslsocket()} | {ok, ssl:sslsocket(), ssl:protocol_extensions()} | {error, any()}.
handshake(CSocket, Opts, Timeout) ->
case ssl:handshake(CSocket, Opts, Timeout) of
- {ok, NewSocket} ->
- {ok, NewSocket};
+ OK = {ok, _} ->
+ OK;
+ OK = {ok, _, _} ->
+ OK;
+ Error = {error, _} ->
+ Error
+ end.
+
+-spec handshake_continue(ssl:sslsocket(), timeout())
+ -> {ok, ssl:sslsocket()} | {error, any()}.
+handshake_continue(CSocket, Timeout) ->
+ handshake_continue(CSocket, [], Timeout).
+
+-spec handshake_continue(ssl:sslsocket(), [ssl:tls_server_option()], timeout())
+ -> {ok, ssl:sslsocket()} | {error, any()}.
+handshake_continue(CSocket, Opts, Timeout) ->
+ case ssl:handshake_continue(CSocket, Opts, Timeout) of
+ OK = {ok, _} ->
+ OK;
Error = {error, _} ->
Error
end.
+-spec handshake_cancel(ssl:sslsocket()) -> ok.
+handshake_cancel(CSocket) ->
+ ok = ssl:handshake_cancel(CSocket).
+
%% @todo Probably filter Opts?
-spec connect(inet:ip_address() | inet:hostname(),
inet:port_number(), any())
diff --git a/src/ranch_tcp.erl b/src/ranch_tcp.erl
index 3b4e4c3..0d8da2e 100644
--- a/src/ranch_tcp.erl
+++ b/src/ranch_tcp.erl
@@ -21,7 +21,11 @@
-export([listen/1]).
-export([disallowed_listen_options/0]).
-export([accept/2]).
+-export([handshake/2]).
-export([handshake/3]).
+-export([handshake_continue/2]).
+-export([handshake_continue/3]).
+-export([handshake_cancel/1]).
-export([connect/3]).
-export([connect/4]).
-export([recv/3]).
@@ -105,10 +109,26 @@ disallowed_listen_options() ->
accept(LSocket, Timeout) ->
gen_tcp:accept(LSocket, Timeout).
+-spec handshake(inet:socket(), timeout()) -> {ok, inet:socket()}.
+handshake(CSocket, Timeout) ->
+ handshake(CSocket, [], Timeout).
+
-spec handshake(inet:socket(), opts(), timeout()) -> {ok, inet:socket()}.
handshake(CSocket, _, _) ->
{ok, CSocket}.
+-spec handshake_continue(inet:socket(), timeout()) -> no_return().
+handshake_continue(CSocket, Timeout) ->
+ handshake_continue(CSocket, [], Timeout).
+
+-spec handshake_continue(inet:socket(), opts(), timeout()) -> no_return().
+handshake_continue(_, _, _) ->
+ error(not_supported).
+
+-spec handshake_cancel(inet:socket()) -> no_return().
+handshake_cancel(_) ->
+ error(not_supported).
+
%% @todo Probably filter Opts?
-spec connect(inet:ip_address() | inet:hostname(),
inet:port_number(), any())
diff --git a/src/ranch_transport.erl b/src/ranch_transport.erl
index 6790977..5fd6242 100644
--- a/src/ranch_transport.erl
+++ b/src/ranch_transport.erl
@@ -30,7 +30,11 @@
-callback listen(ranch:transport_opts(any())) -> {ok, socket()} | {error, atom()}.
-callback accept(socket(), timeout())
-> {ok, socket()} | {error, closed | timeout | atom()}.
--callback handshake(socket(), opts(), timeout()) -> {ok, socket()} | {error, any()}.
+-callback handshake(socket(), timeout()) -> {ok, socket()} | {ok, socket(), any()} | {error, any()}.
+-callback handshake(socket(), opts(), timeout()) -> {ok, socket()} | {ok, socket(), any()} | {error, any()}.
+-callback handshake_continue(socket(), timeout()) -> {ok, socket()} | {error, any()}.
+-callback handshake_continue(socket(), opts(), timeout()) -> {ok, socket()} | {error, any()}.
+-callback handshake_cancel(socket()) -> ok.
-callback connect(string(), inet:port_number(), opts())
-> {ok, socket()} | {error, atom()}.
-callback connect(string(), inet:port_number(), opts(), timeout())