Browse Source

Update docs and modernize examples

* Use the map form for transport options everywhere
* Remove mentions of the list form for transport options
* Use a state enter call instead of gen_statem:enter_loop/4 and
  proc_lib:start_link/3 in the tcp_reverse example
* Take care of different EOLs in the tcp_reverse example
* Mention state enter calls, the next_event action, and {continue, ...}
  in the docs for how to use gen_statem and gen_server
Jan Uhlig 3 years ago
parent
commit
581b6954d3

+ 12 - 13
doc/src/guide/listeners.asciidoc

@@ -19,7 +19,6 @@ A listener can be started and stopped at will.
 When starting a listener, a number of different settings are required:
 When starting a listener, a number of different settings are required:
 
 
 * A name to identify it locally and be able to interact with it.
 * A name to identify it locally and be able to interact with it.
-* The number of acceptors in the pool.
 * A transport handler and its associated options.
 * A transport handler and its associated options.
 * A protocol handler and its associated options.
 * A protocol handler and its associated options.
 
 
@@ -43,8 +42,8 @@ to the `echo_protocol` handler.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, [{port, 5555}],
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 5555}]},
+    echo_protocol, []
 ).
 ).
 
 
 You can try this out by compiling and running the `tcp_echo` example in the
 You can try this out by compiling and running the `tcp_echo` example in the
@@ -142,8 +141,8 @@ argument is the name of the listener you gave in `ranch:start_listener/5`.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, [{port, 0}],
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 0}]},
+    echo_protocol, []
 ).
 ).
 Port = ranch:get_port(tcp_echo).
 Port = ranch:get_port(tcp_echo).
 
 
@@ -238,8 +237,8 @@ overloaded and ensuring all the connections are handled optimally.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => 100},
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => 100},
+    echo_protocol, []
 ).
 ).
 
 
 You can disable this limit by setting its value to the atom `infinity`.
 You can disable this limit by setting its value to the atom `infinity`.
@@ -248,8 +247,8 @@ You can disable this limit by setting its value to the atom `infinity`.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => infinity},
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 5555}], max_connections => infinity},
+    echo_protocol, []
 ).
 ).
 
 
 The maximum number of connections is a soft limit. In practice, it
 The maximum number of connections is a soft limit. In practice, it
@@ -305,8 +304,8 @@ measure to find the best value for your application.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, [{port, 5555}, {num_acceptors, 42}],
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 5555}], num_acceptors => 42},
+    echo_protocol, []
 ).
 ).
 
 
 === Customizing the number of connection supervisors
 === Customizing the number of connection supervisors
@@ -325,8 +324,8 @@ processes.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(tcp_echo,
 {ok, _} = ranch:start_listener(tcp_echo,
-	ranch_tcp, #{socket_opts => [{port, 5555}], num_conns_sups => 42}],
-	echo_protocol, []
+    ranch_tcp, #{socket_opts => [{port, 5555}], num_conns_sups => 42},
+    echo_protocol, []
 ).
 ).
 
 
 === When running out of file descriptors
 === When running out of file descriptors

+ 22 - 8
doc/src/guide/protocols.asciidoc

@@ -59,7 +59,7 @@ loop(Socket, Transport) ->
 	end.
 	end.
 ----
 ----
 
 
-=== Using gen_statem
+=== Using gen_statem and gen_server
 
 
 Special processes like the ones that use the `gen_statem` or `gen_server`
 Special processes like the ones that use the `gen_statem` or `gen_server`
 behaviours have the particularity of having their `start_link` call not
 behaviours have the particularity of having their `start_link` call not
@@ -67,12 +67,21 @@ return until the `init` function returns. This is problematic, because
 you won't be able to call `ranch:handshake/1,2` from the `init` callback
 you won't be able to call `ranch:handshake/1,2` from the `init` callback
 as this would cause a deadlock to happen.
 as this would cause a deadlock to happen.
 
 
-Use the `gen_statem:enter_loop/4` function. It allows you to start your process
-normally (although it must be started with `proc_lib` like all special
-processes), then perform any needed operations before falling back into
-the normal `gen_statem` execution loop.
+This problem can be addressed in several ways.
 
 
-.Use a gen_statem for protocol handling
+==== gen_statem
+
+* Use state enter calls and place the `ranch:handshake/1,2` call in the enter
+  clause of the initial state. Check the `tcp_reverse` example for a complete
+  example.
+* Use a `next_event` action in the return from `init/1` and place the
+  `ranch:handshake/1,2` call in the clause handling the event in the initial
+  state.
+* Use the `gen_statem:enter_loop/4` function and start your process with
+  `proc_lib:spawn_link/3` or `proc_lib:start_link/3,4,5`. See below for an
+  example.
+
+.Using gen_statem:enter_loop/4 to start a protocol
 
 
 [source,erlang]
 [source,erlang]
 ----
 ----
@@ -87,7 +96,7 @@ the normal `gen_statem` execution loop.
 start_link(Ref, Transport, Opts) ->
 start_link(Ref, Transport, Opts) ->
 	{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Transport, Opts}])}.
 	{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Transport, Opts}])}.
 
 
-init({Ref, Transport, _Opts = []}) ->
+init({Ref, Transport, _Opts}) ->
 	%% Perform any required state initialization here.
 	%% Perform any required state initialization here.
 	{ok, Socket} = ranch:handshake(Ref),
 	{ok, Socket} = ranch:handshake(Ref),
 	ok = Transport:setopts(Socket, [{active, once}]),
 	ok = Transport:setopts(Socket, [{active, once}]),
@@ -96,4 +105,9 @@ init({Ref, Transport, _Opts = []}) ->
 %% Other gen_statem callbacks here.
 %% Other gen_statem callbacks here.
 ----
 ----
 
 
-Check the `tcp_reverse` example for a complete example.
+==== gen_server
+
+* Use `{continue, Continue}` in the return from `init/1` and place the
+  `ranch:handshake/1,2` call in a corresponding `handle_continue/2` clause.
+* Use the `gen_server:enter_loop/3` function and start your process with
+  `proc_lib:spawn_link/3` or `proc_lib:start_link/3,4,5`.

+ 2 - 2
doc/src/guide/ssl_auth.asciidoc

@@ -50,12 +50,12 @@ the listener to enable this behavior.
 
 
 [source,erlang]
 [source,erlang]
 {ok, _} = ranch:start_listener(my_ssl,
 {ok, _} = ranch:start_listener(my_ssl,
-	ranch_ssl, [
+	ranch_ssl, #{socket_opts => [
 		{port, SSLPort},
 		{port, SSLPort},
 		{certfile, PathToCertfile},
 		{certfile, PathToCertfile},
 		{cacertfile, PathToCACertfile},
 		{cacertfile, PathToCACertfile},
 		{verify, verify_peer}
 		{verify, verify_peer}
-	],
+	]},
 	my_protocol, []
 	my_protocol, []
 ).
 ).
 
 

+ 0 - 5
doc/src/manual/ranch.asciidoc

@@ -74,11 +74,6 @@ opts() = any() | transport_opts(any())
 
 
 Transport or socket options.
 Transport or socket options.
 
 
-It is possible to give the full transport options in a map
-(see `transport_opts(SocketOpts)`), or only the socket options
-(assuming they are not a map and no Ranch-specific option
-needs to be given).
-
 === ref()
 === ref()
 
 
 [source,erlang]
 [source,erlang]

+ 0 - 3
doc/src/manual/ranch.child_spec.asciidoc

@@ -49,9 +49,6 @@ Transport options include the Ranch-specific options
 and the socket options. The listener's port number must
 and the socket options. The listener's port number must
 be defined in the socket options.
 be defined in the socket options.
 +
 +
-Socket options may be given directly if there are no
-Ranch-specific options.
-+
 The available options for the built-in Ranch transports
 The available options for the built-in Ranch transports
 are documented in the link:man:ranch_tcp(3)[ranch_tcp(3)]
 are documented in the link:man:ranch_tcp(3)[ranch_tcp(3)]
 and link:man:ranch_ssl(3)[ranch_ssl(3)] manuals.
 and link:man:ranch_ssl(3)[ranch_ssl(3)] manuals.

+ 0 - 5
doc/src/manual/ranch.get_transport_options.asciidoc

@@ -24,11 +24,6 @@ The listener name.
 
 
 The current transport options are returned.
 The current transport options are returned.
 
 
-If the transport options were specified as only socket options (not a map) using
-link:man:ranch:start_listener(3)[ranch:start_listener(3)] or
-link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], they
-are returned as `#{socket_opts => SocketOpts}`.
-
 == Examples
 == Examples
 
 
 .Get the current transport options
 .Get the current transport options

+ 25 - 13
examples/tcp_reverse/src/reverse_protocol.erl

@@ -16,28 +16,29 @@
 
 
 -define(TIMEOUT, 60000).
 -define(TIMEOUT, 60000).
 
 
--record(state, {socket, transport}).
+-record(state, {ref, transport, socket}).
 
 
 %% API.
 %% API.
 
 
 start_link(Ref, Transport, Opts) ->
 start_link(Ref, Transport, Opts) ->
-	{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Transport, Opts}])}.
+	gen_statem:start_link(?MODULE, {Ref, Transport, Opts}, []).
 
 
 %% gen_statem.
 %% gen_statem.
 
 
 callback_mode() ->
 callback_mode() ->
-	state_functions.
+	[state_functions, state_enter].
 
 
 init({Ref, Transport, _Opts = []}) ->
 init({Ref, Transport, _Opts = []}) ->
+	{ok, connected, #state{ref=Ref, transport=Transport}, ?TIMEOUT}.
+
+connected(enter, connected, StateData=#state{
+		ref=Ref, transport=Transport}) ->
 	{ok, Socket} = ranch:handshake(Ref),
 	{ok, Socket} = ranch:handshake(Ref),
 	ok = Transport:setopts(Socket, [{active, once}, {packet, line}]),
 	ok = Transport:setopts(Socket, [{active, once}, {packet, line}]),
-	gen_statem:enter_loop(?MODULE, [], connected,
-		#state{socket=Socket, transport=Transport},
-		[?TIMEOUT]).
-
+	{keep_state, StateData#state{socket=Socket}};
 connected(info, {tcp, Socket, Data}, _StateData=#state{
 connected(info, {tcp, Socket, Data}, _StateData=#state{
 		socket=Socket, transport=Transport})
 		socket=Socket, transport=Transport})
-		when byte_size(Data) > 1 ->
+		when byte_size(Data) >= 1 ->
 	Transport:setopts(Socket, [{active, once}]),
 	Transport:setopts(Socket, [{active, once}]),
 	Transport:send(Socket, reverse_binary(Data)),
 	Transport:send(Socket, reverse_binary(Data)),
 	{keep_state_and_data, ?TIMEOUT};
 	{keep_state_and_data, ?TIMEOUT};
@@ -57,7 +58,7 @@ connected(_EventType, _Msg, _StateData) ->
 
 
 terminate(Reason, StateName, StateData=#state{
 terminate(Reason, StateName, StateData=#state{
 		socket=Socket, transport=Transport})
 		socket=Socket, transport=Transport})
-		when Socket=/=undefined andalso Transport=/=undefined ->
+		when Socket=/=undefined, Transport=/=undefined ->
 	catch Transport:close(Socket),
 	catch Transport:close(Socket),
 	terminate(Reason, StateName,
 	terminate(Reason, StateName,
 		StateData#state{socket=undefined, transport=undefined});
 		StateData#state{socket=undefined, transport=undefined});
@@ -69,7 +70,18 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
 
 
 %% Internal.
 %% Internal.
 
 
-reverse_binary(B) when is_binary(B) ->
-	[list_to_binary(lists:reverse(binary_to_list(
-		binary:part(B, {0, byte_size(B)-2})
-	))), "\r\n"].
+reverse_binary(B0) when is_binary(B0) ->
+	Size = bit_size(B0),
+	<<B1:Size/integer-little>> = B0,
+	case <<B1:Size/integer-big>> of
+		%% Take care of different possible line terminators.
+		<<$\n, $\r, B2/binary>> ->
+			%% CR/LF (Windows)
+			<<B2/binary, $\r, $\n>>;
+		<<$\n, B2/binary>> ->
+			%% LF (Linux, Mac OS X and later)
+			<<B2/binary, $\n>>;
+		<<$\r, B2/binary>> ->
+			%% CR (Mac Classic, ie prior to Mac OS X)
+			<<B2/binary, $\r>>
+	end.