Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Import the acceptor code from Cowboy
Modules were renamed. The 'cowboy_' prefix became 'ranch_'. At the same time, ranch_ssl_transport became ranch_ssl, and ranch_tcp_transport became ranch_tcp, because appending '_transport' felt a bit redundant considering SSL and TCP clearly are transports. One test has been added to make sure everything is working.
- Loading branch information
Loïc Hoguin
committed
Apr 14, 2012
1 parent
f971ec1
commit 4156fa3
Showing
23 changed files
with
1,238 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.ranch.plt | ||
.eunit | ||
deps | ||
doc/*.css | ||
doc/*.html | ||
doc/*.png | ||
doc/edoc-info | ||
ebin | ||
logs | ||
test/*.beam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Ranch is available thanks to the work of: | ||
|
||
Loïc Hoguin | ||
Ali Sabil | ||
Andrew Thompson | ||
DeadZen | ||
Hunter Morris | ||
Jesper Louis Andersen | ||
Paul Oliver | ||
Roberto Ostinelli | ||
Steven Gravell |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Copyright (c) 2011-2012, Loïc Hoguin <essen@ninenines.eu> | ||
|
||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted, provided that the above | ||
copyright notice and this permission notice appear in all copies. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# See LICENSE for licensing information. | ||
|
||
PROJECT = ranch | ||
|
||
DIALYZER = dialyzer | ||
REBAR = rebar | ||
|
||
all: app | ||
|
||
# Application. | ||
|
||
deps: | ||
@$(REBAR) get-deps | ||
|
||
app: deps | ||
@$(REBAR) compile | ||
|
||
clean: | ||
@$(REBAR) clean | ||
rm -f test/*.beam | ||
rm -f erl_crash.dump | ||
|
||
docs: clean-docs | ||
@$(REBAR) doc skip_deps=true | ||
|
||
clean-docs: | ||
rm -f doc/*.css | ||
rm -f doc/*.html | ||
rm -f doc/*.png | ||
rm -f doc/edoc-info | ||
|
||
# Tests. | ||
|
||
tests: clean app eunit ct | ||
|
||
eunit: | ||
@$(REBAR) -C rebar.tests.config eunit skip_deps=true | ||
|
||
ct: | ||
@$(REBAR) -C rebar.tests.config ct skip_deps=true | ||
|
||
# Dialyzer. | ||
|
||
build-plt: | ||
@$(DIALYZER) --build_plt --output_plt .$(PROJECT).plt \ | ||
--apps kernel stdlib sasl tools inets crypto public_key ssl | ||
|
||
dialyze: | ||
@$(DIALYZER) --src src --plt .$(PROJECT).plt \ | ||
-Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,91 @@ | ||
Ranch | ||
===== | ||
|
||
Ranch is a socket acceptor pool, able to accept connections for any kind | ||
of TCP protocol. | ||
Ranch is a socket acceptor pool for TCP protocols. | ||
|
||
Goals | ||
----- | ||
|
||
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. | ||
|
||
Ranch provides a **modular** design, letting you choose which transport | ||
and protocol are going to be used for a particular listener. Listeners | ||
accept and manage connections on one port, and include facilities to | ||
limit the number of **concurrent** connections. Connections are sorted | ||
into **pools**, each pool having a different configurable limit. | ||
|
||
Ranch also allows you to **upgrade** the acceptor pool without having | ||
to close any of the currently opened sockets. | ||
|
||
The project is currently in early development. Comments and suggestions are | ||
more than welcome. To contribute, either open bug reports, or fork the project | ||
and send us pull requests with new or improved functionality. You should | ||
discuss your plans with us before doing any serious work, though, to avoid | ||
duplicating efforts. | ||
|
||
Quick start | ||
----------- | ||
|
||
* Add Ranch as a rebar or agner dependency to your application. | ||
* Start Ranch and add one or more listeners. | ||
* Write protocol handlers for your application. | ||
|
||
Getting Started | ||
--------------- | ||
|
||
Ranch accepts connections received on a given port and using a given | ||
transport, like TCP or SSL, and forward them to a given protocol | ||
handler. Acceptors and protocol handler processes are of course | ||
supervised automatically. | ||
|
||
Ranch does nothing by default. You need to explicitly request Ranch | ||
to listen on a port with your chosen transport and protocol handlers. | ||
To do so, you must start a listener. | ||
|
||
A listener is a special kind of supervisor that manages both the | ||
acceptor pool and the protocol processes. It is named and can thus be | ||
started and stopped at will. | ||
|
||
An acceptor pool is a pool of processes whose only role is to accept | ||
new connections. It's good practice to have many of these processes | ||
as they are very cheap and allow much quicker response when you get | ||
many connections. Of course, as with everything else, you should | ||
**benchmark** before you decide what's best for you. | ||
|
||
Ranch includes both TCP and SSL transport handlers, abstracted through | ||
a single common interface. | ||
|
||
You can start and stop listeners by calling `ranch:start_listener/6` and | ||
`ranch:stop_listener/1` respectively. | ||
|
||
The following example demonstrates the startup of a very simple listener. | ||
|
||
``` erlang | ||
application:start(ranch), | ||
%% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts | ||
ranch:start_listener(my_echo_listener, 100, | ||
ranch_tcp, [{port, 1234}], | ||
my_echo_protocol, [{log, "echo.log"}] | ||
). | ||
``` | ||
|
||
Writing a protocol handler | ||
-------------------------- | ||
|
||
The only exported function a protocol handler needs is the start_link/4 | ||
function, with arguments ListenerPid, Socket, Transport and Opts. ListenerPid | ||
is the pid to the listener's gen_server, managing the connections. Socket is of | ||
course the client socket; Transport is the module name of the chosen transport | ||
handler and Opts is protocol options defined when starting the listener. | ||
|
||
After initializing your protocol, it is recommended to call the | ||
function ranch:accept_ack/1 with the ListenerPid as argument, | ||
as it will ensure Ranch has been able to fully initialize the socket. | ||
Anything you do past this point is up to you! | ||
|
||
If you need to change some socket options, like enabling raw mode for example, | ||
you can call the <em>Transport:setopts/2</em> function. It is the protocol's | ||
responsability to manage the socket usage, there should be no need for an user | ||
to specify that kind of options while starting a listener. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
ROADMAP | ||
======= | ||
|
||
This document explains in as much details as possible the | ||
list of planned changes and work to be done on the Ranch | ||
project. It is non-exhaustive and subject to change. Items | ||
are not ordered. | ||
|
||
* Write examples. | ||
|
||
Ideally we would have one complete example per folder. | ||
|
||
Examples should be commented. They may or may not be | ||
used for writing the user guides. | ||
|
||
* Write user guides. | ||
|
||
We currently have good API documentation, but no step | ||
by step user guides. | ||
|
||
* Continuous performance testing. | ||
|
||
Initially dubbed the Horse project, Ranch could benefit | ||
from a continuous performance testing tool that would | ||
allow us to easily compare the impact of the changes we | ||
are introducing, similar to what the Phoronix test suite | ||
allows. | ||
|
||
* Transport upgrades. | ||
|
||
Some protocols allow an upgrade from TCP to SSL without | ||
closing the connection. This is currently not possible | ||
through the Ranch API. | ||
|
||
* Resizing the acceptor pool. | ||
|
||
We should be able to add more acceptors to a pool but also | ||
to remove some of them as needed. | ||
|
||
* Add Transport:secure/0. | ||
|
||
Currently Cowboy checks if a connection is secure by | ||
checking if its name is 'ssl'. This isn't a very modular | ||
solution, adding an API function that returns whether | ||
a connection is secure would fix that issue. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{incl_app, ranch, details}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
@author Lo�c Hoguin <essen@ninenines.eu> | ||
@copyright 2011-2012 Lo�c Hoguin | ||
@version HEAD | ||
@title Socket acceptor pool for TCP protocols. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{erl_opts, [ | ||
%% bin_opt_info, | ||
warn_missing_spec, | ||
warnings_as_errors, | ||
warn_export_all | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{cover_enabled, true}. | ||
{deps, []}. | ||
{eunit_opts, [verbose, {report, {eunit_surefire, [{dir, "."}]}}]}. | ||
{erl_opts, []}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
%% Copyright (c) 2011-2012, Loïc Hoguin <essen@ninenines.eu> | ||
%% | ||
%% Permission to use, copy, modify, and/or distribute this software for any | ||
%% purpose with or without fee is hereby granted, provided that the above | ||
%% copyright notice and this permission notice appear in all copies. | ||
%% | ||
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
|
||
{application, ranch, [ | ||
{description, "Socket acceptor pool for TCP protocols."}, | ||
{vsn, "0.1.0"}, | ||
{modules, []}, | ||
{registered, [ranch_sup]}, | ||
{applications, [ | ||
kernel, | ||
stdlib | ||
]}, | ||
{mod, {ranch_app, []}}, | ||
{env, []} | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
%% Copyright (c) 2011-2012, Loïc Hoguin <essen@ninenines.eu> | ||
%% | ||
%% Permission to use, copy, modify, and/or distribute this software for any | ||
%% purpose with or without fee is hereby granted, provided that the above | ||
%% copyright notice and this permission notice appear in all copies. | ||
%% | ||
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
|
||
%% @doc Ranch API to start and stop listeners. | ||
-module(ranch). | ||
|
||
-export([start_listener/6, stop_listener/1, child_spec/6, accept_ack/1, | ||
get_protocol_options/1, set_protocol_options/2]). | ||
|
||
%% @doc Start a listener for the given transport and protocol. | ||
%% | ||
%% A listener is effectively a pool of <em>NbAcceptors</em> acceptors. | ||
%% Acceptors accept connections on the given <em>Transport</em> and forward | ||
%% connections to the given <em>Protocol</em> handler. Both transport and | ||
%% protocol modules can be given options through the <em>TransOpts</em> and | ||
%% the <em>ProtoOpts</em> arguments. Available options are documented in the | ||
%% <em>listen</em> transport function and in the protocol module of your choice. | ||
%% | ||
%% All acceptor and connection processes are supervised by the listener. | ||
%% | ||
%% It is recommended to set a large enough number of acceptors to improve | ||
%% performance. The exact number depends of course on your hardware, on the | ||
%% protocol used and on the number of expected simultaneous connections. | ||
%% | ||
%% The <em>Transport</em> option <em>max_connections</em> allows you to define | ||
%% the maximum number of simultaneous connections for this listener. It defaults | ||
%% to 1024. See <em>ranch_listener</em> for more details on limiting the number | ||
%% of connections. | ||
%% | ||
%% <em>Ref</em> can be used to stop the listener later on. | ||
-spec start_listener(any(), non_neg_integer(), module(), any(), module(), any()) | ||
-> {ok, pid()}. | ||
start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) | ||
when is_integer(NbAcceptors) andalso is_atom(Transport) | ||
andalso is_atom(Protocol) -> | ||
supervisor:start_child(ranch_sup, child_spec(Ref, NbAcceptors, | ||
Transport, TransOpts, Protocol, ProtoOpts)). | ||
|
||
%% @doc Stop a listener identified by <em>Ref</em>. | ||
%% | ||
%% Note that stopping the listener will close all currently running | ||
%% connections abruptly. | ||
-spec stop_listener(any()) -> ok | {error, not_found}. | ||
stop_listener(Ref) -> | ||
case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of | ||
ok -> | ||
supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}); | ||
{error, Reason} -> | ||
{error, Reason} | ||
end. | ||
|
||
%% @doc Return a child spec suitable for embedding. | ||
%% | ||
%% When you want to embed Ranch in another application, you can use this | ||
%% function to create a <em>ChildSpec</em> suitable for use in a supervisor. | ||
%% The parameters are the same as in <em>start_listener/6</em> but rather | ||
%% than hooking the listener to the Ranch internal supervisor, it just returns | ||
%% the spec. | ||
-spec child_spec(any(), non_neg_integer(), module(), any(), module(), any()) | ||
-> supervisor:child_spec(). | ||
child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) | ||
when is_integer(NbAcceptors) andalso is_atom(Transport) | ||
andalso is_atom(Protocol) -> | ||
{{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [ | ||
NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts | ||
]}, permanent, 5000, supervisor, [ranch_listener_sup]}. | ||
|
||
%% @doc Acknowledge the accepted connection. | ||
%% | ||
%% Effectively used to make sure the socket control has been given to | ||
%% the protocol process before starting to use it. | ||
-spec accept_ack(pid()) -> ok. | ||
accept_ack(ListenerPid) -> | ||
receive {shoot, ListenerPid} -> ok end. | ||
|
||
%% @doc Return the current protocol options for the given listener. | ||
-spec get_protocol_options(any()) -> any(). | ||
get_protocol_options(Ref) -> | ||
ListenerPid = ref_to_listener_pid(Ref), | ||
{ok, ProtoOpts} = ranch_listener:get_protocol_options(ListenerPid), | ||
ProtoOpts. | ||
|
||
%% @doc Upgrade the protocol options for the given listener. | ||
%% | ||
%% The upgrade takes place at the acceptor level, meaning that only the | ||
%% newly accepted connections receive the new protocol options. This has | ||
%% no effect on the currently opened connections. | ||
-spec set_protocol_options(any(), any()) -> ok. | ||
set_protocol_options(Ref, ProtoOpts) -> | ||
ListenerPid = ref_to_listener_pid(Ref), | ||
ok = ranch_listener:set_protocol_options(ListenerPid, ProtoOpts). | ||
|
||
%% Internal. | ||
|
||
-spec ref_to_listener_pid(any()) -> pid(). | ||
ref_to_listener_pid(Ref) -> | ||
Children = supervisor:which_children(ranch_sup), | ||
{_, ListenerSupPid, _, _} = lists:keyfind( | ||
{ranch_listener_sup, Ref}, 1, Children), | ||
ListenerSupChildren = supervisor:which_children(ListenerSupPid), | ||
{_, ListenerPid, _, _} = lists:keyfind( | ||
ranch_listener, 1, ListenerSupChildren), | ||
ListenerPid. |
Oops, something went wrong.