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:
 
 * 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 protocol handler and its associated options.
 
@@ -43,8 +42,8 @@ to the `echo_protocol` handler.
 
 [source,erlang]
 {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
@@ -142,8 +141,8 @@ argument is the name of the listener you gave in `ranch:start_listener/5`.
 
 [source,erlang]
 {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).
 
@@ -238,8 +237,8 @@ overloaded and ensuring all the connections are handled optimally.
 
 [source,erlang]
 {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`.
@@ -248,8 +247,8 @@ You can disable this limit by setting its value to the atom `infinity`.
 
 [source,erlang]
 {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
@@ -305,8 +304,8 @@ measure to find the best value for your application.
 
 [source,erlang]
 {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
@@ -325,8 +324,8 @@ processes.
 
 [source,erlang]
 {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

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

@@ -59,7 +59,7 @@ loop(Socket, Transport) ->
 	end.
 ----
 
-=== Using gen_statem
+=== Using gen_statem and 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
@@ -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
 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]
 ----
@@ -87,7 +96,7 @@ the normal `gen_statem` execution loop.
 start_link(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.
 	{ok, Socket} = ranch:handshake(Ref),
 	ok = Transport:setopts(Socket, [{active, once}]),
@@ -96,4 +105,9 @@ init({Ref, Transport, _Opts = []}) ->
 %% 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]
 {ok, _} = ranch:start_listener(my_ssl,
-	ranch_ssl, [
+	ranch_ssl, #{socket_opts => [
 		{port, SSLPort},
 		{certfile, PathToCertfile},
 		{cacertfile, PathToCACertfile},
 		{verify, verify_peer}
-	],
+	]},
 	my_protocol, []
 ).
 

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

@@ -74,11 +74,6 @@ opts() = any() | transport_opts(any())
 
 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()
 
 [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
 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
 are documented in the link:man:ranch_tcp(3)[ranch_tcp(3)]
 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.
 
-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
 
 .Get the current transport options

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

@@ -16,28 +16,29 @@
 
 -define(TIMEOUT, 60000).
 
--record(state, {socket, transport}).
+-record(state, {ref, transport, socket}).
 
 %% API.
 
 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.
 
 callback_mode() ->
-	state_functions.
+	[state_functions, state_enter].
 
 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 = 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{
 		socket=Socket, transport=Transport})
-		when byte_size(Data) > 1 ->
+		when byte_size(Data) >= 1 ->
 	Transport:setopts(Socket, [{active, once}]),
 	Transport:send(Socket, reverse_binary(Data)),
 	{keep_state_and_data, ?TIMEOUT};
@@ -57,7 +58,7 @@ connected(_EventType, _Msg, _StateData) ->
 
 terminate(Reason, StateName, StateData=#state{
 		socket=Socket, transport=Transport})
-		when Socket=/=undefined andalso Transport=/=undefined ->
+		when Socket=/=undefined, Transport=/=undefined ->
 	catch Transport:close(Socket),
 	terminate(Reason, StateName,
 		StateData#state{socket=undefined, transport=undefined});
@@ -69,7 +70,18 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
 
 %% 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.