diff options
Diffstat (limited to 'docs/en/ranch/2.2/guide/protocols.asciidoc')
-rw-r--r-- | docs/en/ranch/2.2/guide/protocols.asciidoc | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/docs/en/ranch/2.2/guide/protocols.asciidoc b/docs/en/ranch/2.2/guide/protocols.asciidoc new file mode 100644 index 00000000..8f55cea2 --- /dev/null +++ b/docs/en/ranch/2.2/guide/protocols.asciidoc @@ -0,0 +1,113 @@ +== Protocols + +A protocol handler starts a connection process and defines the +protocol logic executed in this process. + +=== Writing a protocol handler + +All protocol handlers must implement the `ranch_protocol` behavior +which defines a single callback, `start_link/3`. This callback is +responsible for spawning a new process for handling the connection. +It receives three arguments: the name of the listener, the +transport handler being used and the protocol options defined in +the call to `ranch:start_listener/5`. This callback must +return `{ok, Pid}`, with `Pid` the pid of the new process. + +The newly started process can then freely initialize itself. However, +it must call `ranch:handshake/1,2` before doing any socket operation. +This will ensure the connection process is the owner of the socket. +It expects the listener's name as argument. + +.Perform the socket handshake + +[source,erlang] +{ok, Socket} = ranch:handshake(Ref). + +If your protocol code requires specific socket options, you should +set them while initializing your connection process, after +calling `ranch:handshake/1,2`. You can use `Transport:setopts/2` +for that purpose. + +Following is the complete protocol code for the example found +in `examples/tcp_echo/`. + +.Protocol module that echoes everything it receives + +[source,erlang] +---- +-module(echo_protocol). +-behaviour(ranch_protocol). + +-export([start_link/3]). +-export([init/3]). + +start_link(Ref, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), + {ok, Pid}. + +init(Ref, Transport, _Opts = []) -> + {ok, Socket} = ranch:handshake(Ref), + loop(Socket, Transport). + +loop(Socket, Transport) -> + case Transport:recv(Socket, 0, 5000) of + {ok, Data} -> + Transport:send(Socket, Data), + loop(Socket, Transport); + _ -> + ok = Transport:close(Socket) + end. +---- + +=== 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 +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. + +This problem can be addressed in several ways. + +==== 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] +---- +-module(my_protocol). +-behaviour(gen_statem). +-behaviour(ranch_protocol). + +-export([start_link/3]). +-export([init/1]). +%% Exports of other gen_statem callbacks here. + +start_link(Ref, Transport, Opts) -> + {ok, proc_lib:spawn_link(?MODULE, 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}]), + gen_statem:enter_loop(?MODULE, [], state_name, {state_data, Socket, Transport}). + +%% Other gen_statem callbacks here. +---- + +==== 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`. |