aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2015-08-22 13:15:08 +0200
committerLoïc Hoguin <[email protected]>2015-08-22 13:15:08 +0200
commitf4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42 (patch)
tree5f73255bbd51d46fccf371ff7cdd67c6bea8e7b7 /doc
parentd30408b2e8c14c0e56ce997f5aff0010c03cef0b (diff)
downloadranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.tar.gz
ranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.tar.bz2
ranch-f4c6da56d4fe9494f4fe23c48b8d7c3c1e9e6b42.zip
Convert the documentation to Asciidoc
Diffstat (limited to 'doc')
-rw-r--r--doc/src/guide/book.asciidoc20
-rw-r--r--doc/src/guide/embedded.asciidoc48
-rw-r--r--doc/src/guide/internals.asciidoc94
-rw-r--r--doc/src/guide/introduction.asciidoc25
-rw-r--r--doc/src/guide/listeners.asciidoc251
-rw-r--r--doc/src/guide/parsers.asciidoc92
-rw-r--r--doc/src/guide/protocols.asciidoc125
-rw-r--r--doc/src/guide/ssl_auth.asciidoc120
-rw-r--r--doc/src/guide/transports.asciidoc169
-rw-r--r--doc/src/manual/ranch.asciidoc170
-rw-r--r--doc/src/manual/ranch_app.asciidoc27
-rw-r--r--doc/src/manual/ranch_protocol.asciidoc44
-rw-r--r--doc/src/manual/ranch_ssl.asciidoc142
-rw-r--r--doc/src/manual/ranch_tcp.asciidoc123
-rw-r--r--doc/src/manual/ranch_transport.asciidoc194
15 files changed, 1644 insertions, 0 deletions
diff --git a/doc/src/guide/book.asciidoc b/doc/src/guide/book.asciidoc
new file mode 100644
index 0000000..59e8e70
--- /dev/null
+++ b/doc/src/guide/book.asciidoc
@@ -0,0 +1,20 @@
+// a2x: --dblatex-opts "-P latex.output.revhistory=0 -P doc.publisher.show=0 -P index.numbered=0"
+// a2x: -d book --attribute tabsize=4
+
+= Ranch User Guide
+
+include::introduction.asciidoc[Introduction]
+
+include::listeners.asciidoc[Listeners]
+
+include::transports.asciidoc[Transports]
+
+include::protocols.asciidoc[Protocols]
+
+include::embedded.asciidoc[Embedded mode]
+
+include::parsers.asciidoc[Writing parsers]
+
+include::ssl_auth.asciidoc[SSL client authentication]
+
+include::internals.asciidoc[Internals]
diff --git a/doc/src/guide/embedded.asciidoc b/doc/src/guide/embedded.asciidoc
new file mode 100644
index 0000000..593a807
--- /dev/null
+++ b/doc/src/guide/embedded.asciidoc
@@ -0,0 +1,48 @@
+== Embedded mode
+
+Embedded mode allows you to insert Ranch listeners directly
+in your supervision tree. This allows for greater fault tolerance
+control by permitting the shutdown of a listener due to the
+failure of another part of the application and vice versa.
+
+=== Embedding
+
+To embed Ranch in your application you can simply add the child specs
+to your supervision tree. This can all be done in the `init/1` function
+of one of your application supervisors.
+
+Ranch requires at the minimum two kinds of child specs for embedding.
+First, you need to add `ranch_sup` to your supervision tree, only once,
+regardless of the number of listeners you will use. Then you need to
+add the child specs for each listener.
+
+Ranch has a convenience function for getting the listeners child specs
+called `ranch:child_spec/6`, that works like `ranch:start_listener/6`,
+except that it doesn't start anything, it only returns child specs.
+
+As for `ranch_sup`, the child spec is simple enough to not require a
+convenience function.
+
+The following example adds both `ranch_sup` and one listener to another
+application's supervision tree.
+
+.Embed Ranch directly in your supervision tree
+
+[source,erlang]
+----
+init([]) ->
+ RanchSupSpec = {ranch_sup, {ranch_sup, start_link, []},
+ permanent, 5000, supervisor, [ranch_sup]},
+ ListenerSpec = ranch:child_spec(echo, 100,
+ ranch_tcp, [{port, 5555}],
+ echo_protocol, []
+ ),
+ {ok, {{one_for_one, 10, 10}, [RanchSupSpec, ListenerSpec]}}.
+----
+
+Remember, you can add as many listener child specs as needed, but only
+one `ranch_sup` spec!
+
+It is recommended that your architecture makes sure that all listeners
+are restarted if `ranch_sup` fails. See the Ranch internals chapter for
+more details on how Ranch does it.
diff --git a/doc/src/guide/internals.asciidoc b/doc/src/guide/internals.asciidoc
new file mode 100644
index 0000000..fa63f1d
--- /dev/null
+++ b/doc/src/guide/internals.asciidoc
@@ -0,0 +1,94 @@
+== Internals
+
+This chapter may not apply to embedded Ranch as embedding allows you
+to use an architecture specific to your application, which may or may
+not be compatible with the description of the Ranch application.
+
+Note that for everything related to efficiency and performance,
+you should perform the benchmarks yourself to get the numbers that
+matter to you. Generic benchmarks found on the web may or may not
+be of use to you, you can never know until you benchmark your own
+system.
+
+=== Architecture
+
+Ranch is an OTP application.
+
+Like all OTP applications, Ranch has a top supervisor. It is responsible
+for supervising the `ranch_server` process and all the listeners that
+will be started.
+
+The `ranch_server` gen_server is a central process keeping track of the
+listeners and their acceptors. It does so through the use of a public ets
+table called `ranch_server`. The table is owned by the top supervisor
+to improve fault tolerance. This way if the `ranch_server` gen_server
+fails, it doesn't lose any information and the restarted process can
+continue as if nothing happened.
+
+Ranch uses a custom supervisor for managing connections. This supervisor
+keeps track of the number of connections and handles connection limits
+directly. While it is heavily optimized to perform the task of creating
+connection processes for accepted connections, it is still following the
+OTP principles and the usual `sys` and `supervisor` calls will work on
+it as expected.
+
+Listeners are grouped into the `ranch_listener_sup` supervisor and
+consist of three kinds of processes: the listener gen_server, the
+acceptor processes and the connection processes, both grouped under
+their own supervisor. All of these processes are registered to the
+`ranch_server` gen_server with varying amount of information.
+
+All socket operations, including listening for connections, go through
+transport handlers. Accepted connections are given to the protocol handler.
+Transport handlers are simple callback modules for performing operations on
+sockets. Protocol handlers start a new process, which receives socket
+ownership, with no requirements on how the code should be written inside
+that new process.
+
+=== Number of acceptors
+
+The second argument to `ranch:start_listener/6` is the number of
+processes that will be accepting connections. Care should be taken
+when choosing this number.
+
+First of all, it should not be confused with the maximum number
+of connections. Acceptor processes are only used for accepting and
+have nothing else in common with connection processes. Therefore
+there is nothing to be gained from setting this number too high,
+in fact it can slow everything else down.
+
+Second, this number should be high enough to allow Ranch to accept
+connections concurrently. But the number of cores available doesn't
+seem to be the only factor for choosing this number, as we can
+observe faster accepts if we have more acceptors than cores. It
+might be entirely dependent on the protocol, however.
+
+Our observations suggest that using 100 acceptors on modern hardware
+is a good solution, as it's big enough to always have acceptors ready
+and it's low enough that it doesn't have a negative impact on the
+system's performances.
+
+=== Platform-specific TCP features
+
+Some socket options are platform-specific and not supported by `inet`.
+They can be of interest because they generally are related to
+optimizations provided by the underlying OS. They can still be enabled
+thanks to the `raw` option, for which we will see an example.
+
+One of these features is `TCP_DEFER_ACCEPT` on Linux. It is a simplified
+accept mechanism which will wait for application data to come in before
+handing out the connection to the Erlang process.
+
+This is especially useful if you expect many connections to be mostly
+idle, perhaps part of a connection pool. They can be handled by the
+kernel directly until they send any real data, instead of allocating
+resources to idle connections.
+
+To enable this mechanism, the following option can be used.
+
+.Using raw transport options
+
+[source,erlang]
+{raw, 6, 9, << 30:32/native >>}
+
+It means go on layer 6, turn on option 9 with the given integer parameter.
diff --git a/doc/src/guide/introduction.asciidoc b/doc/src/guide/introduction.asciidoc
new file mode 100644
index 0000000..3199fb2
--- /dev/null
+++ b/doc/src/guide/introduction.asciidoc
@@ -0,0 +1,25 @@
+== Introduction
+
+Ranch is a socket acceptor pool for TCP protocols.
+
+Ranch aims to provide everything you need to accept TCP connections
+with a small code base and low latency while being easy to use directly
+as an application or to embed into your own.
+
+=== Prerequisites
+
+It is assumed the developer already knows Erlang and has some experience
+with socket programming and TCP protocols.
+
+=== Supported platforms
+
+Ranch is tested and supported on Linux.
+
+Ranch is developed for Erlang R15B01+.
+
+Ranch may be compiled on earlier Erlang versions with small source code
+modifications but there is no guarantee that it will work as expected.
+
+=== Versioning
+
+Ranch uses http://semver.org/[Semantic Versioning 2.0.0]
diff --git a/doc/src/guide/listeners.asciidoc b/doc/src/guide/listeners.asciidoc
new file mode 100644
index 0000000..ef2d49c
--- /dev/null
+++ b/doc/src/guide/listeners.asciidoc
@@ -0,0 +1,251 @@
+== Listeners
+
+A listener is a set of processes whose role is to listen on a port
+for new connections. It manages a pool of acceptor processes, each
+of them indefinitely accepting connections. When it does, it starts
+a new process executing the protocol handler code. All the socket
+programming is abstracted through the user of transport handlers.
+
+The listener takes care of supervising all the acceptor and connection
+processes, allowing developers to focus on building their application.
+
+=== Starting a listener
+
+Ranch does nothing by default. It is up to the application developer
+to request that Ranch listens for connections.
+
+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.
+
+Ranch includes both TCP and SSL transport handlers, respectively
+`ranch_tcp` and `ranch_ssl`.
+
+A listener can be started by calling the `ranch:start_listener/6`
+function. Before doing so however, you must ensure that the `ranch`
+application is started.
+
+.Starting the Ranch application
+
+[source,erlang]
+ok = application:start(ranch).
+
+You are then ready to start a listener. Let's call it `tcp_echo`. It will
+have a pool of 100 acceptors, use a TCP transport and forward connections
+to the `echo_protocol` handler.
+
+.Starting a listener for TCP connections on port 5555
+
+[source,erlang]
+{ok, _} = ranch:start_listener(tcp_echo, 100,
+ ranch_tcp, [{port, 5555}],
+ echo_protocol, []
+).
+
+You can try this out by compiling and running the `tcp_echo` example in the
+examples directory. To do so, open a shell in the 'examples/tcp_echo/'
+directory and run the following command:
+
+.Building and starting a Ranch example
+
+[source,bash]
+$ make run
+
+You can then connect to it using telnet and see the echo server reply
+everything you send to it. Then when you're done testing, you can use
+the `Ctrl+]` key to escape to the telnet command line and type
+`quit` to exit.
+
+.Connecting to the example listener with telnet
+
+[source,bash]
+----
+$ telnet localhost 5555
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+Hello!
+Hello!
+It works!
+It works!
+^]
+
+telnet> quit
+Connection closed.
+----
+
+=== Stopping a listener
+
+All you need to stop a Ranch listener is to call the
+`ranch:stop_listener/1` function with the listener's name
+as argument. In the previous section we started the listener
+named `tcp_echo`. We can now stop it.
+
+.Stopping a listener
+
+[source,erlang]
+ranch:stop_listener(tcp_echo).
+
+=== Default transport options
+
+By default the socket will be set to return `binary` data, with the
+options `{active, false}`, `{packet, raw}`, `{reuseaddr, true}` set.
+These values can't be overriden when starting the listener, but
+they can be overriden using `Transport:setopts/2` in the protocol.
+
+It will also set `{backlog, 1024}` and `{nodelay, true}`, which
+can be overriden at listener startup.
+
+=== Listening on a random port
+
+You do not have to specify a specific port to listen on. If you give
+the port number 0, or if you omit the port number entirely, Ranch will
+start listening on a random port.
+
+You can retrieve this port number by calling `ranch:get_port/1`. The
+argument is the name of the listener you gave in `ranch:start_listener/6`.
+
+.Starting a listener for TCP connections on a random port
+
+[source,erlang]
+{ok, _} = ranch:start_listener(tcp_echo, 100,
+ ranch_tcp, [{port, 0}],
+ echo_protocol, []
+).
+Port = ranch:get_port(tcp_echo).
+
+=== Listening on privileged ports
+
+Some systems limit access to ports below 1024 for security reasons.
+This can easily be identified by an `{error, eacces}` error when trying
+to open a listening socket on such a port.
+
+The methods for listening on privileged ports vary between systems,
+please refer to your system's documentation for more information.
+
+We recommend the use of port rewriting for systems with a single server,
+and load balancing for systems with multiple servers. Documenting these
+solutions is however out of the scope of this guide.
+
+=== Accepting connections on an existing socket
+
+If you want to accept connections on an existing socket, you can use the
+`socket` transport option, which should just be the relevant data returned
+from the connect function for the transport or the underlying socket library
+(`gen_tcp:connect`, `ssl:connect`). The accept function will then be
+called on the passed in socket. You should connect the socket in
+`{active, false}` mode, as well.
+
+Note, however, that because of a bug in SSL, you cannot change ownership of an
+SSL listen socket prior to R16. Ranch will catch the error thrown, but the
+owner of the SSL socket will remain as whatever process created the socket.
+However, this will not affect accept behaviour unless the owner process dies,
+in which case the socket is closed. Therefore, to use this feature with SSL
+with an erlang release prior to R16, ensure that the SSL socket is opened in a
+persistant process.
+
+=== Limiting the number of concurrent connections
+
+The `max_connections` transport option allows you to limit the number
+of concurrent connections. It defaults to 1024. Its purpose is to
+prevent your system from being overloaded and ensuring all the
+connections are handled optimally.
+
+.Customizing the maximum number of concurrent connections
+
+[source,erlang]
+{ok, _} = ranch:start_listener(tcp_echo, 100,
+ ranch_tcp, [{port, 5555}, {max_connections, 100}],
+ echo_protocol, []
+).
+
+You can disable this limit by setting its value to the atom `infinity`.
+
+.Disabling the limit for the number of connections
+
+[source,erlang]
+{ok, _} = ranch:start_listener(tcp_echo, 100,
+ ranch_tcp, [{port, 5555}, {max_connections, infinity}],
+ echo_protocol, []
+).
+
+You may not always want connections to be counted when checking for
+`max_connections`. For example you might have a protocol where both
+short-lived and long-lived connections are possible. If the long-lived
+connections are mostly waiting for messages, then they don't consume
+much resources and can safely be removed from the count.
+
+To remove the connection from the count, you must call the
+`ranch:remove_connection/1` from within the connection process,
+with the name of the listener as the only argument.
+
+.Removing a connection from the count of connections
+
+[source,erlang]
+ranch:remove_connection(Ref).
+
+As seen in the chapter covering protocols, this pid is received as the
+first argument of the protocol's `start_link/4` callback.
+
+You can modify the `max_connections` value on a running listener by
+using the `ranch:set_max_connections/2` function, with the name of the
+listener as first argument and the new value as the second.
+
+.Upgrading the maximum number of connections
+
+[source,erlang]
+ranch:set_max_connections(tcp_echo, MaxConns).
+
+The change will occur immediately.
+
+=== Using a supervisor for connection processes
+
+Ranch allows you to define the type of process that will be used
+for the connection processes. By default it expects a `worker`.
+When the `connection_type` configuration value is set to `supervisor`,
+Ranch will consider that the connection process it manages is a
+supervisor and will reflect that in its supervision tree.
+
+Connection processes of type `supervisor` can either handle the
+socket directly or through one of their children. In the latter
+case the start function for the connection process must return
+two pids: the pid of the supervisor you created (that will be
+supervised) and the pid of the protocol handling process (that
+will receive the socket).
+
+Instead of returning `{ok, ConnPid}`, simply return
+`{ok, SupPid, ConnPid}`.
+
+It is very important that the connection process be created
+under the supervisor process so that everything works as intended.
+If not, you will most likely experience issues when the supervised
+process is stopped.
+
+=== Upgrading
+
+Ranch allows you to upgrade the protocol options. This takes effect
+immediately and for all subsequent connections.
+
+To upgrade the protocol options, call `ranch:set_protocol_options/2`
+with the name of the listener as first argument and the new options
+as the second.
+
+.Upgrading the protocol options
+
+[source,erlang]
+ranch:set_protocol_options(tcp_echo, NewOpts).
+
+All future connections will use the new options.
+
+You can also retrieve the current options similarly by
+calling `ranch:get_protocol_options/1`.
+
+.Retrieving the current protocol options
+
+[source,erlang]
+Opts = ranch:get_protocol_options(tcp_echo).
diff --git a/doc/src/guide/parsers.asciidoc b/doc/src/guide/parsers.asciidoc
new file mode 100644
index 0000000..9eacbfa
--- /dev/null
+++ b/doc/src/guide/parsers.asciidoc
@@ -0,0 +1,92 @@
+== Writing parsers
+
+There are three kinds of protocols:
+
+* Text protocols
+* Schema-less binary protocols
+* Schema-based binary protocols
+
+This chapter introduces the first two kinds. It will not cover
+more advanced topics such as continuations or parser generators.
+
+This chapter isn't specifically about Ranch, we assume here that
+you know how to read data from the socket. The data you read and
+the data that hasn't been parsed is saved in a buffer. Every
+time you read from the socket, the data read is appended to the
+buffer. What happens next depends on the kind of protocol. We
+will only cover the first two.
+
+=== Parsing text
+
+Text protocols are generally line based. This means that we can't
+do anything with them until we receive the full line.
+
+A simple way to get a full line is to use `binary:split/{2,3}`.
+
+.Using binary:split/2 to get a line of input
+
+[source,erlang]
+case binary:split(Buffer, <<"\n">>) of
+ [_] ->
+ get_more_data(Buffer);
+ [Line, Rest] ->
+ handle_line(Line, Rest)
+end.
+
+In the above example, we can have two results. Either there was
+a line break in the buffer and we get it split into two parts,
+the line and the rest of the buffer; or there was no line break
+in the buffer and we need to get more data from the socket.
+
+Next, we need to parse the line. The simplest way is to again
+split, here on space. The difference is that we want to split
+on all spaces character, as we want to tokenize the whole string.
+
+.Using binary:split/3 to split text
+
+[source,erlang]
+case binary:split(Line, <<" ">>, [global]) of
+ [<<"HELLO">>] ->
+ be_polite();
+ [<<"AUTH">>, User, Password] ->
+ authenticate_user(User, Password);
+ [<<"QUIT">>, Reason] ->
+ quit(Reason)
+ %% ...
+end.
+
+Pretty simple, right? Match on the command name, get the rest
+of the tokens in variables and call the respective functions.
+
+After doing this, you will want to check if there is another
+line in the buffer, and handle it immediately if any.
+Otherwise wait for more data.
+
+=== Parsing binary
+
+Binary protocols can be more varied, although most of them are
+pretty similar. The first four bytes of a frame tend to be
+the size of the frame, which is followed by a certain number
+of bytes for the type of frame and then various parameters.
+
+Sometimes the size of the frame includes the first four bytes,
+sometimes not. Other times this size is encoded over two bytes.
+And even other times little-endian is used instead of big-endian.
+
+The general idea stays the same though.
+
+.Using binary pattern matching to split frames
+
+[source,erlang]
+<< Size:32, _/bits >> = Buffer,
+case Buffer of
+ << Frame:Size/binary, Rest/bits >> ->
+ handle_frame(Frame, Rest);
+ _ ->
+ get_more_data(Buffer)
+end.
+
+You will then need to parse this frame using binary pattern
+matching, and handle it. Then you will want to check if there
+is another frame fully received in the buffer, and handle it
+immediately if any. Otherwise wait for more data.
diff --git a/doc/src/guide/protocols.asciidoc b/doc/src/guide/protocols.asciidoc
new file mode 100644
index 0000000..8060343
--- /dev/null
+++ b/doc/src/guide/protocols.asciidoc
@@ -0,0 +1,125 @@
+== 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/4`. This callback is
+responsible for spawning a new process for handling the connection.
+It receives four arguments: the name of the listener, the socket, the
+transport handler being used and the protocol options defined in
+the call to `ranch:start_listener/6`. 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:accept_ack/1` 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.
+
+.Acknowledge accepting the socket
+
+[source,erlang]
+ok = ranch:accept_ack(Ref).
+
+If your protocol code requires specific socket options, you should
+set them while initializing your connection process, after
+calling `ranch:accept_ack/1`. 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/4]).
+-export([init/4]).
+
+start_link(Ref, Socket, Transport, Opts) ->
+ Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
+ {ok, Pid}.
+
+init(Ref, Socket, Transport, _Opts = []) ->
+ ok = ranch:accept_ack(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_server
+
+Special processes like the ones that use the `gen_server` or `gen_fsm`
+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:accept_ack/1` from the `init` callback
+as this would cause a deadlock to happen.
+
+There are two ways of solving this problem.
+
+The first, and probably the most elegant one, is to make use of the
+`gen_server:enter_loop/3` 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_server` execution loop.
+
+.Use a gen_server for protocol handling
+
+[source,erlang]
+----
+-module(my_protocol).
+-behaviour(gen_server).
+-behaviour(ranch_protocol).
+
+-export([start_link/4]).
+-export([init/4]).
+%% Exports of other gen_server callbacks here.
+
+start_link(Ref, Socket, Transport, Opts) ->
+ proc_lib:start_link(?MODULE, init, [Ref, Socket, Transport, Opts]).
+
+init(Ref, Socket, Transport, _Opts = []) ->
+ ok = proc_lib:init_ack({ok, self()}),
+ %% Perform any required state initialization here.
+ ok = ranch:accept_ack(Ref),
+ ok = Transport:setopts(Socket, [{active, once}]),
+ gen_server:enter_loop(?MODULE, [], {state, Socket, Transport}).
+
+%% Other gen_server callbacks here.
+----
+
+The second method involves triggering a timeout just after `gen_server:init`
+ends. If you return a timeout value of `0` then the `gen_server` will call
+`handle_info(timeout, _, _)` right away.
+
+.Use a gen_server for protocol handling, method 2
+
+[source,erlang]
+----
+-module(my_protocol).
+-behaviour(gen_server).
+-behaviour(ranch_protocol).
+
+%% Exports go here.
+
+init([Ref, Socket, Transport]) ->
+ {ok, {state, Ref, Socket, Transport}, 0}.
+
+handle_info(timeout, State={state, Ref, Socket, Transport}) ->
+ ok = ranch:accept_ack(Ref),
+ ok = Transport:setopts(Socket, [{active, once}]),
+ {noreply, State};
+%% ...
+----
diff --git a/doc/src/guide/ssl_auth.asciidoc b/doc/src/guide/ssl_auth.asciidoc
new file mode 100644
index 0000000..39f9c3c
--- /dev/null
+++ b/doc/src/guide/ssl_auth.asciidoc
@@ -0,0 +1,120 @@
+== SSL client authentication
+
+=== Purpose
+
+SSL client authentication is a mechanism allowing applications to
+identify certificates. This allows your application to make sure that
+the client is an authorized certificate, but makes no claim about
+whether the user can be trusted. This can be combined with a password
+based authentication to attain greater security.
+
+The server only needs to retain the certificate serial number and
+the certificate issuer to authenticate the certificate. Together,
+they can be used to uniquely identify a certicate.
+
+As Ranch allows the same protocol code to be used for both SSL and
+non-SSL transports, you need to make sure you are in an SSL context
+before attempting to perform an SSL client authentication. This
+can be done by checking the return value of `Transport:name/0`.
+
+=== Obtaining client certificates
+
+You can obtain client certificates from various sources. You can
+generate them yourself, or you can use a service like CAcert.org
+which allows you to generate client and server certificates for
+free.
+
+Following are the steps you need to take to create a CAcert.org
+account, generate a certificate and install it in your favorite
+browser.
+
+* Open [CAcert.org](http://cacert.org) in your favorite browser
+* Root Certificate link: install both certificates
+* Join (Register an account)
+* Verify your account (check your email inbox!)
+* Log in
+* Client Certificates: New
+* Follow instructions to create the certificate
+* Install the certificate in your browser
+
+You can optionally save the certificate for later use, for example
+to extract the `IssuerID` information as will be detailed later on.
+
+=== Transport configuration
+
+The SSL transport does not request a client certificate by default.
+You need to specify the `{verify, verify_peer}` option when starting
+the listener to enable this behavior.
+
+.Configure a listener for SSL authentication
+
+[source,erlang]
+{ok, _} = ranch:start_listener(my_ssl, 100,
+ ranch_ssl, [
+ {port, SSLPort},
+ {certfile, PathToCertfile},
+ {cacertfile, PathToCACertfile},
+ {verify, verify_peer}
+ ],
+ my_protocol, []
+).
+
+In this example we set the required `port` and `certfile`, but also
+the `cacertfile` containing the CACert.org root certificate, and
+the option to request the client certificate.
+
+If you enable the `{verify, verify_peer}` option and the client does
+not have a client certificate configured for your domain, then no
+certificate will be sent. This allows you to use SSL for more than
+just authenticated clients.
+
+=== Authentication
+
+To authenticate users, you must first save the certificate information
+required. If you have your users' certificate files, you can simply
+load the certificate and retrieve the information directly.
+
+.Retrieve the issuer ID from a certificate
+
+[source,erlang]
+----
+certfile_to_issuer_id(Filename) ->
+ {ok, Data} = file:read_file(Filename),
+ [{'Certificate', Cert, not_encrypted}] = public_key:pem_decode(Data),
+ {ok, IssuerID} = public_key:pkix_issuer_id(Cert, self),
+ IssuerID.
+----
+
+The `IssuerID` variable contains both the certificate serial number
+and the certificate issuer stored in a tuple, so this value alone can
+be used to uniquely identify the user certificate. You can save this
+value in a database, a configuration file or any other place where an
+Erlang term can be stored and retrieved.
+
+To retrieve the `IssuerID` from a running connection, you need to first
+retrieve the client certificate and then extract this information from
+it. Ranch does not provide a function to retrieve the client certificate.
+Instead you can use the `ssl:peercert/1` function. Once you have the
+certificate, you can again use the `public_key:pkix_issuer_id/2` to
+extract the `IssuerID` value.
+
+The following function returns the `IssuerID` or `false` if no client
+certificate was found. This snippet is intended to be used from your
+protocol code.
+
+.Retrieve the issuer ID from the certificate for the current connection
+
+[source,erlang]
+----
+socket_to_issuer_id(Socket) ->
+ case ssl:peercert(Socket) of
+ {error, no_peercert} ->
+ false;
+ {ok, Cert} ->
+ {ok, IssuerID} = public_key:pkix_issuer_id(Cert, self),
+ IssuerID
+ end.
+----
+
+You then only need to match the `IssuerID` value to authenticate the
+user.
diff --git a/doc/src/guide/transports.asciidoc b/doc/src/guide/transports.asciidoc
new file mode 100644
index 0000000..9195376
--- /dev/null
+++ b/doc/src/guide/transports.asciidoc
@@ -0,0 +1,169 @@
+== Transports
+
+A transport defines the interface to interact with a socket.
+
+Transports can be used for connecting, listening and accepting
+connections, but also for receiving and sending data. Both
+passive and active mode are supported, although all sockets
+are initialized as passive.
+
+=== TCP transport
+
+The TCP transport is a thin wrapper around `gen_tcp`.
+
+=== SSL transport
+
+The SSL transport is a thin wrapper around `ssl`. It requires
+the `crypto`, `asn1`, `public_key` and `ssl` applications
+to be started. When starting an SSL listener, Ranch will attempt
+to automatically start them. It will not try to stop them when
+the listener is removed, however.
+
+.Starting the SSL application
+
+[source,erlang]
+ssl:start().
+
+In a proper OTP setting, you will need to make your application
+depend on the `crypto`, `public_key` and `ssl` applications.
+They will be started automatically when starting your release.
+
+The SSL transport `accept/2` function performs both transport
+and SSL accepts. Errors occurring during the SSL accept phase
+are returned as `{error, {ssl_accept, atom()}}` to differentiate
+on which socket the problem occurred.
+
+=== Sending and receiving data
+
+This section assumes that `Transport` is a valid transport handler
+(like `ranch_tcp` or `ranch_ssl`) and `Socket` is a connected
+socket obtained through the listener.
+
+You can send data to a socket by calling the `Transport:send/2`
+function. The data can be given as `iodata()`, which is defined as
+`binary() | iolist()`. All the following calls will work:
+
+.Sending data to the socket
+
+[source,erlang]
+----
+Transport:send(Socket, <<"Ranch is cool!">>).
+Transport:send(Socket, "Ranch is cool!").
+Transport:send(Socket, ["Ranch", ["is", "cool!"]]).
+Transport:send(Socket, ["Ranch", [<<"is">>, "cool!"]]).
+----
+
+You can receive data either in passive or in active mode. Passive mode
+means that you will perform a blocking `Transport:recv/3` call, while
+active mode means that you will receive the data as a message.
+
+By default, all data will be received as binary. It is possible to
+receive data as strings, although this is not recommended as binaries
+are a more efficient construct, especially for binary protocols.
+
+Receiving data using passive mode requires a single function call. The
+first argument is the socket, and the third argument is a timeout duration
+before the call returns with `{error, timeout}`.
+
+The second argument is the amount of data in bytes that we want to receive.
+The function will wait for data until it has received exactly this amount.
+If you are not expecting a precise size, you can specify 0 which will make
+this call return as soon as data was read, regardless of its size.
+
+.Receiving data from the socket in passive mode
+
+[source,erlang]
+{ok, Data} = Transport:recv(Socket, 0, 5000).
+
+Active mode requires you to inform the socket that you want to receive
+data as a message and to write the code to actually receive it.
+
+There are two kinds of active modes: `{active, once}` and
+`{active, true}`. The first will send a single message before going
+back to passive mode; the second will send messages indefinitely.
+We recommend not using the `{active, true}` mode as it could quickly
+flood your process mailbox. It's better to keep the data in the socket
+and read it only when required.
+
+Three different messages can be received:
+
+* `{OK, Socket, Data}`
+* `{Closed, Socket}`
+* `{Error, Socket, Reason}`
+
+The value of `OK`, `Closed` and `Error` can be different
+depending on the transport being used. To be able to properly match
+on them you must first call the `Transport:messages/0` function.
+
+.Retrieving the transport's active message identifiers
+
+[source,erlang]
+{OK, Closed, Error} = Transport:messages().
+
+To start receiving messages you will need to call the `Transport:setopts/2`
+function, and do so every time you want to receive data.
+
+.Receiving messages from the socket in active mode
+
+[source,erlang]
+----
+{OK, Closed, Error} = Transport:messages(),
+Transport:setopts(Socket, [{active, once}]),
+receive
+ {OK, Socket, Data} ->
+ io:format("data received: ~p~n", [Data]);
+ {Closed, Socket} ->
+ io:format("socket got closed!~n");
+ {Error, Socket, Reason} ->
+ io:format("error happened: ~p~n", [Reason])
+end.
+----
+
+You can easily integrate active sockets with existing Erlang code as all
+you really need is just a few more clauses when receiving messages.
+
+=== Sending files
+
+As in the previous section it is assumed `Transport` is a valid transport
+handler and `Socket` is a connected socket obtained through the listener.
+
+To send a whole file, with name `Filename`, over a socket:
+
+.Sending a file by filename
+
+[source,erlang]
+{ok, SentBytes} = Transport:sendfile(Socket, Filename).
+
+Or part of a file, with `Offset` greater than or equal to 0, `Bytes` number of
+bytes and chunks of size `ChunkSize`:
+
+.Sending part of a file by filename in chunks
+
+[source,erlang]
+Opts = [{chunk_size, ChunkSize}],
+{ok, SentBytes} = Transport:sendfile(Socket, Filename, Offset, Bytes, Opts).
+
+To improve efficiency when sending multiple parts of the same file it is also
+possible to use a file descriptor opened in raw mode:
+
+.Sending a file opened in raw mode
+
+[source,erlang]
+{ok, RawFile} = file:open(Filename, [raw, read, binary]),
+{ok, SentBytes} = Transport:sendfile(Socket, RawFile, Offset, Bytes, Opts).
+
+=== Writing a transport handler
+
+A transport handler is a module implementing the `ranch_transport` behavior.
+It defines a certain number of callbacks that must be written in order to
+allow transparent usage of the transport handler.
+
+The behavior doesn't define the socket options available when opening a
+socket. These do not need to be common to all transports as it's easy enough
+to write different initialization functions for the different transports that
+will be used. With one exception though. The `setopts/2` function *must*
+implement the `{active, once}` and the `{active, true}` options.
+
+If the transport handler doesn't have a native implementation of `sendfile/5` a
+fallback is available, `ranch_transport:sendfile/6`. The extra first argument
+is the transport's module. See `ranch_ssl` for an example.
diff --git a/doc/src/manual/ranch.asciidoc b/doc/src/manual/ranch.asciidoc
new file mode 100644
index 0000000..f2e8a7d
--- /dev/null
+++ b/doc/src/manual/ranch.asciidoc
@@ -0,0 +1,170 @@
+= ranch(3)
+
+== Name
+
+ranch - socket acceptor pool
+
+== Description
+
+The `ranch` module provides functions for starting and
+manipulating Ranch listeners.
+
+== Types
+
+=== max_conns() = non_neg_integer() | infinity
+
+Maximum number of connections allowed on this listener.
+
+This is a soft limit. The actual number of connections
+might be slightly above the limit due to concurrency
+when accepting new connections. Some connections may
+also be removed from this count explicitly by the user
+code.
+
+=== opt()
+
+[source,erlang]
+----
+opt() = {ack_timeout, timeout()}
+ | {connection_type, worker | supervisor}
+ | {max_connections, max_conns()}
+ | {shutdown, timeout() | brutal_kill}
+ | {socket, any()}
+----
+
+Ranch-specific transport options.
+
+These options are not passed on to the transports.
+They are used by Ranch while setting up the listeners.
+
+=== ref() = any()
+
+Unique name used to refer to a listener.
+
+== Option descriptions
+
+None of the options are required.
+
+ack_timeout (5000)::
+ Maximum allowed time for the `ranch:accept_ack/1` call to finish.
+connection_type (worker)::
+ Type of process that will handle the connection.
+max_connections (1024)::
+ Maximum number of active connections. Soft limit. Using `infinity` will disable the limit entirely.
+shutdown (5000)::
+ Maximum allowed time for children to stop on listener shutdown.
+socket::
+ Listening socket opened externally to be used instead of calling `Transport:listen/1`.
+
+== Exports
+
+=== accept_ack(Ref) -> ok
+
+Ref = ref():: Listener name.
+
+Acknowledge that the connection is accepted.
+
+This function MUST be used by a connection process to inform
+Ranch that it initialized properly and let it perform any
+additional operations before the socket can be safely used.
+
+=== child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> supervisor:child_spec()
+
+Ref = ref():: Listener name.
+NbAcceptors = non_neg_integer():: Number of acceptor processes.
+Transport = module():: Transport module.
+TransOpts = any():: Transport options.
+Protocol = module():: Protocol module.
+ProtoOpts = any():: Protocol options.
+
+Return child specifications for a new listener.
+
+This function can be used to embed a listener directly
+in an application instead of letting Ranch handle it.
+
+=== get_max_connections(Ref) -> MaxConns
+
+Ref = ref():: Listener name.
+MaxConns = max_conns():: Current maximum number of connections.
+
+Return the max number of connections allowed for the given listener.
+
+=== get_port(Ref) -> Port
+
+Ref = ref():: Listener name.
+Port = inet:port_number():: Port number used by this listener.
+
+Return the port for the given listener.
+
+=== get_protocol_options(Ref) -> ProtoOpts
+
+Ref = ref():: Listener name.
+ProtoOpts = any():: Current protocol options.
+
+Return the protocol options set for the given listener.
+
+=== remove_connection(Ref) -> ok
+
+Ref = ref():: Listener name.
+
+Do not count this connection when limiting the number of connections.
+
+You can use this function for long-running connection processes
+which spend most of their time idling rather than consuming
+resources. This allows Ranch to accept a lot more connections
+without sacrificing the latency of the system.
+
+This function may only be called from a connection process.
+
+=== set_max_connections(Ref, MaxConns) -> ok
+
+Ref = ref():: Listener name.
+MaxConns = max_conns():: New maximum number of connections.
+
+Set the max number of connections for the given listener.
+
+The change will be applied immediately. If the new value is
+smaller than the previous one, Ranch will not kill the extra
+connections, but will wait for them to terminate properly.
+
+=== set_protocol_options(Ref, ProtoOpts) -> ok
+
+Ref = ref():: Listener name.
+ProtoOpts = any():: New protocol options.
+
+Set the protocol options for the given listener.
+
+The change will be applied immediately for all new connections.
+Old connections will not receive the new options.
+
+=== start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> {ok, pid()} | {error, badarg}
+
+Ref = ref():: Listener name.
+NbAcceptors = non_neg_integer():: Number of acceptor processes.
+Transport = module():: Transport module.
+TransOpts = any():: Transport options.
+Protocol = module():: Protocol module.
+ProtoOpts = any():: Protocol options.
+
+Start listening for connections using the given transport
+and protocol. Returns the pid for this listener's supervisor.
+
+There are additional transport options that apply
+regardless of transport. They allow configuring how the
+connections are supervised, rate limited and more. Please
+consult the previous section for more details.
+
+=== stop_listener(Ref) -> ok | {error, not_found}
+
+Ref = ref():: Listener name.
+
+Stop the given listener.
+
+The listener is stopped gracefully, first by closing the
+listening port, then by stopping the connection processes.
+These processes are stopped according to the `shutdown`
+transport option, which may be set to brutally kill all
+connection processes or give them some time to stop properly.
+
+This function does not return until the listener is
+completely stopped.
diff --git a/doc/src/manual/ranch_app.asciidoc b/doc/src/manual/ranch_app.asciidoc
new file mode 100644
index 0000000..2edfc72
--- /dev/null
+++ b/doc/src/manual/ranch_app.asciidoc
@@ -0,0 +1,27 @@
+= ranch(7)
+
+== Name
+
+ranch - Socket acceptor pool for TCP protocols.
+
+== Dependencies
+
+The `ranch` application has no particular dependency required
+to start.
+
+It has optional dependencies that are only required when
+listening for SSL connections. The dependencies are `crypto`,
+`asn1`, `public_key` and `ssl`. They are started automatically
+if they weren't before.
+
+== Environment
+
+The `ranch` application defines one application environment
+configuration parameter.
+
+profile (false)::
+ When enabled, Ranch will start `eprof` profiling automatically.
+
+You can use the `ranch_app:profile_output/0` function to stop
+profiling and output the results to the files 'procs.profile'
+and 'total.profile'. Do not use in production.
diff --git a/doc/src/manual/ranch_protocol.asciidoc b/doc/src/manual/ranch_protocol.asciidoc
new file mode 100644
index 0000000..714a82b
--- /dev/null
+++ b/doc/src/manual/ranch_protocol.asciidoc
@@ -0,0 +1,44 @@
+= ranch_protocol(3)
+
+== Name
+
+ranch_protocol - behaviour for protocol modules
+
+== Description
+
+The `ranch_protocol` behaviour defines the interface used
+by Ranch protocols.
+
+== Types
+
+None.
+
+== Callbacks
+
+=== start_link(Ref, Socket, Transport, ProtoOpts) -> {ok, pid()} | {ok, pid(), pid()}
+
+Ref = ranch:ref():: Listener name.
+Socket = any():: Socket for this connection.
+Transport = module():: Transport module for this socket.
+ProtoOpts = any():: Protocol options.
+
+Start a new connection process for the given socket.
+
+The only purpose of this callback is to start a process that
+will handle the socket. It must spawn the process, link and
+then return the new pid. This function will always be called
+from inside a supervisor.
+
+This callback can also return two pids. The first pid is the
+pid of the process that will be supervised. The second pid is
+the pid of the process that will receive ownership of the
+socket. This second process must be a child of the first. This
+form is only available when `connection_type` is set to
+`supervisor`.
+
+If any other value is returned, the supervisor will close the
+socket and assume no process has been started.
+
+Do not perform any operations in this callback, as this would
+block the supervisor responsible for starting connection
+processes and degrade performance severely.
diff --git a/doc/src/manual/ranch_ssl.asciidoc b/doc/src/manual/ranch_ssl.asciidoc
new file mode 100644
index 0000000..55accad
--- /dev/null
+++ b/doc/src/manual/ranch_ssl.asciidoc
@@ -0,0 +1,142 @@
+= ranch_ssl(3)
+
+== Name
+
+ranch_ssl - SSL transport module
+
+== Description
+
+The `ranch_ssl` module implements an SSL Ranch transport.
+
+== Types
+
+=== ssl_opt()
+
+[source,erlang]
+----
+ssl_opt() = {alpn_preferred_protocols, [binary()]}
+ | {cacertfile, string()}
+ | {cacerts, [public_key:der_encoded()]}
+ | {cert, public_key:der_encoded()}
+ | {certfile, string()}
+ | {ciphers, [ssl:erl_cipher_suite()] | string()}
+ | {client_renegotiation, boolean()}
+ | {crl_cache, {module(), {internal | any(), list()}}}
+ | {crl_check, boolean() | peer | best_effort}
+ | {depth, 0..255}
+ | {dh, public_key:der_encoded()}
+ | {dhfile, string()}
+ | {fail_if_no_peer_cert, boolean()}
+ | {hibernate_after, integer() | undefined}
+ | {honor_cipher_order, boolean()}
+ | {key, {'RSAPrivateKey' | 'DSAPrivateKey' | 'PrivateKeyInfo', public_key:der_encoded()}}
+ | {keyfile, string()}
+ | {log_alert, boolean()}
+ | {next_protocols_advertised, [binary()]}
+ | {partial_chain, fun(([public_key:der_encoded()]) -> {trusted_ca, public_key:der_encoded()} | unknown_ca)}
+ | {password, string()}
+ | {psk_identity, string()}
+ | {reuse_session, fun()}
+ | {reuse_sessions, boolean()}
+ | {secure_renegotiate, boolean()}
+ | {sni_fun, fun()}
+ | {sni_hosts, [{string(), ssl_opt()}]}
+ | {user_lookup_fun, {fun(), any()}}
+ | {verify, ssl:verify_type()}
+ | {verify_fun, {fun(), any()}}
+ | {versions, [atom()]}.
+----
+
+SSL-specific listen options.
+
+=== opt() = ranch_tcp:opt() | ssl_opt()
+
+Listen options.
+
+=== opts() = [opt()]
+
+List of listen options.
+
+== Option descriptions
+
+Specifying a certificate is mandatory, either through the `cert`
+or the `certfile` option. None of the other options are required.
+
+The default value is given next to the option name.
+
+alpn_preferred_protocols::
+ Perform Application-Layer Protocol Negotiation with the given list of preferred protocols.
+cacertfile::
+ Path to PEM encoded trusted certificates file used to verify peer certificates.
+cacerts::
+ List of DER encoded trusted certificates.
+cert::
+ DER encoded user certificate.
+certfile::
+ Path to the PEM encoded user certificate file. May also contain the private key.
+ciphers::
+ List of ciphers that clients are allowed to use.
+client_renegotiation (true)::
+ Whether to allow client-initiated renegotiation.
+crl_cache ({ssl_crl_cache, {internal, []}})::
+ Customize the module used to cache Certificate Revocation Lists.
+crl_check (false)::
+ Whether to perform CRL check on all certificates in the chain during validation.
+depth (1)::
+ Maximum of intermediate certificates allowed in the certification path.
+dh::
+ DER encoded Diffie-Hellman parameters.
+dhfile::
+ Path to the PEM encoded Diffie-Hellman parameters file.
+fail_if_no_peer_cert (false)::
+ Whether to refuse the connection if the client sends an empty certificate.
+hibernate_after (undefined)::
+ Time in ms after which SSL socket processes go into hibernation to reduce memory usage.
+honor_cipher_order (false)::
+ If true, use the server's preference for cipher selection. If false, use the client's preference.
+key::
+ DER encoded user private key.
+keyfile::
+ Path to the PEM encoded private key file, if different than the certfile.
+log_alert (true)::
+ If false, error reports will not be displayed.
+next_protocols_advertised::
+ List of protocols to send to the client if it supports the Next Protocol extension.
+nodelay (true)::
+ Whether to enable TCP_NODELAY.
+partial_chain::
+ Claim an intermediate CA in the chain as trusted.
+password::
+ Password to the private key file, if password protected.
+psk_identity::
+ Provide the given PSK identity hint to the client during the handshake.
+reuse_session::
+ Custom policy to decide whether a session should be reused.
+reuse_sessions (false)::
+ Whether to allow session reuse.
+secure_renegotiate (false)::
+ Whether to reject renegotiation attempts that do not conform to RFC5746.
+sni_fun::
+ Function called when the client requests a host using Server Name Indication. Returns options to apply.
+sni_hosts::
+ Options to apply for the host that matches what the client requested with Server Name Indication.
+user_lookup_fun::
+ Function called to determine the shared secret when using PSK, or provide parameters when using SRP.
+verify (verify_none)::
+ Use `verify_peer` to request a certificate from the client.
+verify_fun::
+ Custom policy to decide whether a client certificate is valid.
+versions::
+ TLS protocol versions that will be supported.
+
+Note that the client will not send a certificate unless the
+value for the `verify` option is set to `verify_peer`. This
+means that the `fail_if_no_peer_cert` only apply when combined
+with the `verify` option. The `verify_fun` option allows
+greater control over the client certificate validation.
+
+The options `sni_fun` and `sni_hosts` are mutually exclusive.
+
+== Exports
+
+None.
diff --git a/doc/src/manual/ranch_tcp.asciidoc b/doc/src/manual/ranch_tcp.asciidoc
new file mode 100644
index 0000000..1fc268d
--- /dev/null
+++ b/doc/src/manual/ranch_tcp.asciidoc
@@ -0,0 +1,123 @@
+= ranch_tcp(3)
+
+== Name
+
+ranch_tcp - TCP transport module
+
+== Description
+
+The `ranch_tcp` module implements a TCP Ranch transport.
+
+Note that due to bugs in OTP up to at least R16B02, it is
+recommended to disable async threads when using the
+`sendfile` function of this transport, as it can make
+the threads stuck indefinitely.
+
+== Types
+
+=== opt()
+
+[source,erlang]
+----
+opt() = {backlog, non_neg_integer()}
+ | {buffer, non_neg_integer()}
+ | {delay_send, boolean()}
+ | {dontroute, boolean()}
+ | {exit_on_close, boolean()}
+ | {fd, non_neg_integer()}
+ | {high_msgq_watermark, non_neg_integer()}
+ | {high_watermark, non_neg_integer()}
+ | inet
+ | inet6
+ | {ip, inet:ip_address()}
+ | {keepalive, boolean()}
+ | {linger, {boolean(), non_neg_integer()}}
+ | {low_msgq_watermark, non_neg_integer()}
+ | {low_watermark, non_neg_integer()}
+ | {nodelay, boolean()}
+ | {port, inet:port_number()}
+ | {priority, integer()}
+ | {raw, non_neg_integer(), non_neg_integer(), binary()}
+ | {recbuf, non_neg_integer()}
+ | {send_timeout, timeout()}
+ | {send_timeout_close, boolean()}
+ | {sndbuf, non_neg_integer()}
+ | {tos, integer()}
+----
+
+Listen options.
+
+This does not represent the entirety of the options that can
+be set on the socket, but only the options that may be
+set independently of protocol implementation.
+
+=== opts() = [opt()]
+
+List of listen options.
+
+Option descriptions
+-------------------
+
+None of the options are required.
+
+Please consult the `gen_tcp` and `inet` manuals for a more
+thorough description of these options. This manual only aims
+to provide a short description along with what the defaults
+are. Defaults may be different in Ranch compared to `gen_tcp`.
+Defaults are given next to the option name.
+
+backlog (1024)::
+ Max length of the queue of pending connections.
+buffer::
+ Size of the buffer used by the Erlang driver. Default is system-dependent.
+delay_send (false)::
+ Always queue packets before sending, to send fewer, larger packets over the network.
+dontroute (false)::
+ Don't send via a gateway, only send to directly connected hosts.
+exit_on_close (true)::
+ Disable to allow sending data after a close has been detected.
+fd::
+ File descriptor of the socket, if it was opened externally.
+high_msgq_watermark (8192)::
+ Limit in the amount of data in the socket message queue before the socket queue becomes busy.
+high_watermark (8192)::
+ Limit in the amount of data in the ERTS socket implementation's queue before the socket becomes busy.
+inet::
+ Set up the socket for IPv4.
+inet6::
+ Set up the socket for IPv6.
+ip::
+ Interface to listen on. Listen on all interfaces by default.
+keepalive (false)::
+ Enable sending of keep-alive messages.
+linger ({false, 0})::
+ Whether to wait and how long to flush data sent before closing the socket.
+low_msgq_watermark (4096)::
+ Amount of data in the socket message queue before the socket queue leaves busy state.
+low_watermark (4096)::
+ Amount of data in the ERTS socket implementation's queue before the socket leaves busy state.
+nodelay (true)::
+ Whether to enable TCP_NODELAY.
+port (0)::
+ TCP port number to listen on. 0 means a random port will be used.
+priority (0)::
+ Priority value for all packets to be sent by this socket.
+recbuf::
+ Minimum size of the socket's receive buffer. Default is system-dependent.
+send_timeout (30000)::
+ How long the send call may wait for confirmation before returning.
+send_timeout_close (true)::
+ Whether to close the socket when the confirmation wasn't received.
+sndbuf::
+ Minimum size of the socket's send buffer. Default is system-dependent.
+tos::
+ Value for the IP_TOS IP level option. Use with caution.
+
+In addition, the `raw` option can be used to set system-specific
+options by specifying the protocol level, the option number and
+the actual option value specified as a binary. This option is not
+portable. Use with caution.
+
+== Exports
+
+None.
diff --git a/doc/src/manual/ranch_transport.asciidoc b/doc/src/manual/ranch_transport.asciidoc
new file mode 100644
index 0000000..a9322f4
--- /dev/null
+++ b/doc/src/manual/ranch_transport.asciidoc
@@ -0,0 +1,194 @@
+= ranch_transport(3)
+
+== Name
+
+ranch_transport - behaviour for transport modules
+
+== Description
+
+The `ranch_transport` behaviour defines the interface used
+by Ranch transports.
+
+== Types
+
+=== sendfile_opts() = [{chunk_size, non_neg_integer()}]
+
+Options used by the sendfile function and callbacks.
+
+Allows configuring the chunk size, in bytes. Defaults to 8191 bytes.
+
+== Callbacks
+
+=== accept(LSocket, Timeout) -> {ok, CSocket} | {error, closed | timeout | atom()}
+
+LSocket = CSocket = any():: Listening socket.
+Timeout = timeout():: Accept timeout.
+
+Accept a connection on the given listening socket.
+
+The `accept_ack` callback will be used to initialize the socket
+after accepting the connection. This is most useful when the
+transport is not raw TCP, like with SSL for example.
+
+=== accept_ack(CSocket, Timeout) -> ok
+
+CSocket = any():: Socket for this connection.
+Timeout = timeout():: Ack timeout.
+
+Perform post-accept initialization of the connection.
+
+This function will be called by connection processes
+before performing any socket operation. It allows
+transports that require extra initialization to perform
+their task and make the socket ready to use.
+
+=== close(Socket) -> ok
+
+Socket = any():: Socket opened with listen/1 or accept/2.
+
+Close the given socket.
+
+=== controlling_process(Socket, Pid) -> ok | {error, closed | not_owner | atom()}
+
+Socket = any():: Socket opened with listen/1 or accept/2.
+Pid = pid():: Pid of the new owner of the socket.
+
+Change the controlling process for the given socket.
+
+The controlling process is the process that is allowed to
+perform operations on the socket, and that will receive
+messages from the socket when active mode is used. When
+the controlling process dies, the socket is closed.
+
+=== listen(TransOpts) -> {ok, LSocket} | {error, atom()}
+
+TransOpts = any():: Transport options.
+LSocket = any():: Listening socket.
+
+Listen for connections on the given port.
+
+The port is given as part of the transport options under
+the key `port`. Any other option is transport dependent.
+
+The socket returned by this call can then be used to
+accept connections. It is not possible to send or receive
+data from the listening socket.
+
+=== messages() -> {OK, Closed, Error}
+
+OK = Closed = Error = atom():: Tuple names.
+
+Return the atoms used to identify messages sent in active mode.
+
+=== name() -> Name
+
+Name = atom():: Transport module name.
+
+Return the name of the transport.
+
+=== peername(CSocket) -> {ok, {IP, Port}} | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+IP = inet:ip_address():: IP of the remote endpoint.
+Port = inet:port_number():: Port of the remote endpoint.
+
+Return the IP and port of the remote endpoint.
+
+=== recv(CSocket, Length, Timeout) -> {ok, Packet} | {error, closed | timeout | atom()}
+
+CSocket = any():: Socket for this connection.
+Length = non_neg_integer():: Requested length.
+Timeout = timeout():: Receive timeout.
+Packet = iodata() | any():: Data received.
+
+Receive data from the given socket when in passive mode.
+
+Trying to receive data from a socket that is in active mode
+will return an error.
+
+A length of 0 will return any data available on the socket.
+
+While it is possible to use the timeout value `infinity`,
+this is highly discouraged as this could cause your process
+to get stuck waiting for data that will never come. This may
+happen when a socket becomes half-open due to a crash of the
+remote endpoint. Wi-Fi going down is another common culprit
+of this issue.
+
+=== send(CSocket, Packet) -> ok | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+Packet = iodata():: Data to be sent.
+
+Send data to the given socket.
+
+=== sendfile(CSocket, File) -> sendfile(CSocket, File, 0, 0, [])
+
+Alias of `ranch_transport:sendfile/5`.
+
+=== sendfile(CSocket, File, Offset, Bytes) -> sendfile(CSocket, File, Offset, Bytes, [])
+
+Alias of `ranch_transport:sendfile/5`.
+
+=== sendfile(CSocket, File, Offset, Bytes, SfOpts) -> {ok, SentBytes} | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+File = file:filename_all() | file:fd():: Filename or file descriptor for the file to be sent.
+Offset = non_neg_integer():: Begin sending at this position in the file.
+Bytes = non_neg_integer():: Send this many bytes.
+SentBytes = non_neg_integer():: This many bytes were sent.
+SfOpts = sendfile_opts():: Sendfile options.
+
+Send data from a file to the given socket.
+
+The file may be sent full or in parts, and may be specified
+by its filename or by an already open file descriptor.
+
+Transports that manipulate TCP directly may use the
+`file:sendfile/{2,4,5}` function, which calls the sendfile
+syscall where applicable (on Linux, for example). Other
+transports can use the `sendfile/6` function exported from
+this module.
+
+=== setopts(CSocket, SockOpts) -> ok | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+SockOpts = any():: Socket options.
+
+Change options for the given socket.
+
+This is mainly useful for switching to active or passive mode
+or to set protocol-specific options.
+
+=== shutdown(CSocket, How) -> ok | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+How = read | write | read_write:: Which side(s) of the socket to close.
+
+Immediately close the socket in one or two directions.
+
+=== sockname(Socket) -> {ok, {IP, Port}} | {error, atom()}
+
+Socket = any():: Socket opened with listen/1 or accept/2.
+IP = inet:ip_address():: IP of the local endpoint.
+Port = inet:port_number():: Port of the local endpoint.
+
+Return the IP and port of the local endpoint.
+
+== Exports
+
+=== sendfile(Transport, CSocket, File, Offset, Bytes, SfOpts) -> {ok, SentBytes} | {error, atom()}
+
+Transport = module():: Transport module for this socket.
+CSocket = any():: Socket for this connection.
+File = file:filename_all() | file:fd():: Filename or file descriptor for the file to be sent.
+Offset = non_neg_integer():: Begin sending at this position in the file.
+Bytes = non_neg_integer():: Send this many bytes.
+SentBytes = non_neg_integer():: This many bytes were sent.
+SfOpts = sendfile_opts():: Sendfile options.
+
+Send data from a file to the given socket.
+
+This function emulates the function `file:sendfile/{2,4,5}`
+and may be used when transports are not manipulating TCP
+directly.