├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── LICENSE ├── Makefile ├── README.asciidoc ├── doc └── src │ ├── guide │ ├── book.asciidoc │ ├── connection_draining.asciidoc │ ├── embedded.asciidoc │ ├── internals.asciidoc │ ├── introduction.asciidoc │ ├── listeners.asciidoc │ ├── migrating_from_1.5.asciidoc │ ├── migrating_from_1.6.asciidoc │ ├── migrating_from_1.7.asciidoc │ ├── migrating_from_1.x.asciidoc │ ├── migrating_from_2.0.asciidoc │ ├── migrating_from_2.1.asciidoc │ ├── parsers.asciidoc │ ├── protocols.asciidoc │ ├── ssl_auth.asciidoc │ └── transports.asciidoc │ └── manual │ ├── ranch.asciidoc │ ├── ranch.child_spec.asciidoc │ ├── ranch.get_addr.asciidoc │ ├── ranch.get_max_connections.asciidoc │ ├── ranch.get_port.asciidoc │ ├── ranch.get_protocol_options.asciidoc │ ├── ranch.get_status.asciidoc │ ├── ranch.get_transport_options.asciidoc │ ├── ranch.handshake.asciidoc │ ├── ranch.handshake_cancel.asciidoc │ ├── ranch.handshake_continue.asciidoc │ ├── ranch.info.asciidoc │ ├── ranch.procs.asciidoc │ ├── ranch.recv_proxy_header.asciidoc │ ├── ranch.remove_connection.asciidoc │ ├── ranch.resume_listener.asciidoc │ ├── ranch.set_max_connections.asciidoc │ ├── ranch.set_protocol_options.asciidoc │ ├── ranch.set_transport_options.asciidoc │ ├── ranch.start_listener.asciidoc │ ├── ranch.stop_listener.asciidoc │ ├── ranch.suspend_listener.asciidoc │ ├── ranch.wait_for_connections.asciidoc │ ├── ranch_app.asciidoc │ ├── ranch_protocol.asciidoc │ ├── ranch_proxy_header.asciidoc │ ├── ranch_proxy_header.header.asciidoc │ ├── ranch_proxy_header.parse.asciidoc │ ├── ranch_proxy_header.to_connection_info.asciidoc │ ├── ranch_ssl.asciidoc │ ├── ranch_tcp.asciidoc │ ├── ranch_transport.asciidoc │ └── ranch_transport.sendfile.asciidoc ├── ebin └── ranch.app ├── erlang.mk ├── examples ├── tcp_echo │ ├── Makefile │ ├── README.md │ ├── relx.config │ └── src │ │ ├── echo_protocol.erl │ │ ├── tcp_echo_app.erl │ │ └── tcp_echo_sup.erl └── tcp_reverse │ ├── Makefile │ ├── README.md │ ├── relx.config │ └── src │ ├── reverse_protocol.erl │ ├── tcp_reverse_app.erl │ └── tcp_reverse_sup.erl ├── src ├── ranch.appup ├── ranch.erl ├── ranch_acceptor.erl ├── ranch_acceptors_sup.erl ├── ranch_app.erl ├── ranch_conns_sup.erl ├── ranch_conns_sup_sup.erl ├── ranch_crc32c.erl ├── ranch_embedded_sup.erl ├── ranch_listener_sup.erl ├── ranch_protocol.erl ├── ranch_proxy_header.erl ├── ranch_server.erl ├── ranch_server_proxy.erl ├── ranch_ssl.erl ├── ranch_sup.erl ├── ranch_tcp.erl └── ranch_transport.erl └── test ├── acceptor_SUITE.erl ├── active_echo_protocol.erl ├── batch_echo_protocol.erl ├── check_tcp_options.erl ├── cover.spec ├── crash_protocol.erl ├── echo_protocol.erl ├── embedded_sup.erl ├── handshake_protocol.erl ├── notify_and_wait_protocol.erl ├── proxy_header_SUITE.erl ├── proxy_protocol.erl ├── ranch_concuerror.erl ├── ranch_ct_hook.erl ├── ranch_erlang_transport.erl ├── ranch_listen_error_transport.erl ├── remove_conn_and_wait_protocol.erl ├── sendfile_SUITE.erl ├── shutdown_SUITE.erl ├── ssl_upgrade_protocol.erl ├── stampede_SUITE.erl ├── supervisor_separate.erl ├── transport_capabilities_protocol.erl ├── trap_exit_protocol.erl └── upgrade_SUITE.erl /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | ## Use workflows from ninenines/ci.erlang.mk to test Ranch. 2 | 3 | name: Check Ranch 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | schedule: 11 | ## Every Monday at 4am. 12 | - cron: 0 4 * * 1 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | cleanup-master: 20 | name: Cleanup master build 21 | runs-on: ubuntu-latest 22 | permissions: 23 | actions: write 24 | steps: 25 | 26 | - name: Cleanup master build if necessary 27 | if: ${{ github.event_name == 'schedule' }} 28 | run: | 29 | gh cache delete Linux-X64-Erlang-master -R $REPO || true 30 | gh cache delete macOS-ARM64-Erlang-master -R $REPO || true 31 | env: 32 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | REPO: ${{ github.repository }} 34 | 35 | check: 36 | name: Ranch 37 | needs: cleanup-master 38 | uses: ninenines/ci.erlang.mk/.github/workflows/ci.yaml@master 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .erlang.mk 2 | .ranch.plt 3 | *.d 4 | deps 5 | doc/guide.pdf 6 | doc/html 7 | doc/man3 8 | doc/man7 9 | ebin/test 10 | ebin/ranch.appup 11 | ebin/*.beam 12 | examples/*/ebin 13 | examples/*/*.bak 14 | examples/*/*.d 15 | examples/*/_rel 16 | logs 17 | test/*.beam 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2025, Loïc Hoguin 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE for licensing information. 2 | 3 | PROJECT = ranch 4 | PROJECT_DESCRIPTION = Socket acceptor pool for TCP protocols. 5 | PROJECT_VERSION = 2.2.0 6 | PROJECT_REGISTERED = ranch_server 7 | 8 | # Options. 9 | 10 | CT_OPTS += -pa test -ct_hooks ranch_ct_hook [] # -boot start_sasl 11 | PLT_APPS = crypto public_key tools # common_test ct_helper stampede 12 | 13 | # Dependencies. 14 | 15 | LOCAL_DEPS = ssl 16 | 17 | DOC_DEPS = asciideck 18 | 19 | TEST_DEPS = $(if $(CI_ERLANG_MK),ci.erlang.mk) ct_helper stampede 20 | dep_ct_helper = git https://github.com/ninenines/ct_helper master 21 | dep_stampede = git https://github.com/juhlig/stampede 0.6.0 22 | 23 | # Concuerror tests. 24 | 25 | # CONCUERROR_OPTS = -v 7 -k 26 | CONCUERROR_TESTS = ranch_concuerror:start_stop ranch_concuerror:info 27 | 28 | # CI configuration. 29 | 30 | dep_ci.erlang.mk = git https://github.com/ninenines/ci.erlang.mk master 31 | DEP_EARLY_PLUGINS = ci.erlang.mk 32 | 33 | AUTO_CI_OTP ?= OTP-LATEST-24+ 34 | AUTO_CI_WINDOWS ?= OTP-LATEST-24+ 35 | 36 | # Hex configuration. 37 | 38 | define HEX_TARBALL_EXTRA_METADATA 39 | #{ 40 | licenses => [<<"ISC">>], 41 | links => #{ 42 | <<"User guide">> => <<"https://ninenines.eu/docs/en/ranch/2.2/guide/">>, 43 | <<"Function reference">> => <<"https://ninenines.eu/docs/en/ranch/2.2/manual/">>, 44 | <<"GitHub">> => <<"https://github.com/ninenines/ranch">>, 45 | <<"Sponsor">> => <<"https://github.com/sponsors/essen">> 46 | } 47 | } 48 | endef 49 | 50 | # Standard targets. 51 | 52 | include erlang.mk 53 | 54 | # Don't run the havoc test suite by default. 55 | 56 | ifndef FULL 57 | CT_SUITES := $(filter-out stampede,$(CT_SUITES)) 58 | endif 59 | 60 | # Compile options. 61 | 62 | ERLC_OPTS += +warn_missing_spec +warn_untyped_record 63 | TEST_ERLC_OPTS += +'{parse_transform, eunit_autoexport}' 64 | 65 | # Dialyze the tests. 66 | 67 | #DIALYZER_OPTS += --src -r test 68 | 69 | # Use erl_make_certs from the tested release during CI 70 | # and ensure that ct_helper is always recompiled. 71 | # 72 | # Note that erl_make_certs was removed from OTP-20.1. For now 73 | # we are fine using the most recent version from OTP-20. 74 | 75 | ci-setup:: $(DEPS_DIR)/ct_helper 76 | $(gen_verbose) cp ~/.kerl/builds/$(CI_OTP_RELEASE)/otp_src_git/lib/ssl/test/erl_make_certs.erl deps/ct_helper/src/ || true 77 | $(gen_verbose) $(MAKE) -C $(DEPS_DIR)/ct_helper clean app 78 | 79 | # Prepare for the release. 80 | 81 | prepare_tag: 82 | $(verbose) $(warning Hex metadata: $(HEX_TARBALL_EXTRA_METADATA)) 83 | $(verbose) echo 84 | $(verbose) echo -n "Most recent tag: " 85 | $(verbose) git tag --sort=creatordate | tail -n1 86 | $(verbose) git verify-tag `git tag --sort=creatordate | tail -n1` 87 | $(verbose) echo -n "MAKEFILE: " 88 | $(verbose) grep -m1 PROJECT_VERSION Makefile 89 | $(verbose) echo -n "APP: " 90 | $(verbose) grep -m1 vsn ebin/$(PROJECT).app | sed 's/ //g' 91 | $(verbose) echo -n "APPUP: " 92 | $(verbose) grep -m1 {\" src/$(PROJECT).appup 93 | $(verbose) echo -n "GUIDE: " 94 | $(verbose) grep -h dep_$(PROJECT)_commit doc/src/guide/*.asciidoc || true 95 | $(verbose) echo ; echo 96 | $(verbose) echo -n "LICENSE: " ; head -n1 LICENSE 97 | $(verbose) echo 98 | $(verbose) echo "Dependencies:" 99 | $(verbose) grep ^DEPS Makefile || echo "DEPS =" 100 | $(verbose) grep ^dep_ Makefile || true 101 | $(verbose) echo 102 | $(verbose) echo "Links in the README:" 103 | $(verbose) grep http.*:// README.asciidoc 104 | $(verbose) echo 105 | $(verbose) echo "Titles in most recent CHANGELOG:" 106 | $(verbose) for f in `ls -rv doc/src/guide/migrating_from_*.asciidoc | head -n1`; do \ 107 | echo $$f:; \ 108 | grep == $$f; \ 109 | done 110 | -------------------------------------------------------------------------------- /README.asciidoc: -------------------------------------------------------------------------------- 1 | = Ranch 2 | 3 | Ranch is a socket acceptor pool for TCP protocols. 4 | 5 | == Goals 6 | 7 | Ranch aims to provide everything you need to accept TCP connections with 8 | a *small* code base and *low latency* while being easy to use directly 9 | as an application or to *embed* into your own. 10 | 11 | Ranch provides a *modular* design, letting you choose which transport 12 | and protocol are going to be used for a particular listener. Listeners 13 | accept and manage connections on one port, and include facilities to 14 | limit the number of *concurrent* connections. Connections are sorted 15 | into *pools*, each pool having a different configurable limit. 16 | 17 | Ranch also allows you to *upgrade* the acceptor pool without having 18 | to close any of the currently opened sockets. 19 | 20 | == Online documentation 21 | 22 | * https://ninenines.eu/docs/en/ranch/2.2/guide[User guide] 23 | * https://ninenines.eu/docs/en/ranch/2.2/manual[Function reference] 24 | 25 | == Offline documentation 26 | 27 | * While still online, run `make docs` 28 | * User guide available in `doc/` in PDF and HTML formats 29 | * Function reference man pages available in `doc/man3/` and `doc/man7/` 30 | * Run `make install-docs` to install man pages on your system 31 | * Full documentation in Asciidoc available in `doc/src/` 32 | * Examples available in `examples/` 33 | 34 | == Getting help 35 | 36 | * https://discord.gg/x25nNq2fFE[Discord server] 37 | * https://github.com/ninenines/ranch/issues[Issues tracker] 38 | * https://ninenines.eu/services[Commercial Support] 39 | -------------------------------------------------------------------------------- /doc/src/guide/book.asciidoc: -------------------------------------------------------------------------------- 1 | // a2x: --dblatex-opts "-P latex.output.revhistory=0 -P doc.publisher.show=0 -P index.numbered=0" 2 | // a2x: -d book --attribute tabsize=4 3 | 4 | = Ranch User Guide 5 | 6 | = Interface 7 | 8 | include::introduction.asciidoc[Introduction] 9 | 10 | include::listeners.asciidoc[Listeners] 11 | 12 | include::transports.asciidoc[Transports] 13 | 14 | include::protocols.asciidoc[Protocols] 15 | 16 | include::embedded.asciidoc[Embedded mode] 17 | 18 | = How to 19 | 20 | include::parsers.asciidoc[Writing parsers] 21 | 22 | include::ssl_auth.asciidoc[SSL client authentication] 23 | 24 | include::connection_draining.asciidoc[Connection draining] 25 | 26 | = Advanced 27 | 28 | include::internals.asciidoc[Internals] 29 | 30 | = Additional information 31 | 32 | include::migrating_from_2.1.asciidoc[Migrating from Ranch 2.1 to 2.2] 33 | 34 | include::migrating_from_2.0.asciidoc[Migrating from Ranch 2.0 to 2.1] 35 | 36 | include::migrating_from_1.7.asciidoc[Migrating from Ranch 1.7 to 2.0] 37 | 38 | include::migrating_from_1.6.asciidoc[Migrating from Ranch 1.6 to 1.7] 39 | 40 | include::migrating_from_1.5.asciidoc[Migrating from Ranch 1.5 to 1.6] 41 | 42 | include::migrating_from_1.x.asciidoc[Migrating from Ranch 1.x] 43 | -------------------------------------------------------------------------------- /doc/src/guide/connection_draining.asciidoc: -------------------------------------------------------------------------------- 1 | == Connection draining 2 | 3 | Stopping a Ranch listener via `ranch:stop_listener/1` will invariably kill 4 | all connection processes the listener hosts. However, you may want to stop 5 | a listener in a graceful fashion, ie by not accepting any new connections, 6 | but allowing the existing connection processes to exit by themselves instead 7 | of being killed. 8 | 9 | For this purpose, you should first suspend the listener you wish to 10 | stop gracefully, and then wait for its connection count to drop to 11 | zero. 12 | 13 | .Draining a single listener 14 | 15 | [source,erlang] 16 | ---- 17 | ok = ranch:suspend_listener(Ref), 18 | ok = ranch:wait_for_connections(Ref, '==', 0), 19 | ok = ranch:stop_listener(Ref). 20 | ---- 21 | 22 | If you want to drain more than just one listener, it may be important to first suspend 23 | them all before beginning to wait for their connection counts to reach zero. Otherwise, 24 | the not yet suspended listeners will still be accepting connections while you wait for 25 | the suspended ones to be drained. 26 | 27 | .Draining multiple listeners 28 | 29 | [source,erlang] 30 | ---- 31 | lists:foreach( 32 | fun (Ref) -> 33 | ok = ranch:suspend_listener(Ref) 34 | end, 35 | Refs 36 | ), 37 | lists:foreach( 38 | fun (Ref) -> 39 | ok = ranch:wait_for_connections(Ref, '==', 0), 40 | ok = ranch:stop_listener(Ref) 41 | end, 42 | Refs 43 | ). 44 | ---- 45 | 46 | If you have long-running connection processes hosted by the listener you want to stop 47 | gracefully, draining may take a long time, possibly forever. If you just want to give 48 | the connection processes a chance to finish, but are not willing to wait for infinity, 49 | the waiting part could be handled in a separate process. 50 | 51 | .Draining a listener with a timeout 52 | 53 | [source,erlang] 54 | ---- 55 | ok = ranch:suspend_listener(Ref), 56 | {DrainPid, DrainRef} = spawn_monitor( 57 | fun () -> 58 | ok = ranch:wait_for_connections(Ref, '==', 0) 59 | end 60 | ), 61 | receive 62 | {'DOWN', DrainRef, process, DrainPid, _} -> 63 | ok 64 | after DrainTimeout -> 65 | exit(DrainPid, kill), 66 | ok 67 | end, 68 | ok = ranch:stop_listener(Ref). 69 | ---- 70 | 71 | To drain listeners automatically as part of your application shutdown routine, 72 | use the `prep_stop/1` function of your application module. 73 | 74 | .Draining listeners automatically on application shutdown 75 | 76 | [source,erlang] 77 | ---- 78 | -module(my_app). 79 | 80 | -behavior(application). 81 | 82 | -export([start/2]). 83 | -export([prep_stop/1]). 84 | -export([stop/1]). 85 | 86 | start(_StartType, _StartArgs) -> 87 | {ok, _} = ranch:start_listener(my_listener, ranch_tcp, #{}, my_protocol, []), 88 | my_app_sup:start_link(). 89 | 90 | prep_stop(State) -> 91 | ok = ranch:suspend_listener(my_listener), 92 | ok = ranch:wait_for_connections(my_listener, '==', 0), 93 | ok = ranch:stop_listener(my_listener), 94 | State. 95 | 96 | stop(_State) -> 97 | ok. 98 | ---- 99 | -------------------------------------------------------------------------------- /doc/src/guide/embedded.asciidoc: -------------------------------------------------------------------------------- 1 | == Embedded mode 2 | 3 | Embedded mode allows you to insert Ranch listeners directly 4 | in your supervision tree. This allows for greater fault tolerance 5 | control by permitting the shutdown of a listener due to the 6 | failure of another part of the application and vice versa. 7 | 8 | However, just as for non-embedded listeners that were started via 9 | `ranch:start_listener/5`, it is required that the `ranch` application 10 | is running before you can start embedded listeners. Furthermore, 11 | this also means that embedded listeners will restart when `ranch_sup` fails. 12 | 13 | WARNING: By using embedded mode, it is possible to start a listener with the same name 14 | as an already existing listener. This will corrupt the information Ranch 15 | keeps for that listener, so you should take care to ensure unique listener 16 | names yourself. A good way to achieve this is by combining the embedded 17 | listener's name with `?MODULE`, or the name of the application it is used 18 | in. 19 | 20 | === Embedding 21 | 22 | To embed Ranch in your application you can simply add the child specs 23 | to your supervision tree. This can all be done in the `init/1` function 24 | of one of your application supervisors. 25 | 26 | Ranch has a convenience function for getting the listeners child specs 27 | called `ranch:child_spec/5`, that works like `ranch:start_listener/5`, 28 | except that it doesn't start anything, it only returns child specs. 29 | 30 | The following example adds one listener to another application's 31 | supervision tree. 32 | 33 | .Embed Ranch directly in your supervision tree 34 | 35 | [source,erlang] 36 | ---- 37 | init([]) -> 38 | ListenerSpec = ranch:child_spec({?MODULE, echo}, 39 | ranch_tcp, #{socket_opts => [{port, 5555}]}, 40 | echo_protocol, [] 41 | ), 42 | {ok, {#{}, [ListenerSpec]}}. 43 | ---- 44 | 45 | Embedded listeners cannot be stopped via `ranch:stop_listener/1`. Instead, 46 | are to be stopped as part of the shutdown of your application's supervison 47 | tree. 48 | -------------------------------------------------------------------------------- /doc/src/guide/internals.asciidoc: -------------------------------------------------------------------------------- 1 | == Internals 2 | 3 | This chapter may not apply to embedded Ranch as embedding allows you 4 | to use an architecture specific to your application, which may or may 5 | not be compatible with the description of the Ranch application. 6 | 7 | Note that for everything related to efficiency and performance, 8 | you should perform the benchmarks yourself to get the numbers that 9 | matter to you. Generic benchmarks found on the web may or may not 10 | be of use to you, you can never know until you benchmark your own 11 | system. 12 | 13 | A third party dive into the internals of Ranch is available should 14 | you be interested: https://baozi.technology/ranch-under-the-hood/[Ranch: what's under the hood?] 15 | We make no claims with regard to its freshness or accuracy but this 16 | is a nice document to read along this section. 17 | 18 | === Architecture 19 | 20 | Ranch is an OTP application. 21 | 22 | Like all OTP applications, Ranch has a top supervisor. It is responsible 23 | for supervising the `ranch_server` process and all the listeners that 24 | will be started. 25 | 26 | The `ranch_server` gen_server is a central process keeping track of the 27 | listeners and their acceptors. It does so through the use of a public ets 28 | table called `ranch_server`. The table is owned by the top supervisor 29 | to improve fault tolerance. This way if the `ranch_server` gen_server 30 | fails, it doesn't lose any information and the restarted process can 31 | continue as if nothing happened. 32 | 33 | Ranch uses a custom supervisor for managing connections. This supervisor 34 | keeps track of the number of connections and handles connection limits 35 | directly. While it is heavily optimized to perform the task of creating 36 | connection processes for accepted connections, it is still following the 37 | OTP principles and the usual `sys` and `supervisor` calls will work on 38 | it as expected. 39 | 40 | Listeners are grouped into the `ranch_listener_sup` supervisor and 41 | consist of three kinds of processes: the listener gen_server, the 42 | acceptor processes and the connection processes, both grouped under 43 | their own supervisor. All of these processes are registered to the 44 | `ranch_server` gen_server with varying amount of information. 45 | 46 | All socket operations, including listening for connections, go through 47 | transport handlers. Accepted connections are given to the protocol handler. 48 | Transport handlers are simple callback modules for performing operations on 49 | sockets. Protocol handlers start a new process, which receives socket 50 | ownership, with no requirements on how the code should be written inside 51 | that new process. 52 | 53 | === Number of acceptors 54 | 55 | The second argument to `ranch:start_listener/5` is the number of 56 | processes that will be accepting connections. Care should be taken 57 | when choosing this number. 58 | 59 | First of all, it should not be confused with the maximum number 60 | of connections. Acceptor processes are only used for accepting and 61 | have nothing else in common with connection processes. Therefore 62 | there is nothing to be gained from setting this number too high, 63 | in fact it can slow everything else down. 64 | 65 | Second, this number should be high enough to allow Ranch to accept 66 | connections concurrently. But the number of cores available doesn't 67 | seem to be the only factor for choosing this number, as we can 68 | observe faster accepts if we have more acceptors than cores. It 69 | might be entirely dependent on the protocol, however. 70 | 71 | Our observations suggest that using 100 acceptors on modern hardware 72 | is a good solution, as it's big enough to always have acceptors ready 73 | and it's low enough that it doesn't have a negative impact on the 74 | system's performances. 75 | 76 | === Platform-specific TCP features 77 | 78 | Some socket options are platform-specific and not supported by `inet`. 79 | They can be of interest because they generally are related to 80 | optimizations provided by the underlying OS. They can still be enabled 81 | thanks to the `raw` option, for which we will see an example. 82 | 83 | One of these features is `TCP_DEFER_ACCEPT` on Linux. It is a simplified 84 | accept mechanism which will wait for application data to come in before 85 | handing out the connection to the Erlang process. 86 | 87 | This is especially useful if you expect many connections to be mostly 88 | idle, perhaps part of a connection pool. They can be handled by the 89 | kernel directly until they send any real data, instead of allocating 90 | resources to idle connections. 91 | 92 | To enable this mechanism, the following option can be used. 93 | 94 | .Using raw transport options 95 | 96 | [source,erlang] 97 | {raw, 6, 9, << 30:32/native >>} 98 | 99 | It means go on layer 6, turn on option 9 with the given integer parameter. 100 | -------------------------------------------------------------------------------- /doc/src/guide/introduction.asciidoc: -------------------------------------------------------------------------------- 1 | == Introduction 2 | 3 | Ranch is a socket acceptor pool for TCP protocols. 4 | 5 | Ranch aims to provide everything you need to accept TCP connections 6 | with a small code base and low latency while being easy to use directly 7 | as an application or to embed into your own. 8 | 9 | === Prerequisites 10 | 11 | It is assumed the developer already knows Erlang and has some experience 12 | with socket programming and TCP protocols. 13 | 14 | === Supported platforms 15 | 16 | Ranch is tested and supported on Linux, FreeBSD, macOS and Windows. 17 | 18 | Ranch is developed for Erlang/OTP 24+. 19 | 20 | Ranch may be compiled on earlier Erlang versions with small source code 21 | modifications but there is no guarantee that it will work as expected. 22 | 23 | === Versioning 24 | 25 | Ranch uses http://semver.org/[Semantic Versioning 2.0.0] 26 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_1.5.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 1.5 to 1.6 3 | 4 | Ranch 1.6 added the ability to suspend and resume listeners. 5 | It also deprecates a number of features and add interfaces 6 | that will be used in Ranch 2.0. 7 | 8 | Ranch 1.6 is compatible with Erlang/OTP 18.0 onward. Support 9 | for older releases has been removed. 10 | 11 | === Features added 12 | 13 | * Listeners can now be suspended/resumed without stopping existing 14 | connection processes. This effectively closes the listening socket 15 | and stops the acceptor processes. 16 | 17 | * Transport options can now be updated for suspended listeners. 18 | 19 | * The `Socket` argument given when the protocol starts has been 20 | deprecated. In Ranch 2.0 the socket will be obtainable only 21 | by calling `ranch:handshake/1,2`. 22 | 23 | * Ranch-specific transport options and socket options are now 24 | better separated. When passing Ranch-specific transport options, 25 | Ranch now expects to receive a map, in which case socket 26 | options are passed in the `socket_opts` value. When there 27 | are only socket options they can be passed to Ranch directly 28 | as a convenience. 29 | 30 | * Any future transport option will only be added to the map 31 | type. This includes transport options added in this release. 32 | 33 | * The transport option `ack_timeout` was renamed to `handshake_timeout` 34 | in the map type. 35 | 36 | * The `cacerts` socket option is now silenced in error logs 37 | just like the `certs` and `key` options. 38 | 39 | * The manual has been heavily updated and now features one 40 | manual page per function and module, complete with a per-function 41 | changelog, examples and more. 42 | 43 | === Experimental features added 44 | 45 | * It is now possible to configure the restart intensity for 46 | `ranch_sup` using the OTP application environment. This 47 | feature will remain undocumented unless there is popular 48 | demand for it. 49 | 50 | * Add the transport option `logger` that allows configuring 51 | which logger module will be used. The logger module must 52 | follow the interface of the new `logger` module in Erlang/OTP 21, 53 | or be set to `error_logger` to keep the old behavior. 54 | 55 | === Changed behaviors 56 | 57 | * Transport modules must now implement `Transport:handshake/2,3` 58 | which deprecates and will replace `Transport:accept_ack/1` in 59 | Ranch 2.0. It returns a new socket and can therefore be used 60 | for implementing TLS upgrade mechanisms. 61 | 62 | === New functions 63 | 64 | * The functions `ranch:suspend_listener/1` and `ranch:resume_listener/1` 65 | were added. In addition the function `ranch:get_state/1` can be used 66 | to obtain the running state of a listener. 67 | 68 | * A function `ranch:wait_for_connections/3` was added. 69 | 70 | * A function `ranch:handshake/1,2` was added to replace the 71 | function `ranch:accept_ack/1`. 72 | 73 | === Bugs fixed 74 | 75 | * The specs for the function `Transport:sendfile/2,4,5` have been 76 | corrected. The type used for the filename was too restricting. 77 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_1.6.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 1.6 to 1.7 3 | 4 | Ranch 1.7 adds built-in support for the PROXY protocol. 5 | 6 | The PROXY protocol is a simple and efficient way for proxies 7 | to transmit information about the client. 8 | 9 | While a third-party library already existed, it was not 10 | entirely compatible with the Ranch interface, in particular 11 | when socket active mode was involved. This new implementation 12 | fixes that and supports the full protocol with as little 13 | overhead as possible compared to normal operations: just one 14 | extra function call. 15 | 16 | Ranch 1.7 is compatible with Erlang/OTP 19.0 onward. Support 17 | for Erlang/OTP 18 has been removed. 18 | 19 | === Features added 20 | 21 | * Full support for the PROXY protocol was added. 22 | 23 | === New functions 24 | 25 | * Add the function `ranch:recv_proxy_header/2` to receive 26 | the PROXY protocol header and parse it. It must be called 27 | before `ranch:handshake/1,2`. 28 | 29 | * Add the functions `ranch_proxy_header:parse/1` and 30 | `ranch_proxy_header:header/1,2` to parse and build a 31 | PROXY protocol header, respectively. 32 | 33 | === Bugs fixed 34 | 35 | * Fix a race condition when the listener is restarted 36 | after `ranch_listener_sup` crashes. This resulted in 37 | the original options being used even if the options 38 | were updated at runtime. 39 | 40 | * Make the acceptors exit instead of crash when the 41 | listening socket has been closed to prevent 42 | unnecessary logs. 43 | 44 | * Fix an issue where listener information would not get 45 | cleaned up when an embedded listener was stopped. This 46 | was fixed in Ranch 1.6.2. 47 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_1.7.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 1.7+ to Ranch 2.0 3 | 4 | Ranch 2.0 adds support for multiple connection supervisors. 5 | 6 | Ranch 1.x had a bottleneck because it used only a single 7 | connection supervisor. This was more evident when many 8 | connections were dropped at once as the supervisor couldn't 9 | keep up and failed to accept new connections while cleaning 10 | up the old ones. Ranch 2.0 behaves much better in this scenario 11 | by default. Multiple connection supervisors also helps with 12 | concurrently accepting new connections. 13 | 14 | Ranch 2.0 also adds experimental support for opening more 15 | than one listening socket on a single port. 16 | 17 | Starting with Ranch 2.0 we are also providing a 18 | https://github.com/juhlig/prometheus_ranch[Prometheus collector] 19 | as a separate project as well as a 20 | https://github.com/juhlig/prometheus_ranch/blob/master/dashboards/ranch-dashboard.json[Grafana dashboard]. 21 | 22 | Ranch 2.0 is compatible with Erlang/OTP 21.0 onward. Support 23 | for Erlang/OTP 19 and 20 has been removed. 24 | 25 | === Features added 26 | 27 | * Ranch now comes with a `ranch.appup` file necessary for 28 | performing release upgrades. A test suite has been added 29 | to confirm release upgrades work from one tag to the next. 30 | Numerous fixes were made that will also improve error recovery. 31 | Release upgrades will only be supported from Ranch 2.0 32 | onward. 33 | 34 | * The `num_conns_sups` option has been added. It allows 35 | configuring the number of connection supervisors. It 36 | now defaults to `num_accceptors`. The old behavior can 37 | be obtained by setting this value to 1. 38 | 39 | * The `logger` option is no longer experimental. It now 40 | defaults to `logger` instead of `error_logger`. 41 | 42 | * UNIX domain sockets are now supported. 43 | 44 | * The active N socket option is now supported. It requires 45 | Erlang/OTP 21.3 or above for TLS, however. 46 | 47 | * Embedded listeners are now failing in a predictable 48 | manner when `ranch_server` goes down. It is no longer 49 | necessary to embed `ranch_sup` and the recommendation 50 | is now to just start Ranch normally when using embedded 51 | listeners. 52 | 53 | * Two steps handshake is now supported. This allows 54 | obtaining TLS extensions and updating options before 55 | resuming the handshake. The handshake can also be 56 | canceled. 57 | 58 | === Experimental features added 59 | 60 | * The experimental `num_listen_sockets` option has been 61 | added. It allows opening more than one listening socket 62 | per listener. It can only be used alongside the Linux 63 | `SO_REUSEPORT` socket option or equivalent. It allows 64 | working around a bottleneck in the kernel and maximizes 65 | resource usage, leading to increased rates for accepting 66 | new connections. 67 | 68 | === Features removed 69 | 70 | * The `socket` option was removed. A more viable solution 71 | is to define a custom transport module that returns a fresh 72 | socket when `Transport:listen/1` is called. 73 | 74 | === Changed behaviors 75 | 76 | * The callback function `Transport:listen/1` and its 77 | implementations in `ranch_tcp` and `ranch_ssl` have changed 78 | to accept a map of transport options instead of only 79 | socket options. 80 | 81 | * The callback function `Transport:messages/0` return value 82 | now includes the tag used for passive messages. 83 | 84 | * The `Socket` argument was removed from `Protocol:start_link/3`. 85 | The socket must now be obtained by calling `ranch:handshake/1,2`. 86 | 87 | === Added functions 88 | 89 | * The functions `ranch:handshake_continue/1,2` and 90 | `ranch:handshake_cancel/1` can be used to perform 91 | a two steps handshake. These functions may not be 92 | supported by all transports. 93 | 94 | === Changed functions 95 | 96 | * The `NumAcceptors` argument was removed from `ranch:start_listener/5` 97 | and `ranch:child_spec/5` and moved to the transport options. 98 | 99 | * Ranch options can no longer be passed along with socket options 100 | as a proplist. The only forms allowed are now the `ranch:opts()` 101 | map or only socket options as-is. Individual transport options 102 | are now validated as well. The `ranch:opts()` map must 103 | be used when socket options also use a map. This applies to the 104 | `ranch:start_listener/5`, `ranch:child_spec/5` and 105 | `ranch:set_transport_options/2` functions. 106 | 107 | * The function `ranch:info/1,2` now returns a map containing 108 | each listener's information rather than a list of key/values. 109 | The key `num_acceptors` was removed as it can be found in the 110 | transport options. 111 | 112 | * The function `ranch:set_transport_options/2` no longer requires 113 | the listener to be suspended. Which options apply immediately, 114 | on suspend/resume or on restart has been documented. Some work 115 | has also been done to make these option changes more predictable. 116 | 117 | === Removed functions 118 | 119 | * The function `ranch:accept_ack/1` has been removed in favor 120 | of `ranch:handshake/1,2`. 121 | 122 | === Bugs fixed 123 | 124 | * Calling `ranch:remove_connection/1` will now resume a sleeping 125 | acceptor process when applicable. 126 | 127 | * Repeatedly calling `ranch:remove_connection/1` from a connection 128 | process would crash the respective connection supervisor. This has 129 | now been fixed. 130 | 131 | * When a connection process was failing to start, the socket was 132 | not closed and this lead to leaking sockets. This is now corrected. 133 | 134 | === Other changes 135 | 136 | * Connection draining has now been documented in the guide 137 | following user feedback and discussions. 138 | 139 | * Ranch is now tested against https://concuerror.com/[Concuerror], 140 | a model checking tool for debugging, testing and verifying 141 | concurrent Erlang programs. Two tests have been added in this 142 | release and more will follow in the future. 143 | 144 | * Ranch is now tested against `stampede`, a chaos monkey style 145 | testing tool. Currently includes three scenarios: normal 146 | TCP and TLS listeners and embedded TCP listener. This new 147 | test suite helped uncover a misplaced `monitor/2` call 148 | added during the development of Ranch 2.0 (we were using a 149 | similar tool, `havoc`, at the time of finding that issue). 150 | 151 | * The supervisor for acceptors and the parent supervisor for 152 | connection supervisors now have an adaptive restart 153 | intensity limit set to `1 + ceil(math:log2(NumChildren))` 154 | to allow room for errors when they have many children. 155 | 156 | * Ranch now uses stricter compiler options. Missing function 157 | specs were added to internal modules. 158 | 159 | * Ranch now calls `ssl:handshake/1,2,3` instead of 160 | `ssl:ssl_accept/1,2`. 161 | 162 | * The `ranch_ssl:ssl_opt()` type has been updated to conform 163 | with Erlang/OTP 23.0. 164 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_1.x.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 1.x 3 | 4 | The changelog for Ranch releases before 1.6 can be found 5 | in this section. 6 | 7 | === 1.5.0 8 | 9 | * Add transport functions getopts/2, getstat/1 and getstat/2 10 | * Fix ranch:info/0 and ranch:procs/2 in embedded mode 11 | * Prevent ranch_conns_sup from stopping on unexpected messages 12 | 13 | === 1.4.0 14 | 15 | * Add new transport option num_acceptor 16 | * Deprecate ranch:start_listener/6 in favor of start_listener/5 17 | * Deprecate ranch:child_spec/6 in favor of child_spec/5 18 | 19 | === 1.3.0 20 | 21 | The version numbers 1.3.1 and 1.3.2 were later made to fix 22 | small mistakes made during the 1.3.0 release process. They 23 | do not include code changes. 24 | 25 | * Tested with OTP R16B+ on Linux, FreeBSD, OSX and Windows 26 | * Add ssl to the list of dependencies 27 | * Add ranch:info/0 and ranch:procs/2 to retrieve Ranch state information 28 | * Allow configuring a listener with only SNI, without a default certificate 29 | * Blacklist transport options instead of whitelist 30 | ** Unknown options are now allowed, but will result in a Dialyzer warning 31 | * Add many transport options typespecs and documentation 32 | * Don't silently drop the accept rate when running out of fds 33 | * Prevent a race condition when stopping listeners 34 | * Improve reporting for common errors, for example eaddrinuse 35 | * Fix double removal of connections bug 36 | ** The number of active connections should now be exact 37 | * Fix stuck acceptor bug when controlling_socket returned errors 38 | * Numerous documentation and examples improvements 39 | 40 | === 1.2.1 41 | 42 | * Fix bug preventing node shutdown when SSL is used with OTP 17.1+ 43 | * Tune restart intensity in all supervisors 44 | 45 | === 1.2.0 46 | 47 | * Allow the supervised process and the process owning the socket to be different 48 | * Add many transport options (please refer to the documentation) 49 | * Add function ranch:get_addr/1 to retrieve both IP and port of listener 50 | * Don't pass Ranch-specific options down to transports 51 | ** Should make Dialyzer happy in user projects 52 | ** New types ranch:opt(), ranch_tcp:opt(), ranch_ssl:ssl_opt() and ranch_ssl:opt() 53 | * Fix crash when filtering unknown options out 54 | * Print a warning for each option filtered out 55 | * Handle Transport:controlling_socket/2 errors and close the socket 56 | * Handle Protocol:start_link/4 crashes to avoid killing all active connections 57 | * Use Asciidoc for documentation 58 | * Test Ranch across 14 Erlang versions on CircleCI 59 | * Improve and document test suites with recent ct_helper improvements 60 | * Fix a number of intermittent test issues 61 | 62 | === 1.1.0 63 | 64 | * Add Transport:secure/0 65 | * Add SSL partial_chain option 66 | * Stop reporting errors on {error, closed} in accept_ack 67 | 68 | === 1.0.0 69 | 70 | * Initial release 71 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_2.0.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 2.0 to Ranch 2.1 3 | 4 | Ranch 2.1 adds counters and alarms. 5 | 6 | The https://github.com/juhlig/prometheus_ranch[Prometheus collector] 7 | was updated to include accepted/terminated connections 8 | metrics. 9 | 10 | Ranch 2.1 is compatible with Erlang/OTP 22.0 onward. Support 11 | for Erlang/OTP 21 has been removed. 12 | 13 | === Features added 14 | 15 | * Metrics are now provided by `ranch:info/0,1`. Currently 16 | includes accepted/terminated connection counts per 17 | connection supervisor. 18 | 19 | * Alarms can now be configured. The only alarm currently 20 | available is `num_connections`. When the number of 21 | connections goes over a configurable threshold Ranch 22 | will call the given callback. This can be used to 23 | programmatically shut down idle connections to 24 | make up space for new connections, for example. 25 | 26 | * A `post_listen_callback` option has been added. It 27 | receives sockets immediately after the `Transport:listen/1` 28 | call. It can be used for some additional initialization 29 | of the socket, such as setting file permissions on 30 | Unix domain sockets. 31 | 32 | * It is now possible to use TLS-PSK authentication 33 | without having to specify a default certificate 34 | for TLS < 1.3. 35 | 36 | === Experimental features added 37 | 38 | * The `inet_backend` option is now properly handled 39 | and tested for TCP listeners. This allows using 40 | the experimental `socket` backend. The `socket` 41 | backend is now tested with Ranch. Note that 42 | there are known issues and Windows support is not 43 | currently implemented. 44 | 45 | === Changed behaviors 46 | 47 | * Ranch will now remove unsupported SSL/TLS options 48 | where applicable. A warning will be logged when 49 | this happens. Options are only removed when they 50 | are not compatible with the selected TLS version 51 | and leaving them would prevent the listener from 52 | starting. 53 | + 54 | The following options are removed when using TLS 55 | 1.1, 1.2 or 1.3: `beast_mitigation` and `padding_check`. 56 | + 57 | The following options are removed when using TLS 58 | 1.3 exclusively: `client_renegotiation`, 59 | `next_protocols_advertised`, `psk_identity`, 60 | `reuse_session`, `reuse_sessions`, 61 | `secure_renegotiate` and `user_lookup_fun`. 62 | 63 | === Added functions 64 | 65 | * The function `ranch_proxy_header:to_connection_info/1` 66 | converts PROXY protocol information to the same 67 | format as `ssl:connection_information/1`. Because 68 | there is little overlap only the `protocol`, 69 | `selected_cipher_suite` and `sni_hostname` will 70 | be available, however. 71 | -------------------------------------------------------------------------------- /doc/src/guide/migrating_from_2.1.asciidoc: -------------------------------------------------------------------------------- 1 | [appendix] 2 | == Migrating from Ranch 2.1 to Ranch 2.2 3 | 4 | Ranch 2.2 is a maintenance release containing a small number 5 | of fixes and improvements. 6 | 7 | Ranch 2.2 is tested with Erlang/OTP 24.0 onward, although it 8 | should be compatible with Erlang/OTP 22.0 and above. 9 | 10 | === Features added 11 | 12 | * `DTLS` is now supported. 13 | 14 | * The `certs_keys` option from `ssl` is now accepted 15 | and documented. 16 | 17 | * The `UNIQUE_ID` PROXY protocol header extension is 18 | now supported. 19 | 20 | * The `ranch_transport` behavior has a new callback 21 | `format_error/1` which allows finer grained formatting 22 | of Ranch's error messages. The callback is currently 23 | optional and will become required in Ranch 3.0. 24 | 25 | === Changed behaviors 26 | 27 | * Ranch will now obfuscate certificates, keys and passwords 28 | in the error message produced on listen error. 29 | 30 | * The exception reason when a connection process has failed 31 | its handshake has been changed to `{shutdown, {Reason, PeerInfo}}` 32 | where `PeerInfo` contains the peer name when available. 33 | 34 | * The `{packet, raw}` socket option is no longer set explicitly, 35 | as this is already the default value. 36 | 37 | === Bugs fixed 38 | 39 | * `ranch:stop_listener/1` will now return an error instead 40 | of throwing an exception when the listener does not exist. 41 | 42 | * Fix `ranch:recv_proxy_header/2` for the upcoming Erlang/OTP 28. 43 | 44 | * Ensure that a user crash while stopping a listener does 45 | not prevent a subsequent attempt to stop it. 46 | 47 | * Alarm option `threshold` was mispelled in Ranch 2.1. This 48 | has been corrected. The wrong spelling `treshold` is still 49 | accepted and will be removed in Ranch 3.0. 50 | -------------------------------------------------------------------------------- /doc/src/guide/parsers.asciidoc: -------------------------------------------------------------------------------- 1 | == Writing parsers 2 | 3 | There are three kinds of protocols: 4 | 5 | * Text protocols 6 | * Schema-less binary protocols 7 | * Schema-based binary protocols 8 | 9 | This chapter introduces the first two kinds. It will not cover 10 | more advanced topics such as continuations or parser generators. 11 | 12 | This chapter isn't specifically about Ranch, we assume here that 13 | you know how to read data from the socket. The data you read and 14 | the data that hasn't been parsed is saved in a buffer. Every 15 | time you read from the socket, the data read is appended to the 16 | buffer. What happens next depends on the kind of protocol. We 17 | will only cover the first two. 18 | 19 | === Parsing text 20 | 21 | Text protocols are generally line based. This means that we can't 22 | do anything with them until we receive the full line. 23 | 24 | A simple way to get a full line is to use `binary:split/2,3`. 25 | 26 | .Using binary:split/2 to get a line of input 27 | 28 | [source,erlang] 29 | case binary:split(Buffer, <<"\n">>) of 30 | [_] -> 31 | get_more_data(Buffer); 32 | [Line, Rest] -> 33 | handle_line(Line, Rest) 34 | end. 35 | 36 | In the above example, we can have two results. Either there was 37 | a line break in the buffer and we get it split into two parts, 38 | the line and the rest of the buffer; or there was no line break 39 | in the buffer and we need to get more data from the socket. 40 | 41 | Next, we need to parse the line. The simplest way is to again 42 | split, here on space. The difference is that we want to split 43 | on all spaces character, as we want to tokenize the whole string. 44 | 45 | .Using binary:split/3 to split text 46 | 47 | [source,erlang] 48 | case binary:split(Line, <<" ">>, [global]) of 49 | [<<"HELLO">>] -> 50 | be_polite(); 51 | [<<"AUTH">>, User, Password] -> 52 | authenticate_user(User, Password); 53 | [<<"QUIT">>, Reason] -> 54 | quit(Reason) 55 | %% ... 56 | end. 57 | 58 | Pretty simple, right? Match on the command name, get the rest 59 | of the tokens in variables and call the respective functions. 60 | 61 | After doing this, you will want to check if there is another 62 | line in the buffer, and handle it immediately if any. 63 | Otherwise wait for more data. 64 | 65 | === Parsing binary 66 | 67 | Binary protocols can be more varied, although most of them are 68 | pretty similar. The first four bytes of a frame tend to be 69 | the size of the frame, which is followed by a certain number 70 | of bytes for the type of frame and then various parameters. 71 | 72 | Sometimes the size of the frame includes the first four bytes, 73 | sometimes not. Other times this size is encoded over two bytes. 74 | And even other times little-endian is used instead of big-endian. 75 | 76 | The general idea stays the same though. 77 | 78 | .Using binary pattern matching to split frames 79 | 80 | [source,erlang] 81 | << Size:32, _/bits >> = Buffer, 82 | case Buffer of 83 | << Frame:Size/binary, Rest/bits >> -> 84 | handle_frame(Frame, Rest); 85 | _ -> 86 | get_more_data(Buffer) 87 | end. 88 | 89 | You will then need to parse this frame using binary pattern 90 | matching, and handle it. Then you will want to check if there 91 | is another frame fully received in the buffer, and handle it 92 | immediately if any. Otherwise wait for more data. 93 | -------------------------------------------------------------------------------- /doc/src/guide/protocols.asciidoc: -------------------------------------------------------------------------------- 1 | == Protocols 2 | 3 | A protocol handler starts a connection process and defines the 4 | protocol logic executed in this process. 5 | 6 | === Writing a protocol handler 7 | 8 | All protocol handlers must implement the `ranch_protocol` behavior 9 | which defines a single callback, `start_link/3`. This callback is 10 | responsible for spawning a new process for handling the connection. 11 | It receives three arguments: the name of the listener, the 12 | transport handler being used and the protocol options defined in 13 | the call to `ranch:start_listener/5`. This callback must 14 | return `{ok, Pid}`, with `Pid` the pid of the new process. 15 | 16 | The newly started process can then freely initialize itself. However, 17 | it must call `ranch:handshake/1,2` before doing any socket operation. 18 | This will ensure the connection process is the owner of the socket. 19 | It expects the listener's name as argument. 20 | 21 | .Perform the socket handshake 22 | 23 | [source,erlang] 24 | {ok, Socket} = ranch:handshake(Ref). 25 | 26 | If your protocol code requires specific socket options, you should 27 | set them while initializing your connection process, after 28 | calling `ranch:handshake/1,2`. You can use `Transport:setopts/2` 29 | for that purpose. 30 | 31 | Following is the complete protocol code for the example found 32 | in `examples/tcp_echo/`. 33 | 34 | .Protocol module that echoes everything it receives 35 | 36 | [source,erlang] 37 | ---- 38 | -module(echo_protocol). 39 | -behaviour(ranch_protocol). 40 | 41 | -export([start_link/3]). 42 | -export([init/3]). 43 | 44 | start_link(Ref, Transport, Opts) -> 45 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 46 | {ok, Pid}. 47 | 48 | init(Ref, Transport, _Opts = []) -> 49 | {ok, Socket} = ranch:handshake(Ref), 50 | loop(Socket, Transport). 51 | 52 | loop(Socket, Transport) -> 53 | case Transport:recv(Socket, 0, 5000) of 54 | {ok, Data} -> 55 | Transport:send(Socket, Data), 56 | loop(Socket, Transport); 57 | _ -> 58 | ok = Transport:close(Socket) 59 | end. 60 | ---- 61 | 62 | === Using gen_statem and gen_server 63 | 64 | Special processes like the ones that use the `gen_statem` or `gen_server` 65 | behaviours have the particularity of having their `start_link` call not 66 | return until the `init` function returns. This is problematic, because 67 | you won't be able to call `ranch:handshake/1,2` from the `init` callback 68 | as this would cause a deadlock to happen. 69 | 70 | This problem can be addressed in several ways. 71 | 72 | ==== gen_statem 73 | 74 | * Use state enter calls and place the `ranch:handshake/1,2` call in the enter 75 | clause of the initial state. Check the `tcp_reverse` example for a complete 76 | example. 77 | * Use a `next_event` action in the return from `init/1` and place the 78 | `ranch:handshake/1,2` call in the clause handling the event in the initial 79 | state. 80 | * Use the `gen_statem:enter_loop/4` function and start your process with 81 | `proc_lib:spawn_link/3` or `proc_lib:start_link/3,4,5`. See below for an 82 | example. 83 | 84 | .Using gen_statem:enter_loop/4 to start a protocol 85 | 86 | [source,erlang] 87 | ---- 88 | -module(my_protocol). 89 | -behaviour(gen_statem). 90 | -behaviour(ranch_protocol). 91 | 92 | -export([start_link/3]). 93 | -export([init/1]). 94 | %% Exports of other gen_statem callbacks here. 95 | 96 | start_link(Ref, Transport, Opts) -> 97 | {ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Transport, Opts}])}. 98 | 99 | init({Ref, Transport, _Opts}) -> 100 | %% Perform any required state initialization here. 101 | {ok, Socket} = ranch:handshake(Ref), 102 | ok = Transport:setopts(Socket, [{active, once}]), 103 | gen_statem:enter_loop(?MODULE, [], state_name, {state_data, Socket, Transport}). 104 | 105 | %% Other gen_statem callbacks here. 106 | ---- 107 | 108 | ==== gen_server 109 | 110 | * Use `{continue, Continue}` in the return from `init/1` and place the 111 | `ranch:handshake/1,2` call in a corresponding `handle_continue/2` clause. 112 | * Use the `gen_server:enter_loop/3` function and start your process with 113 | `proc_lib:spawn_link/3` or `proc_lib:start_link/3,4,5`. 114 | -------------------------------------------------------------------------------- /doc/src/guide/ssl_auth.asciidoc: -------------------------------------------------------------------------------- 1 | == SSL client authentication 2 | 3 | === Purpose 4 | 5 | SSL client authentication is a mechanism allowing applications to 6 | identify certificates. This allows your application to make sure that 7 | the client is an authorized certificate, but makes no claim about 8 | whether the user can be trusted. This can be combined with a password 9 | based authentication to attain greater security. 10 | 11 | The server only needs to retain the certificate serial number and 12 | the certificate issuer to authenticate the certificate. Together, 13 | they can be used to uniquely identify a certificate. 14 | 15 | As Ranch allows the same protocol code to be used for both SSL and 16 | non-SSL transports, you need to make sure you are in an SSL context 17 | before attempting to perform an SSL client authentication. This 18 | can be done by checking the return value of `Transport:name/0`. 19 | 20 | === Obtaining client certificates 21 | 22 | You can obtain client certificates from various sources. You can 23 | generate them yourself, or you can use a service like CAcert.org 24 | which allows you to generate client and server certificates for 25 | free. 26 | 27 | Following are the steps you need to take to create a CAcert.org 28 | account, generate a certificate and install it in your favorite 29 | browser. 30 | 31 | * Open http://cacert.org in your favorite browser 32 | * Root Certificate link: install both certificates 33 | * Join (Register an account) 34 | * Verify your account (check your email inbox!) 35 | * Log in 36 | * Client Certificates: New 37 | * Follow instructions to create the certificate 38 | * Install the certificate in your browser 39 | 40 | You can optionally save the certificate for later use, for example 41 | to extract the `IssuerID` information as will be detailed later on. 42 | 43 | === Transport configuration 44 | 45 | The SSL transport does not request a client certificate by default. 46 | You need to specify the `{verify, verify_peer}` option when starting 47 | the listener to enable this behavior. 48 | 49 | .Configure a listener for SSL authentication 50 | 51 | [source,erlang] 52 | {ok, _} = ranch:start_listener(my_ssl, 53 | ranch_ssl, #{socket_opts => [ 54 | {port, SSLPort}, 55 | {certfile, PathToCertfile}, 56 | {cacertfile, PathToCACertfile}, 57 | {verify, verify_peer} 58 | ]}, 59 | my_protocol, [] 60 | ). 61 | 62 | In this example we set the required `port` and `certfile`, but also 63 | the `cacertfile` containing the CACert.org root certificate, and 64 | the option to request the client certificate. 65 | 66 | If you enable the `{verify, verify_peer}` option and the client does 67 | not have a client certificate configured for your domain, then no 68 | certificate will be sent. This allows you to use SSL for more than 69 | just authenticated clients. 70 | 71 | === Authentication 72 | 73 | To authenticate users, you must first save the certificate information 74 | required. If you have your users' certificate files, you can simply 75 | load the certificate and retrieve the information directly. 76 | 77 | .Retrieve the issuer ID from a certificate 78 | 79 | [source,erlang] 80 | ---- 81 | certfile_to_issuer_id(Filename) -> 82 | {ok, Data} = file:read_file(Filename), 83 | [{'Certificate', Cert, not_encrypted}] = public_key:pem_decode(Data), 84 | {ok, IssuerID} = public_key:pkix_issuer_id(Cert, self), 85 | IssuerID. 86 | ---- 87 | 88 | The `IssuerID` variable contains both the certificate serial number 89 | and the certificate issuer stored in a tuple, so this value alone can 90 | be used to uniquely identify the user certificate. You can save this 91 | value in a database, a configuration file or any other place where an 92 | Erlang term can be stored and retrieved. 93 | 94 | To retrieve the `IssuerID` from a running connection, you need to first 95 | retrieve the client certificate and then extract this information from 96 | it. Ranch does not provide a function to retrieve the client certificate. 97 | Instead you can use the `ssl:peercert/1` function. Once you have the 98 | certificate, you can again use the `public_key:pkix_issuer_id/2` to 99 | extract the `IssuerID` value. 100 | 101 | The following function returns the `IssuerID` or `false` if no client 102 | certificate was found. This snippet is intended to be used from your 103 | protocol code. 104 | 105 | .Retrieve the issuer ID from the certificate for the current connection 106 | 107 | [source,erlang] 108 | ---- 109 | socket_to_issuer_id(Socket) -> 110 | case ssl:peercert(Socket) of 111 | {error, no_peercert} -> 112 | false; 113 | {ok, Cert} -> 114 | {ok, IssuerID} = public_key:pkix_issuer_id(Cert, self), 115 | IssuerID 116 | end. 117 | ---- 118 | 119 | You then only need to match the `IssuerID` value to authenticate the 120 | user. 121 | -------------------------------------------------------------------------------- /doc/src/guide/transports.asciidoc: -------------------------------------------------------------------------------- 1 | == Transports 2 | 3 | A transport defines the interface to interact with a socket. 4 | 5 | Transports can be used for connecting, listening and accepting 6 | connections, but also for receiving and sending data. Both 7 | passive and active mode are supported, although all sockets 8 | are initialized as passive. 9 | 10 | === TCP transport 11 | 12 | The TCP transport is a thin wrapper around `gen_tcp`. 13 | 14 | === SSL transport 15 | 16 | The SSL transport is a thin wrapper around `ssl`. 17 | 18 | Ranch depends on `ssl` by default so any necessary 19 | dependencies will start when Ranch is started. It is 20 | possible to remove the dependency when the SSL transport 21 | will not be used. Refer to your release build tool's 22 | documentation for more information. 23 | 24 | When embedding Ranch listeners that have an SSL transport, 25 | your application must depend on the `ssl` application for 26 | proper behavior. 27 | 28 | === Sending and receiving data 29 | 30 | This section assumes that `Transport` is a valid transport handler 31 | (like `ranch_tcp` or `ranch_ssl`) and `Socket` is a connected 32 | socket obtained through the listener. 33 | 34 | You can send data to a socket by calling the `Transport:send/2` 35 | function. The data can be given as `iodata()`, which is defined as 36 | `binary() | iolist()`. All the following calls will work: 37 | 38 | .Sending data to the socket 39 | 40 | [source,erlang] 41 | ---- 42 | Transport:send(Socket, <<"Ranch is cool!">>). 43 | Transport:send(Socket, "Ranch is cool!"). 44 | Transport:send(Socket, ["Ranch", ["is", "cool!"]]). 45 | Transport:send(Socket, ["Ranch", [<<"is">>, "cool!"]]). 46 | ---- 47 | 48 | You can receive data either in passive or in active mode. Passive mode 49 | means that you will perform a blocking `Transport:recv/3` call, while 50 | active mode means that you will receive the data as a message. 51 | 52 | By default, all data will be received as binary. It is possible to 53 | receive data as strings, although this is not recommended as binaries 54 | are a more efficient construct, especially for binary protocols. 55 | 56 | Receiving data using passive mode requires a single function call. The 57 | first argument is the socket, and the third argument is a timeout duration 58 | before the call returns with `{error, timeout}`. 59 | 60 | The second argument is the amount of data in bytes that we want to receive. 61 | The function will wait for data until it has received exactly this amount. 62 | If you are not expecting a precise size, you can specify 0 which will make 63 | this call return as soon as data was read, regardless of its size. 64 | 65 | .Receiving data from the socket in passive mode 66 | 67 | [source,erlang] 68 | {ok, Data} = Transport:recv(Socket, 0, 5000). 69 | 70 | Active mode requires you to inform the socket that you want to receive 71 | data as a message and to write the code to actually receive it. 72 | 73 | There are three kinds of active modes: `{active, once}`, `{active, N}` 74 | and `{active, true}`. The first will send a single message before going 75 | back to passive mode; the second will send `N` messages followed by 76 | a `Passive` message when switching back to passive mode; the third 77 | will send messages indefinitely. We recommend not using the `{active, true}` 78 | mode as it could quickly flood your process mailbox. It's better to keep 79 | the data in the socket and read it only when required. 80 | 81 | Four different messages can be received: 82 | 83 | * Incoming data: `{OK, Socket, Data}` 84 | * Socket closed: `{Closed, Socket}` 85 | * Socket error: `{Error, Socket, Reason}` 86 | * Switch to passive mode: `{Passive, Socket}` 87 | 88 | The value of `OK`, `Closed`, `Error` and `Passive` can be different 89 | depending on the transport being used. To be able to properly match 90 | on them you must first call the `Transport:messages/0` function. 91 | 92 | .Retrieving the transport's active message identifiers 93 | 94 | [source,erlang] 95 | {OK, Closed, Error, Passive} = Transport:messages(). 96 | 97 | To start receiving messages you will need to call the `Transport:setopts/2` 98 | function, and do so every time you want to receive data. 99 | 100 | .Receiving messages from the socket in active mode 101 | 102 | [source,erlang] 103 | ---- 104 | {OK, Closed, Error, Passive} = Transport:messages(), 105 | Transport:setopts(Socket, [{active, once}]), 106 | receive 107 | {OK, Socket, Data} -> 108 | io:format("data received: ~p~n", [Data]); 109 | {Closed, Socket} -> 110 | io:format("socket got closed!~n"); 111 | {Error, Socket, Reason} -> 112 | io:format("error happened: ~p~n", [Reason]) 113 | end. 114 | ---- 115 | 116 | You can easily integrate active sockets with existing Erlang code as all 117 | you really need is just a few more clauses when receiving messages. 118 | 119 | === Sending files 120 | 121 | As in the previous section it is assumed `Transport` is a valid transport 122 | handler and `Socket` is a connected socket obtained through the listener. 123 | 124 | To send a whole file, with name `Filename`, over a socket: 125 | 126 | .Sending a file by filename 127 | 128 | [source,erlang] 129 | {ok, SentBytes} = Transport:sendfile(Socket, Filename). 130 | 131 | Or part of a file, with `Offset` greater than or equal to 0, `Bytes` number of 132 | bytes and chunks of size `ChunkSize`: 133 | 134 | .Sending part of a file by filename in chunks 135 | 136 | [source,erlang] 137 | Opts = [{chunk_size, ChunkSize}], 138 | {ok, SentBytes} = Transport:sendfile(Socket, Filename, Offset, Bytes, Opts). 139 | 140 | To improve efficiency when sending multiple parts of the same file it is also 141 | possible to use a file descriptor opened in raw mode: 142 | 143 | .Sending a file opened in raw mode 144 | 145 | [source,erlang] 146 | {ok, RawFile} = file:open(Filename, [raw, read, binary]), 147 | {ok, SentBytes} = Transport:sendfile(Socket, RawFile, Offset, Bytes, Opts). 148 | 149 | === Upgrading a TCP socket to SSL 150 | 151 | A connected TCP socket can be upgraded to a SSL socket via the function 152 | `ranch_ssl:handshake/3`. The socket *must* be in `{active, false}` mode 153 | before telling the client that the server is ready to upgrade in order 154 | to avoid race conditions. 155 | 156 | IMPORTANT: The new socket received from `ranch_ssl:handshake/3` must be 157 | used via the `ranch_ssl` transport. 158 | 159 | .Performing a TLS handshake on a TCP socket 160 | [source,erlang] 161 | {ok, SslSocket} = ranch_ssl:handshake(TcpSocket, SslOpts, 5000). 162 | 163 | === Writing a transport handler 164 | 165 | A transport handler is a module implementing the `ranch_transport` behavior. 166 | It defines a certain number of callbacks that must be written in order to 167 | allow transparent usage of the transport handler. 168 | 169 | The behavior doesn't define the socket options available when opening a 170 | socket. These do not need to be common to all transports as it's easy enough 171 | to write different initialization functions for the different transports that 172 | will be used. With one exception though. The `setopts/2` function *must* 173 | implement the `{active, once}` and the `{active, true}` options. 174 | 175 | If the transport handler doesn't have a native implementation of `sendfile/5` a 176 | fallback is available, `ranch_transport:sendfile/6`. The extra first argument 177 | is the transport's module. See `ranch_ssl` for an example. 178 | 179 | It is highly recommended for a custom transport handler to implement the 180 | optional `format_error/1` callback, in order to provide a human-readable 181 | diagnostic string. Implementing this callback will become mandatory in 182 | Ranch 3.0. 183 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch(3) 2 | 3 | == Name 4 | 5 | ranch - Socket acceptor pool 6 | 7 | == Description 8 | 9 | The module `ranch` provides functions for starting and 10 | manipulating Ranch listeners. 11 | 12 | == Exports 13 | 14 | Start/stop: 15 | 16 | * link:man:ranch:start_listener(3)[ranch:start_listener(3)] - Start a listener 17 | * link:man:ranch:stop_listener(3)[ranch:stop_listener(3)] - Stop a listener 18 | * link:man:ranch:child_spec(3)[ranch:child_spec(3)] - Build child specifications for a new listener 19 | 20 | Suspend/resume: 21 | 22 | * link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)] - Suspend a running listener 23 | * link:man:ranch:resume_listener(3)[ranch:resume_listener(3)] - Resume a suspended listener 24 | * link:man:ranch:get_status(3)[ranch:get_status(3)] - Get a listener's running state 25 | 26 | Connections: 27 | 28 | * link:man:ranch:handshake(3)[ranch:handshake(3)] - Perform the transport handshake 29 | * link:man:ranch:handshake_continue(3)[ranch:handshake_continue(3)] - Resume the paused transport handshake 30 | * link:man:ranch:handshake_cancel(3)[ranch:handshake_cancel(3)] - Cancel the paused transport handshake 31 | * link:man:ranch:recv_proxy_header(3)[ranch:recv_proxy_header(3)] - Receive the PROXY protocol header 32 | * link:man:ranch:remove_connection(3)[ranch:remove_connection(3)] - Remove connection from the count 33 | 34 | Options: 35 | 36 | * link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)] - Get the max number of connections per connection supervisor 37 | * link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)] - Get the current protocol options 38 | * link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)] - Get the current transport options 39 | * link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)] - Set the max number of connections per connection supervisor 40 | * link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)] - Set the protocol options 41 | * link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)] - Set the transport options 42 | 43 | Introspection: 44 | 45 | * link:man:ranch:get_addr(3)[ranch:get_addr(3)] - Get the listening address 46 | * link:man:ranch:get_port(3)[ranch:get_port(3)] - Get the listening port 47 | * link:man:ranch:info(3)[ranch:info(3)] - Overview of Ranch listeners 48 | * link:man:ranch:procs(3)[ranch:procs(3)] - Retrieve pids from a listener 49 | * link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)] - Wait for a specific number of connections 50 | 51 | == Types 52 | 53 | === max_conns() 54 | 55 | [source,erlang] 56 | ---- 57 | max_conns() = non_neg_integer() | infinity 58 | ---- 59 | 60 | Maximum number of connections allowed per connection supervisor. 61 | 62 | This is a soft limit. The actual number of connections 63 | might be slightly above the limit due to concurrency 64 | when accepting new connections. Some connections may 65 | also be removed from this count explicitly by the user 66 | code. 67 | 68 | === opts() 69 | 70 | [source,erlang] 71 | ---- 72 | opts() = any() | transport_opts(any()) 73 | ---- 74 | 75 | Transport or socket options. 76 | 77 | === ref() 78 | 79 | [source,erlang] 80 | ---- 81 | ref() = any() 82 | ---- 83 | 84 | Unique name used to refer to a listener. 85 | 86 | === transport_opts(SocketOpts) 87 | 88 | [source,erlang] 89 | ---- 90 | transport_opts(SocketOpts) = #{ 91 | alarms => #{ 92 | term() => #{ 93 | type := num_connections, 94 | threshold := non_neg_integer(), 95 | callback := fun((ref(), term(), pid(), [pid()]) -> any()), 96 | cooldown => non_neg_integer() 97 | } 98 | }, 99 | connection_type => worker | supervisor, 100 | handshake_timeout => timeout(), 101 | max_connections => max_conns(), 102 | logger => module(), 103 | num_acceptors => pos_integer(), 104 | num_conns_sups => pos_integer(), 105 | post_listen_callback => fun((term()) -> ok | {error, term()}), 106 | shutdown => timeout() | brutal_kill, 107 | socket_opts => SocketOpts 108 | } 109 | ---- 110 | 111 | Transport options. 112 | 113 | The transport options are a combination of Ranch-specific 114 | options and transport-specific socket options. 115 | 116 | None of the options are required. 117 | 118 | alarms (#{}):: 119 | 120 | Alarms to call a function when the number of connections tracked 121 | by one connection supervisor reaches or exceeds a defined threshold. 122 | + 123 | The map keys are the alarm names, which can be any `term`. The 124 | associated values are the respective alarm options, again in a map 125 | with the following keys: 126 | 127 | type::: 128 | 129 | Must be set to `num_connections`. 130 | 131 | threshold::: 132 | 133 | Threshold value, which must be a `non_neg_integer`. When the 134 | number of connections tracked by a single connection supervisor 135 | reaches or exceeds this value, The alarm will trigger and call 136 | the function defined in the `callback` key (see below). 137 | 138 | callback::: 139 | 140 | The alarm function, which takes the listener name, the alarm 141 | name, the pid of the connection supervisor and a list of the pids 142 | of all connection processes under that supervisor as arguments. 143 | The return value is ignored. 144 | 145 | cooldown (5000)::: 146 | 147 | The minimum time after which the alarm can be triggered again, 148 | in milliseconds. 149 | 150 | connection_type (worker):: 151 | 152 | Type of process that will handle the connection. 153 | 154 | handshake_timeout (5000):: 155 | 156 | Maximum allowed time for the `ranch:handshake/1,2` call to finish. 157 | 158 | logger (logger):: 159 | 160 | The module that will be used to write log messages. 161 | 162 | max_connections (1024):: 163 | 164 | Maximum number of active connections per connection supervisor. 165 | Soft limit. Use `infinity` to disable the limit entirely. 166 | 167 | num_acceptors (10):: 168 | 169 | Number of processes that accept connections. 170 | 171 | num_conns_sups - see below:: 172 | 173 | Number of processes that supervise connection processes. 174 | If not specified, defaults to be equal to `num_acceptors`. 175 | 176 | post_listen_callback (fun(_ListenSock) -> ok end):: 177 | 178 | A function which will be called after a listen socket has been successfully 179 | created, with the socket as argument. It can be used to perform any 180 | necessary setup steps on the socket. 181 | + 182 | If the callback function returns `ok`, the listener will start accepting 183 | connections on the socket. If it returns `{error, Reason}`, the listener 184 | will fail to start. 185 | 186 | shutdown (5000):: 187 | 188 | Maximum allowed time for children to stop on listener shutdown. 189 | 190 | socket_opts:: 191 | 192 | Socket options to be used by `Transport:listen/1`. Please refer to the 193 | documentation of the transport module you are using for more details. 194 | 195 | == Changelog 196 | 197 | * *2.1*: The `post_listen_callback` transport option was added. 198 | * *2.0*: The type `transport_opts(SocketOpts)` was added. 199 | * *2.0*: The function `ranch:accept_ack/1` was removed in favor of 200 | link:man:ranch:handshake(3)[ranch:handshake(3)]. 201 | * *2.0*: The option `max_connections` is now per connection supervisor. 202 | * *2.0*: The `num_conns_sup` option was added. 203 | * *2.0*: The `socket` option was removed. 204 | * *2.0*: The `logger` option is no longer experimental. It now defaults 205 | to `logger` instead of `error_logger`. 206 | * *2.0*: The `opt()` type was removed. 207 | * *1.6*: The experimental `logger` option was added. 208 | * *1.6*: The `opt()` type was deprecated in favor of the new `opts()` type. 209 | 210 | == See also 211 | 212 | link:man:ranch(7)[ranch(7)] 213 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.child_spec.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:child_spec(3) 2 | 3 | == Name 4 | 5 | ranch:child_spec - Build child specifications for a new listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | child_spec(Ref :: ranch_ref(), 12 | Transport :: module(), 13 | TransOpts :: ranch:opts(), 14 | Protocol :: module(), 15 | ProtoOpts :: any()) 16 | -> supervisor:child_spec() 17 | ---- 18 | 19 | Build child specifications for a new listener which can 20 | be embedded directly in an application's supervision 21 | tree. 22 | 23 | The actual listener is placed under a supervisor which 24 | monitors `ranch_server` via a proxy process and will 25 | restart the listener if `ranch_server` crashes. 26 | 27 | == Arguments 28 | 29 | Ref:: 30 | 31 | The listener name is used to refer to this listener in 32 | future calls, for example when updating the configuration. 33 | + 34 | It can be any Erlang term. An atom is generally good enough, 35 | for example `api`, `my_app_clear` or `my_app_tls`. 36 | 37 | Transport:: 38 | 39 | The transport module that will be used by Ranch to accept 40 | connections and that will be passed to the protocol module 41 | along with the socket. 42 | + 43 | The interface of the transport module is documented in the 44 | link:man:ranch_transport(3)[ranch_transport(3)] manual. 45 | 46 | TransportOpts:: 47 | 48 | Transport options include the Ranch-specific options 49 | and the socket options. The listener's port number must 50 | be defined in the socket options. 51 | + 52 | The available options for the built-in Ranch transports 53 | are documented in the link:man:ranch_tcp(3)[ranch_tcp(3)] 54 | and link:man:ranch_ssl(3)[ranch_ssl(3)] manuals. 55 | 56 | Protocol:: 57 | 58 | The protocol module that will be used by Ranch after 59 | the connection has been accepted. 60 | + 61 | The interface of the protocol module is documented in the 62 | link:man:ranch_protocol(3)[ranch_protocol(3)] manual. 63 | 64 | ProtocolOpts:: 65 | 66 | The protocol options given when calling the protocol 67 | module. Please consult the documentation of the protocol 68 | module you are using for more details. 69 | 70 | == Return value 71 | 72 | Child specifications are returned. 73 | 74 | == Changelog 75 | 76 | * *2.0*: The actual listener is placed under a supervisor in order to 77 | restart the listener if `ranch_server` crashes. 78 | * *2.0*: The `TransOpts` argument must no longer contain 79 | Ranch-specific options if given as a list. Use a map. 80 | * *1.4*: The `NumAcceptors` argument was moved to the transport options. 81 | 82 | == Examples 83 | 84 | .Embed a listener 85 | [source,erlang] 86 | ---- 87 | -behavior(supervisor). 88 | 89 | init(_) -> 90 | {ok, {#{strategy => one_for_one}, [ 91 | ranch:child_spec(echo, 92 | ranch_tcp, [{port, 5555}], 93 | echo_protocol, [] 94 | ) 95 | ]}}. 96 | ---- 97 | 98 | == See also 99 | 100 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 101 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 102 | link:man:ranch(3)[ranch(3)], 103 | link:man:ranch_tcp(3)[ranch_tcp(3)], 104 | link:man:ranch_ssl(3)[ranch_ssl(3)], 105 | link:man:ranch_transport(3)[ranch_transport(3)], 106 | link:man:ranch_protocol(3)[ranch_protocol(3)] 107 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_addr.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_addr(3) 2 | 3 | == Name 4 | 5 | ranch:get_addr - Get the listening address 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_addr(Ref :: ranch:ref()) 12 | -> {IP :: inet:ip_address(), 13 | Port :: inet:port_number()} 14 | | {local, SocketFile :: binary()} 15 | | {undefined, undefined} 16 | ---- 17 | 18 | Get the listening address. 19 | 20 | == Arguments 21 | 22 | Ref:: 23 | 24 | The listener name. 25 | 26 | == Return value 27 | 28 | The address of the listener is returned as a tuple of the form 29 | `{IP, Port}` when listening on a network interface, or 30 | `{local, SocketFile}` when listening on a UNIX Domain socket. 31 | When the listener is suspended, `{undefined, undefined}` will 32 | be returned. 33 | 34 | The IP address is the IP of the network interface the 35 | socket is bound to. 36 | 37 | The socket file is the path of a file on your system the 38 | socket is bound to. 39 | 40 | == Examples 41 | 42 | .Get the listening port and IP 43 | [source,erlang] 44 | ---- 45 | {IP, Port} = ranch:get_addr(example). 46 | ---- 47 | 48 | .Get the listening UNIX Domain socket file 49 | [source,erlang] 50 | ---- 51 | {local, SocketFile} = ranch:get_addr(example). 52 | ---- 53 | 54 | == See also 55 | 56 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 57 | link:man:ranch:get_port(3)[ranch:get_port(3)], 58 | link:man:ranch:info(3)[ranch:info(3)], 59 | link:man:ranch(3)[ranch(3)] 60 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_max_connections.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_max_connections(3) 2 | 3 | == Name 4 | 5 | ranch:get_max_connections - Get the max number of connections per connection supervisor 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_max_connections(Ref :: ranch:ref()) 12 | -> MaxConns :: ranch:max_conns() 13 | ---- 14 | 15 | Get the max number of connections per connection supervisor. 16 | 17 | == Arguments 18 | 19 | Ref:: 20 | 21 | The listener name. 22 | 23 | == Return value 24 | 25 | The maximum number of connections per connection supervisor 26 | is returned. 27 | 28 | == Changelog 29 | 30 | * *2.0*: The maximum number of connections is now per connection supervisor. 31 | 32 | == Examples 33 | 34 | .Get the max number of connections per connection supervisor 35 | [source,erlang] 36 | ---- 37 | MaxConns = ranch:get_max_connections(example). 38 | ---- 39 | 40 | == See also 41 | 42 | link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)], 43 | link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)], 44 | link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)], 45 | link:man:ranch(3)[ranch(3)] 46 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_port.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_port(3) 2 | 3 | == Name 4 | 5 | ranch:get_port - Get the listening port 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_port(Ref :: ranch:ref()) 12 | -> Port :: inet:port_number() | undefined 13 | ---- 14 | 15 | Get the listening port. 16 | 17 | This function is particularly useful to retrieve the 18 | listening port number when it was not provided in the 19 | options and was chosen randomly instead. 20 | 21 | == Arguments 22 | 23 | Ref:: 24 | 25 | The listener name. 26 | 27 | == Return value 28 | 29 | The listening port is returned. 30 | 31 | When the listener is suspended or using a UNIX Domain 32 | socket instead of a network interface, `undefined` 33 | will be returned. 34 | 35 | == Examples 36 | 37 | .Get the listening port 38 | [source,erlang] 39 | ---- 40 | Port = ranch:get_port(example). 41 | ---- 42 | 43 | == See also 44 | 45 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 46 | link:man:ranch:get_addr(3)[ranch:get_addr(3)], 47 | link:man:ranch:info(3)[ranch:info(3)], 48 | link:man:ranch(3)[ranch(3)] 49 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_protocol_options.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_protocol_options(3) 2 | 3 | == Name 4 | 5 | ranch:get_protocol_options - Get the current protocol options 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_protocol_options(Ref :: ranch:ref()) 12 | -> ProtoOpts :: any() 13 | ---- 14 | 15 | Get the current protocol options. 16 | 17 | == Arguments 18 | 19 | Ref:: 20 | 21 | The listener name. 22 | 23 | == Return value 24 | 25 | The current protocol options are returned. 26 | 27 | == Examples 28 | 29 | .Get the current protocol options 30 | [source,erlang] 31 | ---- 32 | ProtoOpts = ranch:get_protocol_options(example). 33 | ---- 34 | 35 | == See also 36 | 37 | link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)], 38 | link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)], 39 | link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)], 40 | link:man:ranch(3)[ranch(3)] 41 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_status.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_status(3) 2 | 3 | == Name 4 | 5 | ranch:get_status - Get a listener's running state 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_status(Ref :: ranch_ref()) -> running | suspended 12 | ---- 13 | 14 | Get a listener's running state. 15 | 16 | == Arguments 17 | 18 | Ref:: 19 | 20 | The listener name. 21 | 22 | == Return value 23 | 24 | An atom is returned indicating the running status of the listener. 25 | 26 | == Changelog 27 | 28 | * *1.6*: Function introduced. 29 | 30 | == Examples 31 | 32 | .Get a listener's running state 33 | [source,erlang] 34 | ---- 35 | ranch:get_status(example). 36 | ---- 37 | 38 | == See also 39 | 40 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 41 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 42 | link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)], 43 | link:man:ranch:resume_listener(3)[ranch:resume_listener(3)], 44 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 45 | link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)], 46 | link:man:ranch(3)[ranch(3)] 47 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.get_transport_options.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:get_transport_options(3) 2 | 3 | == Name 4 | 5 | ranch:get_transport_options - Get the current transport options 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | get_transport_options(Ref :: ranch:ref()) 12 | -> TransOpts :: ranch:transport_opts(any()) 13 | ---- 14 | 15 | Get the current transport options. 16 | 17 | == Arguments 18 | 19 | Ref:: 20 | 21 | The listener name. 22 | 23 | == Return value 24 | 25 | The current transport options are returned. 26 | 27 | == Examples 28 | 29 | .Get the current transport options 30 | [source,erlang] 31 | ---- 32 | TransOpts = ranch:get_transport_options(example). 33 | ---- 34 | 35 | == See also 36 | 37 | link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)], 38 | link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)], 39 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 40 | link:man:ranch(3)[ranch(3)] 41 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.handshake.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:handshake(3) 2 | 3 | == Name 4 | 5 | ranch:handshake - Perform the transport handshake 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | handshake(Ref) -> {ok, Socket} | {continue, Info} 12 | handshake(Ref, Opts) -> {ok, Socket} | {continue, Info} 13 | 14 | Ref :: ranch:ref() 15 | Opts :: any() 16 | Socket :: any() 17 | Info :: any() 18 | ---- 19 | 20 | Perform the transport handshake. 21 | 22 | This function must be called by the protocol process in order 23 | to retrieve the socket for the connection. Ranch performs the 24 | handshake necessary to give control of the socket to this 25 | process and also does the transport handshake, for example 26 | setting up the TLS connection. 27 | 28 | == Arguments 29 | 30 | Ref:: 31 | 32 | The listener name. 33 | 34 | Opts:: 35 | 36 | Transport handshake options. 37 | + 38 | Allowed options depend on the transport module. 39 | 40 | == Return value 41 | 42 | An `ok` tuple is returned containing the socket for the connection 43 | by default. 44 | 45 | Depending on configuration, a `continue` tuple can otherwise 46 | be returned when the handshake operation is paused. It contains 47 | data provided by the transport that can be used to inform further 48 | decisions before resuming the handshake, for example to provide 49 | new transport options. The handshake can be resumed using 50 | link:man:ranch:handshake_continue(3)[ranch:handshake_continue(3)] 51 | or canceled using 52 | link:man:ranch:handshake_cancel(3)[ranch:handshake_cancel(3)]. 53 | 54 | This function will trigger an exception when an error occurs. 55 | 56 | == Changelog 57 | 58 | * *2.0*: The `continue` tuple can now be returned. 59 | * *1.6*: Function introduced. Replaces `ranch:accept_ack/1`. 60 | 61 | == Examples 62 | 63 | .Initialize the connection process 64 | [source,erlang] 65 | ---- 66 | start_link(Ref, Transport, Opts) -> 67 | Pid = proc_lib:spawn_link(?MODULE, init, 68 | [Ref, Transport, Opts]), 69 | {ok, Pid}. 70 | 71 | init(Ref, Transport, Opts) -> 72 | {ok, Socket} = ranch:handshake(Ref), 73 | loop(#state{ref=Ref, socket=Socket, 74 | transport=Transport, opts=Opts}). 75 | ---- 76 | 77 | == See also 78 | 79 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 80 | link:man:ranch:handshake_continue(3)[ranch:handshake_continue(3)], 81 | link:man:ranch:handshake_cancel(3)[ranch:handshake_cancel(3)], 82 | link:man:ranch:recv_proxy_header(3)[ranch:recv_proxy_header(3)], 83 | link:man:ranch:remove_connection(3)[ranch:remove_connection(3)], 84 | link:man:ranch(3)[ranch(3)] 85 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.handshake_cancel.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:handshake_cancel(3) 2 | 3 | == Name 4 | 5 | ranch:handshake_cancel - Cancel the paused transport handshake 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | handshake_cancel(Ref :: ranch:ref()) -> ok 12 | ---- 13 | 14 | Cancel the paused transport handshake. 15 | 16 | This function may be called by the protocol process 17 | to cancel a paused handshake. 18 | 19 | == Arguments 20 | 21 | Ref:: 22 | 23 | The listener name. 24 | + 25 | Allowed options depend on the transport module. 26 | 27 | == Return value 28 | 29 | The return value depends on the transport module. 30 | 31 | == Changelog 32 | 33 | * *2.0*: Function introduced. 34 | 35 | == Examples 36 | 37 | .Cancel a paused transport handshake 38 | [source,erlang] 39 | ---- 40 | start_link(Ref, Transport, Opts) -> 41 | Pid = proc_lib:spawn_link(?MODULE, init, 42 | [Ref, Transport, Opts]), 43 | {ok, Pid}. 44 | 45 | init(Ref, Transport, Opts) -> 46 | {continue, _Info} = ranch:handshake(Ref), 47 | ranch:handshake_cancel(Ref), 48 | exit(handshake_cancelled). 49 | ---- 50 | 51 | == See also 52 | 53 | link:man:ranch:handshake(3)[ranch:handshake(3)], 54 | link:man:ranch:handshake_continue(3)[ranch:handshake_continue(3)], 55 | link:man:ranch(3)[ranch(3)] 56 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.handshake_continue.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:handshake_continue(3) 2 | 3 | == Name 4 | 5 | ranch:handshake_continue - Resume the paused transport handshake 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | handshake_continue(Ref) -> {ok, Socket} 12 | handshake_continue(Ref, Opts) -> {ok, Socket} 13 | 14 | Ref :: ranch:ref() 15 | Opts :: any() 16 | Socket :: any() 17 | ---- 18 | 19 | Resume the paused transport handshake. 20 | 21 | This function must be called by the protocol process in order 22 | to resume a paused handshake. 23 | 24 | == Arguments 25 | 26 | Ref:: 27 | 28 | The listener name. 29 | 30 | Opts:: 31 | 32 | Transport handshake options. 33 | + 34 | Allowed options depend on the transport module. 35 | 36 | == Return value 37 | 38 | An `ok` tuple is returned containing the socket for the connection. 39 | 40 | This function will trigger an exception when an error occurs. 41 | 42 | == Changelog 43 | 44 | * *2.0*: Function introduced. 45 | 46 | == Examples 47 | 48 | .Continue a paused transport handshake 49 | [source,erlang] 50 | ---- 51 | start_link(Ref, Transport, Opts) -> 52 | Pid = proc_lib:spawn_link(?MODULE, init, 53 | [Ref, Transport, Opts]), 54 | {ok, Pid}. 55 | 56 | init(Ref, Transport, Opts) -> 57 | {continue, _Info} = ranch:handshake(Ref), 58 | {ok, Socket} = ranch:handshake_continue(Ref), 59 | loop(#state{ref=Ref, socket=Socket, 60 | transport=Transport, opts=Opts}). 61 | ---- 62 | 63 | == See also 64 | 65 | link:man:ranch:handshake(3)[ranch:handshake(3)], 66 | link:man:ranch:handshake_cancel(3)[ranch:handshake_cancel(3)], 67 | link:man:ranch(3)[ranch(3)] 68 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.info.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:info(3) 2 | 3 | == Name 4 | 5 | ranch:info - Overview of Ranch listeners 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | info() -> #{Ref := Info} 12 | info(Ref) -> Info 13 | 14 | Info :: #{Key :: atom() := Value :: any()} 15 | ---- 16 | 17 | Overview of Ranch listeners. 18 | 19 | == Arguments 20 | 21 | Ref:: 22 | 23 | The listener name. 24 | 25 | == Return value 26 | 27 | Returns detailed information about one or all 28 | Ranch listeners. The following keys are returned: 29 | 30 | pid:: Pid of the listener's top-level supervisor. 31 | status:: Listener status, either running or suspended. 32 | ip:: Interface Ranch listens on. 33 | port:: Port number Ranch listens on. 34 | max_connections:: Maximum number of connections per connection supervisor. 35 | active_connections:: Number of active connections. 36 | all_connections:: Number of connections, including those removed from the count. 37 | transport:: Transport module. 38 | transport_options:: Transport options. 39 | protocol:: Protocol module. 40 | protocol_options:: Protocol options. 41 | metrics:: Listener metrics. 42 | 43 | == Metrics 44 | 45 | Listener metrics are provided as a map, with the following keys: 46 | 47 | {conns_sup, Index, accept}:: Number of accepted connections, per connection supervisor. 48 | {conns_sup, Index, terminate}:: Number of terminated connection processes, per connection supervisor. 49 | 50 | == Changelog 51 | 52 | * *2.1*: Added accept/terminate metrics to the output of `ranch:info/0,1`. 53 | * *2.0*: The listener info is now returned as a map. 54 | * *2.0*: The `num_acceptors` key has been removed. 55 | 56 | == Examples 57 | 58 | .Get information about all listeners 59 | [source,erlang] 60 | ---- 61 | AllInfo = ranch:info(). 62 | ---- 63 | 64 | .Get information about a specific listener 65 | [source,erlang] 66 | ---- 67 | Info = ranch:info(example). 68 | ---- 69 | 70 | == See also 71 | 72 | link:man:ranch:get_addr(3)[ranch:get_addr(3)], 73 | link:man:ranch:get_port(3)[ranch:get_port(3)], 74 | link:man:ranch:procs(3)[ranch:procs(3)], 75 | link:man:ranch(3)[ranch(3)] 76 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.procs.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:procs(3) 2 | 3 | == Name 4 | 5 | ranch:procs - Retrieve pids from a listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | procs(Ref :: ranch:ref(), 12 | Type :: acceptors | connections) 13 | -> Pids :: [pid()] 14 | ---- 15 | 16 | Retrieve pids from a listener. 17 | 18 | == Arguments 19 | 20 | Ref:: 21 | 22 | The listener name. 23 | 24 | Type:: 25 | 26 | The type of process that will be returned. 27 | 28 | == Return value 29 | 30 | A list of pids is returned. 31 | 32 | == Examples 33 | 34 | .Get the pids of the acceptor processes 35 | [source,erlang] 36 | ---- 37 | Pids = ranch:procs(acceptors). 38 | ---- 39 | 40 | .Get the pids of the connection processes 41 | [source,erlang] 42 | ---- 43 | Pids = ranch:procs(connections). 44 | ---- 45 | 46 | == See also 47 | 48 | link:man:ranch:get_addr(3)[ranch:get_addr(3)], 49 | link:man:ranch:get_port(3)[ranch:get_port(3)], 50 | link:man:ranch:info(3)[ranch:info(3)], 51 | link:man:ranch(3)[ranch(3)] 52 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.recv_proxy_header.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:recv_proxy_header(3) 2 | 3 | == Name 4 | 5 | ranch:recv_proxy_header - Receive the PROXY protocol header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | recv_proxy_header(ranch:ref(), timeout()) 12 | -> {ok, ranch_proxy_header:proxy_info()} 13 | | {error, Reason :: atom()} 14 | | {error, protocol_error, HumanReadable :: atom()} 15 | ---- 16 | 17 | Receive the PROXY protocol header. 18 | 19 | This function must be called before `ranch:handshake/1,2` 20 | on newly accepted connections to read and parse the PROXY 21 | protocol header, if any. 22 | 23 | == Arguments 24 | 25 | Ref:: 26 | 27 | The listener name. 28 | 29 | Timeout:: 30 | 31 | Receive timeout in milliseconds. 32 | 33 | == Return value 34 | 35 | An `ok` tuple is returned containing PROXY header information 36 | on success. 37 | 38 | An `error` 2-tuple is returned when a socket error occurs. 39 | 40 | An `error` 3-tuple is returned when a protocol error occurs 41 | and Ranch was not able to parse the PROXY header information. 42 | The third element contains a human-readable description of 43 | the error. 44 | 45 | == Changelog 46 | 47 | * *1.7*: Function introduced. 48 | 49 | == Examples 50 | 51 | .Receive the PROXY protocol header 52 | [source,erlang] 53 | ---- 54 | start_link(Ref, Transport, Opts) -> 55 | Pid = proc_lib:spawn_link(?MODULE, init, 56 | [Ref, Transport, Opts]), 57 | {ok, Pid}. 58 | 59 | init(Ref, Transport, Opts) -> 60 | {ok, ProxyInfo} = ranch:recv_proxy_header(Ref, 1000), 61 | {ok, Socket} = ranch:handshake(Ref), 62 | loop(#state{ref=Ref, socket=Socket, transport=Transport, 63 | proxy_info=ProxyInfo, opts=Opts}). 64 | ---- 65 | 66 | == See also 67 | 68 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 69 | link:man:ranch:handshake(3)[ranch:handshake(3)], 70 | link:man:ranch:remove_connection(3)[ranch:remove_connection(3)], 71 | link:man:ranch(3)[ranch(3)] 72 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.remove_connection.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:remove_connection(3) 2 | 3 | == Name 4 | 5 | ranch:remove_connection - Remove connection from the count 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | remove_connection(Ref :: ranch:ref()) -> ok 12 | ---- 13 | 14 | Remove connection from the count. 15 | 16 | This connection will no longer be included in the count when 17 | limiting the number of connections. This can be useful in a 18 | mixed environment where some connections are active and others 19 | are passive. Passive connections spend most of their time idling 20 | and are not consuming much resources. 21 | 22 | This function may only be called from a connection process. 23 | 24 | == Arguments 25 | 26 | Ref:: 27 | 28 | The listener name. 29 | 30 | == Return value 31 | 32 | The atom `ok` is always returned. It can be safely ignored. 33 | 34 | == Examples 35 | 36 | .Remove the connection process from the count 37 | [source,erlang] 38 | ---- 39 | ranch:remove_connection(example). 40 | ---- 41 | 42 | == See also 43 | 44 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 45 | link:man:ranch:handshake(3)[ranch:handshake(3)], 46 | link:man:ranch(3)[ranch(3)] 47 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.resume_listener.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:resume_listener(3) 2 | 3 | == Name 4 | 5 | ranch:resume_listener - Resume a suspended listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | resume_listener(Ref :: ranch_ref()) 12 | -> ok | {error, any()} 13 | ---- 14 | 15 | Resume a suspended listener. 16 | 17 | Ranch will start listening for and accepting connections 18 | again. The function 19 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)] 20 | can be used to change the transport options before resuming 21 | the listener. 22 | 23 | Nothing is done when the listener is already running. 24 | 25 | == Arguments 26 | 27 | Ref:: 28 | 29 | The listener name. 30 | 31 | == Return value 32 | 33 | The atom `ok` is returned on success. 34 | 35 | An error tuple is returned when the listener could not be restarted. 36 | 37 | == Changelog 38 | 39 | * *1.6*: Function introduced. 40 | 41 | == Examples 42 | 43 | .Resume a listener 44 | [source,erlang] 45 | ---- 46 | ok = ranch:resume_listener(example). 47 | ---- 48 | 49 | == See also 50 | 51 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 52 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 53 | link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)], 54 | link:man:ranch:get_status(3)[ranch:get_status(3)], 55 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 56 | link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)], 57 | link:man:ranch(3)[ranch(3)] 58 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.set_max_connections.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:set_max_connections(3) 2 | 3 | == Name 4 | 5 | ranch:set_max_connections - Set the max number of connections per connection supervisor 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | set_max_connections(Ref :: ranch:ref(), 12 | MaxConns :: ranch:max_conns()) 13 | -> ok 14 | ---- 15 | 16 | Set the max number of connections per connection supervisor. 17 | 18 | The change will be applied immediately. If the new value is 19 | smaller than the previous one, Ranch will wait for the extra 20 | connections to terminate and will not accept new connections 21 | until the number of connections goes below the limit. 22 | 23 | == Arguments 24 | 25 | Ref:: 26 | 27 | The listener name. 28 | 29 | MaxConns:: 30 | 31 | The new maximum number of connections per connection supervisor. 32 | 33 | == Return value 34 | 35 | The atom `ok` is always returned. It can be safely ignored. 36 | 37 | == Changelog 38 | 39 | * *2.0*: The maximum number of connections is now per connection supervisor. 40 | 41 | == Examples 42 | 43 | .Set the max number of connections per connection supervisor 44 | [source,erlang] 45 | ---- 46 | ranch:set_max_connections(example, 10000). 47 | ---- 48 | 49 | == See also 50 | 51 | link:man:ranch:get_max_connections(3)[ranch:get_max_connections(3)], 52 | link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)], 53 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 54 | link:man:ranch(3)[ranch(3)] 55 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.set_protocol_options.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:set_protocol_options(3) 2 | 3 | == Name 4 | 5 | ranch:set_protocol_options - Set the protocol options 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | set_protocol_options(Ref :: ranch:ref(), 12 | ProtoOpts :: any()) 13 | -> ok 14 | ---- 15 | 16 | Set the protocol options. 17 | 18 | The change will be applied immediately for all new connections. 19 | Old connections will not receive the new options. 20 | 21 | Note that the complete set of protocol options is replaced. To update a subset 22 | of the options, it is recommended to get the current protocol options using 23 | link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)], update 24 | them and then set them back using this function. 25 | 26 | == Arguments 27 | 28 | Ref:: 29 | 30 | The listener name. 31 | 32 | ProtoOpts:: 33 | 34 | The new protocol options. 35 | 36 | == Return value 37 | 38 | The atom `ok` is always returned. It can be safely ignored. 39 | 40 | == Examples 41 | 42 | .Set the protocol options 43 | [source,erlang] 44 | ---- 45 | ranch:set_protocol_options(example, ProtoOpts). 46 | ---- 47 | 48 | .Update some of the protocol options 49 | [source,erlang] 50 | ---- 51 | ProtoOpts0 = ranch:get_protocol_options(example), 52 | ProtoOpts = ProtoOpts0#{request_timeout => 2000}, 53 | ranch:set_protocol_options(example, ProtoOpts). 54 | ---- 55 | 56 | == See also 57 | 58 | link:man:ranch:get_protocol_options(3)[ranch:get_protocol_options(3)], 59 | link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)], 60 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 61 | link:man:ranch(3)[ranch(3)] 62 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.set_transport_options.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:set_transport_options(3) 2 | 3 | == Name 4 | 5 | ranch:set_transport_options - Set the transport options 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | set_transport_options(Ref :: ranch:ref(), 12 | TransOpts :: ranch:opts()) 13 | -> ok | {error, Reason :: term()} 14 | ---- 15 | 16 | Set the transport options. 17 | 18 | The complete set of transport options is replaced. To update a subset of the 19 | transport options, it is recommended to get the current transport options using 20 | link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)], update 21 | them and then set them back using this function. 22 | 23 | Changes to the following options will take effect... 24 | 25 | * immediately: 26 | ** `max_connections` 27 | ** `handshake_timeout` 28 | ** `shutdown` 29 | * only after the listener has been suspended and resumed: 30 | ** `num_acceptors` 31 | ** `num_listen_sockets` 32 | ** `post_listen_callback` 33 | ** `socket_opts` 34 | * only when the entire listener is restarted: 35 | ** `connection_type` 36 | ** `num_conns_sups` 37 | ** `logger` 38 | 39 | == Arguments 40 | 41 | Ref:: 42 | 43 | The listener name. 44 | 45 | TransOpts:: 46 | 47 | The new transport options. 48 | 49 | == Return value 50 | 51 | The atom `ok` is returned on success. 52 | 53 | An error tuple is returned on failure, for example if the given 54 | transport options contain invalid values. 55 | 56 | == Changelog 57 | 58 | * *2.0*: The restriction that the listener must be suspended 59 | has been removed. 60 | * *2.0*: The `TransOpts` argument must no longer contain 61 | Ranch-specific options if given as a list. Use a map. 62 | 63 | == Examples 64 | 65 | .Set the transport options 66 | [source,erlang] 67 | ---- 68 | Ref = example, 69 | 70 | ok = ranch:suspend_listener(Ref), 71 | ok = ranch:set_transport_options(Ref, TransOpts), 72 | ok = ranch:resume_listener(Ref). 73 | ---- 74 | 75 | .Update the listener TCP port within the `socket_opts` transport option 76 | [source,erlang] 77 | ---- 78 | Ref = example, 79 | 80 | TransOpts0 = ranch:get_transport_options(Ref), 81 | #{socket_opts = SocketOpts0} = TransOpts0, 82 | SocketOpts = [{port, 12345}|proplists:delete(port, SocketOpts0)], 83 | TransOpts = TransOpts0#{socket_opts = SocketOpts}, 84 | 85 | ok = ranch:suspend_listener(Ref), 86 | ok = ranch:set_transport_options(Ref, TransOpts), 87 | ok = ranch:resume_listener(Ref). 88 | ---- 89 | 90 | == See also 91 | 92 | link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)], 93 | link:man:ranch:resume_listener(3)[ranch:resume_listener(3)], 94 | link:man:ranch:get_transport_options(3)[ranch:get_transport_options(3)], 95 | link:man:ranch:set_max_connections(3)[ranch:set_max_connections(3)], 96 | link:man:ranch:set_protocol_options(3)[ranch:set_protocol_options(3)], 97 | link:man:ranch(3)[ranch(3)] 98 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.start_listener.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:start_listener(3) 2 | 3 | == Name 4 | 5 | ranch:start_listener - Start a listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | start_listener(Ref :: ranch_ref(), 12 | Transport :: module(), 13 | TransOpts :: ranch:opts(), 14 | Protocol :: module(), 15 | ProtoOpts :: any()) 16 | -> {ok, ListenerPid :: pid()} 17 | | {error, any()} 18 | ---- 19 | 20 | Start a listener. 21 | 22 | A listener is a set of processes that accepts and manages 23 | connections using the given transport and protocol modules. 24 | 25 | == Arguments 26 | 27 | Ref:: 28 | 29 | The listener name is used to refer to this listener in 30 | future calls, for example when stopping it or when 31 | updating the configuration. 32 | + 33 | It can be any Erlang term. An atom is generally good enough, 34 | for example `api`, `my_app_clear` or `my_app_tls`. 35 | 36 | Transport:: 37 | 38 | The transport module that will be used by Ranch to accept 39 | connections and that will be passed to the protocol module 40 | along with the socket. 41 | + 42 | The interface of the transport module is documented in the 43 | link:man:ranch_transport(3)[ranch_transport(3)] manual. 44 | 45 | TransportOpts:: 46 | 47 | Transport options include the Ranch-specific options 48 | and the socket options. The listener's port number must 49 | be defined in the socket options. 50 | + 51 | Socket options may be given directly if there are no 52 | Ranch-specific options. 53 | + 54 | The available options for the built-in Ranch transports 55 | are documented in the link:man:ranch_tcp(3)[ranch_tcp(3)] 56 | and link:man:ranch_ssl(3)[ranch_ssl(3)] manuals. 57 | 58 | Protocol:: 59 | 60 | The protocol module that will be used by Ranch after 61 | the connection has been accepted. 62 | + 63 | The interface of the protocol module is documented in the 64 | link:man:ranch_protocol(3)[ranch_protocol(3)] manual. 65 | 66 | ProtocolOpts:: 67 | 68 | The protocol options given when calling the protocol 69 | module. Please consult the documentation of the protocol 70 | module you are using for more details. 71 | 72 | == Return value 73 | 74 | An ok tuple is returned on success. It contains the pid of 75 | the top-level supervisor for the listener. 76 | 77 | An error tuple is returned on error. The error reason may 78 | be any Erlang term. 79 | 80 | A common error is `eaddrinuse`. It indicates that the port 81 | configured for Ranch is already in use. 82 | 83 | == Changelog 84 | 85 | * *2.0*: The `TransOpts` argument must no longer contain 86 | Ranch-specific options if given as a list. Use a map. 87 | * *1.4*: The `NumAcceptors` argument was moved to the transport options. 88 | 89 | == Examples 90 | 91 | .Start a listener 92 | [source,erlang] 93 | ---- 94 | {ok, _} = ranch:start_listener(example, 95 | ranch_tcp, [{port, 8080}], 96 | cowboy_http2, #{} 97 | ). 98 | ---- 99 | 100 | .Start a listener with Ranch-specific options 101 | [source,erlang] 102 | ---- 103 | {ok, _} = ranch:start_listener(example, 104 | ranch_tcp, #{ 105 | num_acceptors => 75, 106 | socket_opts => [{port, 8080}] 107 | }, 108 | cowboy_http2, #{} 109 | ). 110 | ---- 111 | 112 | .Start a listener on a random port 113 | [source,erlang] 114 | ---- 115 | Ref = example, 116 | 117 | {ok, _} = ranch:start_listener(Ref, 118 | ranch_tcp, #{}, 119 | cowboy_http2, #{} 120 | ), 121 | 122 | Port = ranch:get_port(Ref). 123 | ---- 124 | 125 | == See also 126 | 127 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 128 | link:man:ranch:child_spec(3)[ranch:child_spec(3)], 129 | link:man:ranch(3)[ranch(3)], 130 | link:man:ranch_tcp(3)[ranch_tcp(3)], 131 | link:man:ranch_ssl(3)[ranch_ssl(3)], 132 | link:man:ranch_transport(3)[ranch_transport(3)], 133 | link:man:ranch_protocol(3)[ranch_protocol(3)] 134 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.stop_listener.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:stop_listener(3) 2 | 3 | == Name 4 | 5 | ranch:stop_listener - Stop a listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | stop_listener(Ref :: ranch_ref()) 12 | -> ok | {error, not_found} 13 | ---- 14 | 15 | Stop a listener. 16 | 17 | The listener is stopped gracefully, first by closing the 18 | listening port, then by stopping the connection processes. 19 | These processes are stopped according to the `shutdown` 20 | transport option, which may be set to brutally kill all 21 | connection processes or give them some time to stop properly. 22 | 23 | In order for the connection processes to exit gracefully, 24 | they need to trap exit signals and stop before the configured 25 | shutdown timeout. If greater control over the shutdown is 26 | required the functions link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)] 27 | and link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)] 28 | can be used. 29 | 30 | This function does not return until the listener is 31 | completely stopped. 32 | 33 | == Arguments 34 | 35 | Ref:: 36 | 37 | The listener name. 38 | 39 | == Return value 40 | 41 | The atom `ok` is returned on success. 42 | 43 | An error tuple is returned when the listener is not found. 44 | 45 | == Examples 46 | 47 | .Stop a listener 48 | [source,erlang] 49 | ---- 50 | ok = ranch:stop_listener(example). 51 | ---- 52 | 53 | == See also 54 | 55 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 56 | link:man:ranch:child_spec(3)[ranch:child_spec(3)], 57 | link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)], 58 | link:man:ranch(3)[ranch(3)] 59 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.suspend_listener.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:suspend_listener(3) 2 | 3 | == Name 4 | 5 | ranch:suspend_listener - Suspend a running listener 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | suspend_listener(Ref :: ranch_ref()) 12 | -> ok | {error, any()} 13 | ---- 14 | 15 | Suspend a running listener. 16 | 17 | Ranch will stop listening for and accepting connections and 18 | the listening socket will be closed. Existing connections 19 | will continue undisturbed. The function 20 | link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)] 21 | can be used to wait for connections to be closed if necessary. 22 | 23 | Some transport options can only be changed when the listener is 24 | suspended. Please consult the 25 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)] 26 | manual for more information. 27 | 28 | Nothing is done when the listener is already suspended. 29 | 30 | == Arguments 31 | 32 | Ref:: 33 | 34 | The listener name. 35 | 36 | == Return value 37 | 38 | The atom `ok` is returned on success. 39 | 40 | An error tuple is returned when the listener could not be suspended. 41 | 42 | == Changelog 43 | 44 | * *1.6*: Function introduced. 45 | 46 | == Examples 47 | 48 | .Suspend a listener 49 | [source,erlang] 50 | ---- 51 | ok = ranch:suspend_listener(example). 52 | ---- 53 | 54 | == See also 55 | 56 | link:man:ranch:start_listener(3)[ranch:start_listener(3)], 57 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 58 | link:man:ranch:resume_listener(3)[ranch:resume_listener(3)], 59 | link:man:ranch:get_status(3)[ranch:get_status(3)], 60 | link:man:ranch:set_transport_options(3)[ranch:set_transport_options(3)], 61 | link:man:ranch:wait_for_connections(3)[ranch:wait_for_connections(3)], 62 | link:man:ranch(3)[ranch(3)] 63 | -------------------------------------------------------------------------------- /doc/src/manual/ranch.wait_for_connections.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch:wait_for_connections(3) 2 | 3 | == Name 4 | 5 | ranch:wait_for_connections - Wait for a specific number of connections 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | wait_for_connections(Ref :: ranch:ref(), 12 | Operator, 13 | NumConns :: non_neg_integer()) 14 | -> ok 15 | 16 | Operator :: '>' | '>=' | '==' | '=<' | '<' 17 | ---- 18 | 19 | Wait for a specific number of connections. 20 | 21 | This function waits until the number of connections on the 22 | given listener becomes higher than, equal to or lower than 23 | the given number. It never returns otherwise. 24 | 25 | This function can be used to gracefully shutdown a listener 26 | by first suspending the listener and then waiting for 27 | connections to terminate before finally stopping the listener. 28 | 29 | // @todo The suspend/wait/stop pattern should be tested. 30 | 31 | == Arguments 32 | 33 | Ref:: 34 | 35 | The listener name. 36 | 37 | Operator:: 38 | 39 | The operator to use for the comparison. 40 | 41 | NumConns:: 42 | 43 | The number of connections to reach. 44 | 45 | == Return value 46 | 47 | The atom `ok` is always returned. It can be safely ignored. 48 | 49 | == Changelog 50 | 51 | * *1.6*: Function introduced. 52 | 53 | == Examples 54 | 55 | .Wait for at least 100 connections 56 | [source,erlang] 57 | ---- 58 | ranch:wait_for_connections(example, '>=', 100). 59 | ---- 60 | 61 | .Gracefully shutdown a listener 62 | [source,erlang] 63 | ---- 64 | Ref = example, 65 | 66 | ok = ranch:suspend_listener(Ref), 67 | ranch:wait_for_connections(Ref, '==', 0), 68 | ok = ranch:stop_listener(Ref). 69 | ---- 70 | 71 | == See also 72 | 73 | link:man:ranch:stop_listener(3)[ranch:stop_listener(3)], 74 | link:man:ranch:suspend_listener(3)[ranch:suspend_listener(3)], 75 | link:man:ranch:resume_listener(3)[ranch:resume_listener(3)], 76 | link:man:ranch(3)[ranch(3)] 77 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_app.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch(7) 2 | 3 | == Name 4 | 5 | ranch - Socket acceptor pool for TCP protocols 6 | 7 | == Description 8 | 9 | Ranch is a socket acceptor pool for TCP protocols. 10 | 11 | Ranch manages listeners which are a set of processes that 12 | accept and manage connections. The connection's transport 13 | and protocol modules are configured per listener. Listeners 14 | can be inspected and reconfigured without interruptions in 15 | service. 16 | 17 | == Modules 18 | 19 | Functions: 20 | 21 | * link:man:ranch(3)[ranch(3)] - Socket acceptor pool 22 | * link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] - PROXY protocol 23 | 24 | Transports: 25 | 26 | * link:man:ranch_ssl(3)[ranch_ssl(3)] - SSL transport 27 | * link:man:ranch_tcp(3)[ranch_tcp(3)] - TCP transport 28 | 29 | Behaviors: 30 | 31 | * link:man:ranch_protocol(3)[ranch_protocol(3)] - Protocol modules 32 | * link:man:ranch_transport(3)[ranch_transport(3)] - Transport modules 33 | 34 | == Dependencies 35 | 36 | * ssl - Secure communication over sockets 37 | 38 | All these applications must be started before the `ranch` 39 | application. To start Ranch and all dependencies at once: 40 | 41 | [source,erlang] 42 | ---- 43 | {ok, _} = application:ensure_all_started(ranch). 44 | ---- 45 | 46 | == Environment 47 | 48 | The `ranch` application defines one application environment 49 | configuration parameter. 50 | 51 | profile (false):: 52 | 53 | When enabled, Ranch will start `eprof` profiling automatically. 54 | + 55 | You can use the `ranch_app:profile_output/0` function to stop 56 | profiling and output the results to the files 'procs.profile' 57 | and 'total.profile'. Do not use in production. 58 | 59 | == See also 60 | 61 | ssl(7) 62 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_protocol.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_protocol(3) 2 | 3 | == Name 4 | 5 | ranch_protocol - Protocol modules 6 | 7 | == Description 8 | 9 | The module `ranch_protocol` defines the interface used 10 | by Ranch protocols. 11 | 12 | == Callbacks 13 | 14 | Ranch protocols implement the following interface: 15 | 16 | [source,erlang] 17 | ---- 18 | start_link(Ref :: ranch:ref(), 19 | Transport :: module(), 20 | ProtoOpts :: any()) 21 | -> {ok, ConnPid :: pid()} 22 | | {ok, SupPid :: pid(), ConnPid :: pid()} 23 | ---- 24 | 25 | Start a new connection process. 26 | 27 | The only purpose of this callback is to start a process that 28 | will handle the socket. It must spawn the process, link and 29 | then return the new pid. This function will always be called 30 | from inside a supervisor. 31 | 32 | This callback can also return two pids. The first pid is the 33 | pid of the process that will be supervised. The second pid is 34 | the pid of the process that will receive ownership of the 35 | socket. This second process must be a child of the first. This 36 | form is only available when `connection_type` is set to 37 | `supervisor`. 38 | 39 | If any other value is returned, the supervisor will close the 40 | socket and assume no process has been started. 41 | 42 | Do not perform any operations in this callback, as this would 43 | block the supervisor responsible for starting connection 44 | processes and degrade performance severely. 45 | 46 | == Changelog 47 | 48 | * *2.0*: The second argument `Socket` was removed. 49 | * *1.6*: The second argument `Socket` was deprecated. Call 50 | link:man:ranch:handshake(3)[ranch:handshake(3)] 51 | to obtain the socket. 52 | 53 | == See also 54 | 55 | link:man:ranch:handshake(3)[ranch:handshake(3)], 56 | link:man:ranch(7)[ranch(7)] 57 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_proxy_header.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_proxy_header(3) 2 | 3 | == Name 4 | 5 | ranch_proxy_header - PROXY protocol 6 | 7 | == Description 8 | 9 | The module `ranch_proxy_header` provides functions 10 | for parsing and building the PROXY protocol header. 11 | 12 | == Exports 13 | 14 | * link:man:ranch_proxy_header:parse(3)[ranch_proxy_header:parse(3)] - Parse a PROXY protocol header 15 | * link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)] - Build a PROXY protocol header 16 | * link:man:ranch_proxy_header:to_connection_info(3)[ranch_proxy_header:to_connection_info(3)] - Convert proxy_info() to ssl:connection_info() 17 | 18 | == Types 19 | 20 | === proxy_info() 21 | 22 | [source,erlang] 23 | ---- 24 | proxy_info() = #{ 25 | %% Mandatory part. 26 | version := 1 | 2, 27 | command := local | proxy, 28 | transport_family => undefined | ipv4 | ipv6 | unix, 29 | transport_protocol => undefined | stream | dgram, 30 | 31 | %% Addresses. 32 | src_address => inet:ip_address() | binary(), 33 | src_port => inet:port_number(), 34 | dest_address => inet:ip_address() | binary(), 35 | dest_port => inet:port_number(), 36 | 37 | %% Extra TLV-encoded data. 38 | alpn => binary(), %% US-ASCII. 39 | authority => binary(), %% UTF-8. 40 | unique_id => binary(), %% Opaque byte sequence of up to 128 bytes. 41 | netns => binary(), %% US-ASCII. 42 | ssl => #{ 43 | client := [ssl | cert_conn | cert_sess], 44 | verified := boolean(), 45 | version => binary(), %% US-ASCII. 46 | cipher => binary(), %% US-ASCII. 47 | sig_alg => binary(), %% US-ASCII. 48 | key_alg => binary(), %% US-ASCII. 49 | cn => binary() %% UTF-8. 50 | }, 51 | 52 | %% Unknown TLVs can't be parsed so the raw data is given. 53 | raw_tlvs => [{0..255, binary()}] 54 | }. 55 | ---- 56 | 57 | The PROXY protocol information. 58 | 59 | The following fields may be found, although most of them are 60 | optional: 61 | 62 | version:: 63 | 64 | The PROXY protocol version used. 65 | 66 | command:: 67 | 68 | `proxy` is used for proxied connections. `local` for non-proxied 69 | connections. Those do not have any additional information. 70 | 71 | transport_family:: 72 | 73 | The transport family of the original connection. 74 | 75 | transport_protocol:: 76 | 77 | The transport protocol of the original connection. 78 | 79 | src_address:: 80 | 81 | The source address of the original connection. This is the 82 | original address of the client. 83 | 84 | src_port:: 85 | 86 | The source port of the original connection. This is the 87 | port the client opened on its end for the connection. It 88 | is not defined for UNIX domain sockets. 89 | 90 | dest_address:: 91 | 92 | The destination address of the original connection. 93 | 94 | dest_port:: 95 | 96 | The destination port of the original connection. It 97 | is not defined for UNIX domain sockets. 98 | 99 | alpn:: 100 | 101 | The upper layer protocol in use over the connection. This 102 | is typically negotiated via the ALPN extension for TLS. 103 | 104 | authority:: 105 | 106 | The host name serving as authority for the connection. 107 | This is typically passed using the SNI extension for TLS. 108 | 109 | unique_id:: 110 | An opaque byte sequence of up to 128 bytes generated 111 | by the upstream proxy that uniquely identifies the connection. 112 | 113 | netns:: 114 | 115 | The namespace's name for the original connection. 116 | 117 | ssl:: 118 | 119 | Various information pertaining to the original SSL/TLS 120 | connection. 121 | 122 | client::: 123 | 124 | A list containing a number of flags. `ssl` indicates 125 | that the client connected over SSL/TLS. `cert_conn` 126 | indicates that the client provided a certificate over 127 | the original connection. `cert_sess` indicates that 128 | the client provided a certificate at least once over 129 | the TLS session this connection belongs to. 130 | 131 | verified::: 132 | 133 | Whether the client presented a certificate and it was 134 | successfully verified. 135 | 136 | version::: 137 | 138 | The US-ASCII string containing the SSL/TLS version 139 | used for the original connection. 140 | 141 | cipher::: 142 | 143 | The US-ASCII string name of the cipher used. 144 | 145 | sig_alg::: 146 | 147 | The US-ASCII string name of the algorithm used to sign 148 | the certificate provided by the client. 149 | 150 | key_alg::: 151 | 152 | The US-ASCII string name of the algorithm used to generate 153 | the key of the certificate provided by the client. 154 | 155 | cn::: 156 | 157 | The UTF-8 string representation of the Common Name field 158 | of the client certificate's Distinguished Name. 159 | 160 | raw_tlvs:: 161 | 162 | The non-standard TLVs that Ranch was not able to parse. 163 | 164 | == Changelog 165 | 166 | * *2.2*: The `unique_id` TLV was added. 167 | * *1.7*: Module introduced. 168 | 169 | == See also 170 | 171 | link:man:ranch(7)[ranch(7)] 172 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_proxy_header.header.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_proxy_header:header(3) 2 | 3 | == Name 4 | 5 | ranch_proxy_header:header - Build a PROXY protocol header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | header(ProxyInfo) -> header(ProxyInfo, #{}) 12 | header(ProxyInfo, BuildOpts) -> iodata() 13 | 14 | ProxyInfo :: ranch_proxy_header:proxy_info() 15 | BuildOpts :: #{ 16 | checksum => crc32c, 17 | padding => pos_integer() %% >= 3 18 | } 19 | ---- 20 | 21 | Build a PROXY protocol header. 22 | 23 | == Arguments 24 | 25 | ProxyInfo:: 26 | 27 | The proxy information to encode. 28 | 29 | BuildOpts:: 30 | 31 | Options to control whether to add a checksum or padding 32 | should be included in the encoded PROXY protocol header. 33 | 34 | == Return value 35 | 36 | The PROXY protocol header is returned. 37 | 38 | == Changelog 39 | 40 | * *1.7*: Function introduced. 41 | 42 | == Examples 43 | 44 | .Build a PROXY protocol header 45 | [source,erlang] 46 | ---- 47 | ProxyInfo = #{ 48 | version => 2, 49 | command => proxy, 50 | 51 | transport_family => ipv4, 52 | transport_protocol => stream, 53 | 54 | src_address => {192, 168, 1, 11}, 55 | src_port => 54321, 56 | dest_address => {192, 168, 1, 42}, 57 | dest_port => 443 58 | }, 59 | Data = ranch_proxy_header:parse(ProxyInfo). 60 | ---- 61 | 62 | .Build a PROXY protocol header with checksum and padding 63 | [source,erlang] 64 | ---- 65 | Data = ranch_proxy_header:parse(ProxyInfo, #{ 66 | checksum => crc32c, 67 | padding => 7 68 | }). 69 | ---- 70 | 71 | == See also 72 | 73 | link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)], 74 | link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] 75 | 76 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_proxy_header.parse.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_proxy_header:parse(3) 2 | 3 | == Name 4 | 5 | ranch_proxy_header:parse - Parse a PROXY protocol header 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | parse(Data :: binary()) 12 | -> {ok, ranch_proxy_header:proxy_info(), Rest :: binary()} 13 | | {error, HumanReadable :: atom()} 14 | ---- 15 | 16 | Parse a PROXY protocol header. 17 | 18 | == Arguments 19 | 20 | Data:: 21 | 22 | The PROXY protocol header optionally followed by more data. 23 | 24 | == Return value 25 | 26 | An `ok` tuple is returned on success, containing the proxy 27 | information found in the header and the rest of the data 28 | if more was provided. 29 | 30 | An `error` tuple is returned when a protocol error is 31 | detected. It contains a human readable message about the 32 | error. 33 | 34 | == Changelog 35 | 36 | * *1.7*: Function introduced. 37 | 38 | == Examples 39 | 40 | .Parse the PROXY protocol header 41 | [source,erlang] 42 | ---- 43 | {ok ProxyInfo, Rest} = ranch_proxy_header:parse(Data). 44 | ---- 45 | 46 | == See also 47 | 48 | link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)], 49 | link:man:ranch_proxy_header:to_connection_info(3)[ranch_proxy_header:to_connection_info(3)], 50 | link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] 51 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_proxy_header.to_connection_info.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_proxy_header:to_connection_info(3) 2 | 3 | == Name 4 | 5 | ranch_proxy_header:to_connection_info - Convert proxy_info() to ssl:connection_info() 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | to_connection_info(ProxyInfo :: proxy_info()) 12 | -> ssl:connection_info() 13 | ---- 14 | 15 | Convert `ranch_proxy_header:proxy_info()` information 16 | to the `ssl:connection_info()` format returned by 17 | `ssl:connection_information/1,2`. 18 | 19 | == Arguments 20 | 21 | ProxyInfo:: 22 | 23 | The PROXY protocol information. 24 | 25 | == Return value 26 | 27 | Connection information is returned as a proplist. 28 | 29 | Because the PROXY protocol header includes limited 30 | information, only the keys `protocol`, `selected_cipher_suite` 31 | and `sni_hostname` will be returned, at most. All keys 32 | are optional. 33 | 34 | == Changelog 35 | 36 | * *2.1*: Function introduced. 37 | 38 | == Examples 39 | 40 | .Convert the PROXY protocol information 41 | [source,erlang] 42 | ---- 43 | ConnInfo = ranch_proxy_header:to_connection_info(ProxyInfo). 44 | ---- 45 | 46 | == See also 47 | 48 | link:man:ranch_proxy_header:parse(3)[ranch_proxy_header:parse(3)], 49 | link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] 50 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_tcp.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_tcp(3) 2 | 3 | == Name 4 | 5 | ranch_tcp - TCP transport 6 | 7 | == Description 8 | 9 | The module `ranch_tcp` implements a TCP Ranch transport. 10 | 11 | The function `sendfile` may not work correctly when used 12 | against files stored in a VirtualBox shared folder. 13 | 14 | == Exports 15 | 16 | The module `ranch_tcp` implements the interface defined 17 | by link:man:ranch_transport(3)[ranch_transport(3)]. 18 | 19 | == Types 20 | 21 | === opt() 22 | 23 | [source,erlang] 24 | ---- 25 | opt() = {backlog, non_neg_integer()} 26 | | {buffer, non_neg_integer()} 27 | | {delay_send, boolean()} 28 | | {dontroute, boolean()} 29 | | {exit_on_close, boolean()} 30 | | {fd, non_neg_integer()} 31 | | {high_msgq_watermark, non_neg_integer()} 32 | | {high_watermark, non_neg_integer()} 33 | | inet 34 | | inet6 35 | | {ip, inet:ip_address() | inet:local_address()} 36 | | {ipv6_v6only, boolean()} 37 | | {keepalive, boolean()} 38 | | {linger, {boolean(), non_neg_integer()}} 39 | | {low_msgq_watermark, non_neg_integer()} 40 | | {low_watermark, non_neg_integer()} 41 | | {nodelay, boolean()} 42 | | {port, inet:port_number()} 43 | | {priority, integer()} 44 | | {raw, non_neg_integer(), non_neg_integer(), binary()} 45 | | {recbuf, non_neg_integer()} 46 | | {send_timeout, timeout()} 47 | | {send_timeout_close, boolean()} 48 | | {sndbuf, non_neg_integer()} 49 | | {tos, integer()} 50 | ---- 51 | 52 | Listen options. 53 | 54 | Note that additional options may be set by the protocol 55 | module using `Transport:setopts/2`. 56 | 57 | None of the options are required. 58 | 59 | Please consult the `gen_tcp` and `inet` manuals for a more 60 | thorough description of these options. This manual only aims 61 | to provide a short description along with what the defaults 62 | are. Defaults may be different in Ranch compared to `gen_tcp`. 63 | Defaults are given next to the option name: 64 | 65 | backlog (1024):: 66 | 67 | Max length of the queue of pending connections. 68 | 69 | buffer:: 70 | 71 | Size of the buffer used by the Erlang driver. Default 72 | is system-dependent. 73 | 74 | delay_send (false):: 75 | 76 | Always queue data before sending, to send fewer, larger 77 | packets over the network. 78 | 79 | dontroute (false):: 80 | 81 | Don't send via a gateway, only send to directly connected hosts. 82 | 83 | exit_on_close (true):: 84 | 85 | Disable to allow sending data after a close has been detected. 86 | 87 | fd:: 88 | 89 | File descriptor of the socket, if it was opened externally. 90 | 91 | high_msgq_watermark (8192):: 92 | 93 | Limit in the amount of data in the socket message queue before 94 | the queue becomes busy. 95 | 96 | high_watermark (8192):: 97 | 98 | Limit in the amount of data in the ERTS socket implementation's 99 | queue before the socket becomes busy. 100 | 101 | inet:: 102 | 103 | Set up the socket for IPv4. 104 | 105 | inet6:: 106 | 107 | Set up the socket for IPv6. 108 | 109 | ip:: 110 | 111 | Interface to listen on. Listen on all network interfaces by default. 112 | 113 | On UNIX systems, it is also possible to use a UNIX Domain 114 | socket file by specifying `{local, SocketFile}`. 115 | 116 | ipv6_v6only (false):: 117 | 118 | Listen on IPv4 and IPv6 (false) or only on IPv6 (true). 119 | Use with inet6. 120 | 121 | keepalive (false):: 122 | 123 | Enable sending of keep-alive messages. 124 | 125 | linger ({false, 0}):: 126 | 127 | Whether to wait and how long to flush data sent before closing 128 | the socket. 129 | 130 | low_msgq_watermark (4096):: 131 | 132 | Amount of data in the socket message queue before the queue 133 | leaves busy state. 134 | 135 | low_watermark (4096):: 136 | 137 | Amount of data in the ERTS socket implementation's queue 138 | before the socket leaves busy state. 139 | 140 | nodelay (true):: 141 | 142 | Whether to enable TCP_NODELAY. 143 | 144 | port (0):: 145 | 146 | TCP port number to listen on. 0 means a random port will be used. 147 | 148 | priority (0):: 149 | 150 | Priority value for all packets to be sent on this socket. 151 | 152 | recbuf:: 153 | 154 | Minimum size of the socket's receive buffer. 155 | Default is system-dependent. 156 | 157 | send_timeout (30000):: 158 | 159 | How long the send call may wait for confirmation before returning. 160 | 161 | send_timeout_close (true):: 162 | 163 | Whether to close the socket when the confirmation wasn't received. 164 | 165 | sndbuf:: 166 | 167 | Minimum size of the socket's send buffer. 168 | Default is system-dependent. 169 | 170 | tos:: 171 | 172 | Value for the IP_TOS IP level option. Use with caution. 173 | 174 | In addition, the `raw` option can be used to set system-specific 175 | options by specifying the protocol level, the option number and 176 | the actual option value specified as a binary. This option is not 177 | portable. Use with caution. 178 | 179 | === opts() 180 | 181 | [source,erlang] 182 | ---- 183 | opts() :: [opt()] 184 | ---- 185 | 186 | List of listen options. 187 | 188 | == See also 189 | 190 | link:man:ranch(7)[ranch(7)], 191 | link:man:ranch_transport(3)[ranch_transport(3)], 192 | link:man:ranch_ssl(3)[ranch_ssl(3)], 193 | gen_tcp(3), 194 | inet(3) 195 | -------------------------------------------------------------------------------- /doc/src/manual/ranch_transport.sendfile.asciidoc: -------------------------------------------------------------------------------- 1 | = ranch_transport:sendfile(3) 2 | 3 | == Name 4 | 5 | ranch_transport:sendfile - Send a file on the socket 6 | 7 | == Description 8 | 9 | [source,erlang] 10 | ---- 11 | sendfile(Transport :: module(), 12 | Socket :: ranch_transport:socket(), 13 | File :: file:name_all() | file:fd(), 14 | Offset :: non_neg_integer(), 15 | Bytes :: non_neg_integer(), 16 | Opts :: ranch_transport:sendfile_opts()) 17 | -> {ok, SentBytes :: non_neg_integer()} | {error, atom()} 18 | ---- 19 | 20 | Send a file on the socket. 21 | 22 | The file may be sent full or in parts, and may be specified 23 | by its filename or by an already open file descriptor. 24 | 25 | This function emulates the function `file:sendfile/2,4,5` 26 | and may be used when transports are not manipulating TCP 27 | directly. 28 | 29 | == Arguments 30 | 31 | Transport:: 32 | 33 | The transport module. 34 | 35 | Socket:: 36 | 37 | The socket. 38 | 39 | File:: 40 | 41 | The filename or file descriptor for the file to be sent. 42 | 43 | Offset:: 44 | 45 | Start position in the file, in bytes. 46 | 47 | Bytes:: 48 | 49 | Length in bytes. 50 | 51 | Opts:: 52 | 53 | Additional options. 54 | 55 | == Return value 56 | 57 | The number of bytes actually sent is returned on success 58 | inside an `ok` tuple. 59 | 60 | An `error` tuple is returned otherwise. 61 | 62 | == Changelog 63 | 64 | * *1.6*: The type of the `File` argument was extended. 65 | 66 | == Examples 67 | 68 | .Implement Transport:sendfile using the fallback 69 | [source,erlang] 70 | ---- 71 | sendfile(Socket, Filename) -> 72 | sendfile(Socket, Filename, 0, 0, []). 73 | 74 | sendfile(Socket, File, Offset, Bytes) -> 75 | sendfile(Socket, File, Offset, Bytes, []). 76 | 77 | sendfile(Socket, File, Offset, Bytes, Opts) -> 78 | ranch_transport:sendfile(?MODULE, Socket, 79 | File, Offset, Bytes, Opts). 80 | ---- 81 | 82 | == See also 83 | 84 | link:man:ranch_transport(3)[ranch_transport(3)] 85 | -------------------------------------------------------------------------------- /ebin/ranch.app: -------------------------------------------------------------------------------- 1 | {application, 'ranch', [ 2 | {description, "Socket acceptor pool for TCP protocols."}, 3 | {vsn, "2.2.0"}, 4 | {modules, ['ranch','ranch_acceptor','ranch_acceptors_sup','ranch_app','ranch_conns_sup','ranch_conns_sup_sup','ranch_crc32c','ranch_embedded_sup','ranch_listener_sup','ranch_protocol','ranch_proxy_header','ranch_server','ranch_server_proxy','ranch_ssl','ranch_sup','ranch_tcp','ranch_transport']}, 5 | {registered, [ranch_sup,ranch_server]}, 6 | {applications, [kernel,stdlib,ssl]}, 7 | {optional_applications, []}, 8 | {mod, {ranch_app, []}}, 9 | {env, []} 10 | ]}. -------------------------------------------------------------------------------- /examples/tcp_echo/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = tcp_echo 2 | 3 | DEPS = ranch 4 | dep_ranch_commit = master 5 | 6 | REL_DEPS = relx 7 | 8 | include ../../erlang.mk 9 | -------------------------------------------------------------------------------- /examples/tcp_echo/README.md: -------------------------------------------------------------------------------- 1 | Ranch TCP echo example 2 | ====================== 3 | 4 | To try this example, you need GNU `make` and `git` in your PATH. 5 | 6 | To build the example, run the following command: 7 | 8 | ``` bash 9 | $ make 10 | ``` 11 | 12 | To start the release in the foreground: 13 | 14 | ``` bash 15 | $ ./_rel/tcp_echo_example/bin/tcp_echo_example console 16 | ``` 17 | 18 | Then start a telnet session to port 5555: 19 | 20 | ``` bash 21 | $ telnet localhost 5555 22 | ``` 23 | 24 | Type in a few words and see them echoed back. 25 | 26 | Be aware that there is a timeout of 5 seconds without receiving 27 | data before the example server disconnects your session. 28 | -------------------------------------------------------------------------------- /examples/tcp_echo/relx.config: -------------------------------------------------------------------------------- 1 | {release, {tcp_echo_example, "1"}, [tcp_echo, sasl]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/tcp_echo/src/echo_protocol.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(echo_protocol). 4 | -behaviour(ranch_protocol). 5 | 6 | -export([start_link/3]). 7 | -export([init/3]). 8 | 9 | start_link(Ref, Transport, Opts) -> 10 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 11 | {ok, Pid}. 12 | 13 | init(Ref, Transport, _Opts = []) -> 14 | {ok, Socket} = ranch:handshake(Ref), 15 | loop(Socket, Transport). 16 | 17 | loop(Socket, Transport) -> 18 | case Transport:recv(Socket, 0, 60000) of 19 | {ok, Data} when Data =/= <<4>> -> 20 | Transport:send(Socket, Data), 21 | loop(Socket, Transport); 22 | _ -> 23 | ok = Transport:close(Socket) 24 | end. 25 | -------------------------------------------------------------------------------- /examples/tcp_echo/src/tcp_echo_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(tcp_echo_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | {ok, _} = ranch:start_listener(tcp_echo, 15 | ranch_tcp, #{socket_opts => [{port, 5555}]}, 16 | echo_protocol, []), 17 | tcp_echo_sup:start_link(). 18 | 19 | stop(_State) -> 20 | ok. 21 | -------------------------------------------------------------------------------- /examples/tcp_echo/src/tcp_echo_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(tcp_echo_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | {ok, {{one_for_one, 10, 10}, []}}. 23 | -------------------------------------------------------------------------------- /examples/tcp_reverse/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = tcp_reverse 2 | 3 | DEPS = ranch 4 | dep_ranch_commit = master 5 | 6 | REL_DEPS = relx 7 | 8 | include ../../erlang.mk 9 | -------------------------------------------------------------------------------- /examples/tcp_reverse/README.md: -------------------------------------------------------------------------------- 1 | Ranch TCP reverse example 2 | ========================= 3 | 4 | This example uses a `gen_statem` to handle a protocol to revese input. 5 | See `reverse_protocol.erl` for the implementation. Documentation about 6 | this topic can be found in the guide: 7 | 8 | http://ninenines.eu/docs/en/ranch/HEAD/guide/protocols/#using_gen_statem 9 | 10 | To try this example, you need GNU `make` and `git` in your PATH. 11 | 12 | To build the example, run the following command: 13 | 14 | ``` bash 15 | $ make 16 | ``` 17 | 18 | To start the release in the foreground: 19 | 20 | ``` bash 21 | $ ./_rel/tcp_reverse_example/bin/tcp_reverse_example console 22 | ``` 23 | 24 | Then start a telnet session to port 5555: 25 | 26 | ``` bash 27 | $ telnet localhost 5555 28 | ``` 29 | 30 | Type in a few words and see them reversed! Amazing! 31 | 32 | Be aware that there is a timeout of 5 seconds without receiving 33 | data before the example server disconnects your session. 34 | -------------------------------------------------------------------------------- /examples/tcp_reverse/relx.config: -------------------------------------------------------------------------------- 1 | {release, {tcp_reverse_example, "1"}, [tcp_reverse, sasl]}. 2 | {extended_start_script, true}. 3 | -------------------------------------------------------------------------------- /examples/tcp_reverse/src/reverse_protocol.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | -module(reverse_protocol). 4 | -behaviour(gen_statem). 5 | -behaviour(ranch_protocol). 6 | 7 | %% API. 8 | -export([start_link/3]). 9 | 10 | %% gen_statem. 11 | -export([callback_mode/0]). 12 | -export([init/1]). 13 | -export([connected/3]). 14 | -export([terminate/3]). 15 | -export([code_change/4]). 16 | 17 | -define(TIMEOUT, 60000). 18 | 19 | -record(state, {ref, transport, socket}). 20 | 21 | %% API. 22 | 23 | start_link(Ref, Transport, Opts) -> 24 | gen_statem:start_link(?MODULE, {Ref, Transport, Opts}, []). 25 | 26 | %% gen_statem. 27 | 28 | callback_mode() -> 29 | [state_functions, state_enter]. 30 | 31 | init({Ref, Transport, _Opts = []}) -> 32 | {ok, connected, #state{ref=Ref, transport=Transport}, ?TIMEOUT}. 33 | 34 | connected(enter, connected, StateData=#state{ 35 | ref=Ref, transport=Transport}) -> 36 | {ok, Socket} = ranch:handshake(Ref), 37 | ok = Transport:setopts(Socket, [{active, once}, {packet, line}]), 38 | {keep_state, StateData#state{socket=Socket}}; 39 | connected(info, {tcp, Socket, Data}, _StateData=#state{ 40 | socket=Socket, transport=Transport}) 41 | when byte_size(Data) >= 1 -> 42 | Transport:setopts(Socket, [{active, once}]), 43 | Transport:send(Socket, reverse_binary(Data)), 44 | {keep_state_and_data, ?TIMEOUT}; 45 | connected(info, {tcp_closed, _Socket}, _StateData) -> 46 | {stop, normal}; 47 | connected(info, {tcp_error, _, Reason}, _StateData) -> 48 | {stop, Reason}; 49 | connected({call, From}, _Request, _StateData) -> 50 | gen_statem:reply(From, ok), 51 | keep_state_and_data; 52 | connected(cast, _Msg, _StateData) -> 53 | keep_state_and_data; 54 | connected(timeout, _Msg, _StateData) -> 55 | {stop, normal}; 56 | connected(_EventType, _Msg, _StateData) -> 57 | {stop, normal}. 58 | 59 | terminate(Reason, StateName, StateData=#state{ 60 | socket=Socket, transport=Transport}) 61 | when Socket=/=undefined, Transport=/=undefined -> 62 | catch Transport:close(Socket), 63 | terminate(Reason, StateName, 64 | StateData#state{socket=undefined, transport=undefined}); 65 | terminate(_Reason, _StateName, _StateData) -> 66 | ok. 67 | 68 | code_change(_OldVsn, StateName, StateData, _Extra) -> 69 | {ok, StateName, StateData}. 70 | 71 | %% Internal. 72 | 73 | reverse_binary(B0) when is_binary(B0) -> 74 | Size = bit_size(B0), 75 | <> = B0, 76 | case <> of 77 | %% Take care of different possible line terminators. 78 | <<$\n, $\r, B2/binary>> -> 79 | %% CR/LF (Windows) 80 | <>; 81 | <<$\n, B2/binary>> -> 82 | %% LF (Linux, Mac OS X and later) 83 | <>; 84 | <<$\r, B2/binary>> -> 85 | %% CR (Mac Classic, ie prior to Mac OS X) 86 | <> 87 | end. 88 | -------------------------------------------------------------------------------- /examples/tcp_reverse/src/tcp_reverse_app.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(tcp_reverse_app). 5 | -behaviour(application). 6 | 7 | %% API. 8 | -export([start/2]). 9 | -export([stop/1]). 10 | 11 | %% API. 12 | 13 | start(_Type, _Args) -> 14 | {ok, _} = ranch:start_listener(tcp_reverse, 15 | ranch_tcp, #{socket_opts => [{port, 5555}]}, 16 | reverse_protocol, []), 17 | tcp_reverse_sup:start_link(). 18 | 19 | stop(_State) -> 20 | ok. 21 | -------------------------------------------------------------------------------- /examples/tcp_reverse/src/tcp_reverse_sup.erl: -------------------------------------------------------------------------------- 1 | %% Feel free to use, reuse and abuse the code in this file. 2 | 3 | %% @private 4 | -module(tcp_reverse_sup). 5 | -behaviour(supervisor). 6 | 7 | %% API. 8 | -export([start_link/0]). 9 | 10 | %% supervisor. 11 | -export([init/1]). 12 | 13 | %% API. 14 | 15 | -spec start_link() -> {ok, pid()}. 16 | start_link() -> 17 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 18 | 19 | %% supervisor. 20 | 21 | init([]) -> 22 | {ok, {{one_for_one, 10, 10}, []}}. 23 | -------------------------------------------------------------------------------- /src/ranch.appup: -------------------------------------------------------------------------------- 1 | %% ranch_conns_sup is a custom supervisor (special process), 2 | %% not an OTP supervisor. When "supervisor" is used, the 3 | %% module is always loaded before calling system_code_change, 4 | %% for both upgrade and downgrade operations. This is so that 5 | %% the supervisor's init callback of the upgraded/downgraded 6 | %% module gets called. But the custom supervisors in Ranch 7 | %% do not have an init callback and therefore can function 8 | %% like other special processes: when upgrading, load the 9 | %% module then call system_code_change; and when downgrading, 10 | %% call system_code_change and then load the module. 11 | 12 | {"2.2.0", 13 | [{<<"2\\.1\\.[0-9]+.*">>, [ 14 | {apply, {ranch, stop_all_acceptors, []}}, 15 | {load_module, ranch}, 16 | {load_module, ranch_acceptor}, 17 | {update, ranch_acceptors_sup, supervisor}, 18 | {load_module, ranch_app}, 19 | {update, ranch_server, {advanced, []}}, 20 | {update, ranch_conns_sup_sup, supervisor}, 21 | %% See comments at the top of the file about ranch_conns_sup. 22 | {update, ranch_conns_sup, {advanced, []}}, 23 | {load_module, ranch_crc32c}, 24 | {update, ranch_embedded_sup, supervisor}, 25 | {update, ranch_listener_sup, supervisor}, 26 | {load_module, ranch_protocol}, 27 | {load_module, ranch_proxy_header}, 28 | {update, ranch_server_proxy, {advanced, []}}, 29 | {load_module, ranch_ssl}, 30 | {update, ranch_sup, supervisor}, 31 | {load_module, ranch_tcp}, 32 | {load_module, ranch_transport}, 33 | {apply, {ranch, restart_all_acceptors, []}} 34 | ]}], 35 | [{<<"2\\.1\\.[0-9]+.*">>, [ 36 | {apply, {ranch, stop_all_acceptors, []}}, 37 | {load_module, ranch}, 38 | {load_module, ranch_acceptor}, 39 | {update, ranch_acceptors_sup, supervisor}, 40 | {load_module, ranch_app}, 41 | %% See comments at the top of the file about ranch_conns_sup. 42 | {update, ranch_conns_sup, {advanced, []}}, 43 | {update, ranch_conns_sup_sup, supervisor}, 44 | {load_module, ranch_crc32c}, 45 | {update, ranch_embedded_sup, supervisor}, 46 | {update, ranch_listener_sup, supervisor}, 47 | {load_module, ranch_protocol}, 48 | {load_module, ranch_proxy_header}, 49 | {update, ranch_server, {advanced, []}}, 50 | {update, ranch_server_proxy, {advanced, []}}, 51 | {load_module, ranch_ssl}, 52 | {update, ranch_sup, supervisor}, 53 | {load_module, ranch_tcp}, 54 | {load_module, ranch_transport}, 55 | {apply, {ranch, restart_all_acceptors, []}} 56 | ]}] 57 | }. 58 | 59 | {"2.1.0", 60 | [{<<"2\\.0\\.[0-9]+.*">>, [ 61 | {apply, {ranch, stop_all_acceptors, []}}, 62 | {load_module, ranch}, 63 | {load_module, ranch_acceptor}, 64 | {update, ranch_acceptors_sup, supervisor}, 65 | {load_module, ranch_app}, 66 | {update, ranch_server, {advanced, []}}, 67 | {update, ranch_conns_sup_sup, supervisor}, 68 | %% See comments at the top of the file about ranch_conns_sup. 69 | {update, ranch_conns_sup, {advanced, []}}, 70 | {load_module, ranch_crc32c}, 71 | {update, ranch_embedded_sup, supervisor}, 72 | {update, ranch_listener_sup, supervisor}, 73 | {load_module, ranch_protocol}, 74 | {load_module, ranch_proxy_header}, 75 | {update, ranch_server_proxy, {advanced, []}}, 76 | {load_module, ranch_ssl}, 77 | {update, ranch_sup, supervisor}, 78 | {load_module, ranch_tcp}, 79 | {load_module, ranch_transport}, 80 | {apply, {ranch, restart_all_acceptors, []}} 81 | ]}], 82 | [{<<"2\\.0\\.[0-9]+.*">>, [ 83 | {apply, {ranch, stop_all_acceptors, []}}, 84 | {load_module, ranch}, 85 | {load_module, ranch_acceptor}, 86 | {update, ranch_acceptors_sup, supervisor}, 87 | {load_module, ranch_app}, 88 | %% See comments at the top of the file about ranch_conns_sup. 89 | {update, ranch_conns_sup, {advanced, []}}, 90 | {update, ranch_conns_sup_sup, supervisor}, 91 | {load_module, ranch_crc32c}, 92 | {update, ranch_embedded_sup, supervisor}, 93 | {update, ranch_listener_sup, supervisor}, 94 | {load_module, ranch_protocol}, 95 | {load_module, ranch_proxy_header}, 96 | {update, ranch_server, {advanced, []}}, 97 | {update, ranch_server_proxy, {advanced, []}}, 98 | {load_module, ranch_ssl}, 99 | {update, ranch_sup, supervisor}, 100 | {load_module, ranch_tcp}, 101 | {load_module, ranch_transport}, 102 | {apply, {ranch, restart_all_acceptors, []}} 103 | ]}] 104 | }. 105 | 106 | {"2.0.0", 107 | [{<<"2\\.0\\.[0-9]+.*">>, [ 108 | {apply, {ranch, stop_all_acceptors, []}}, 109 | {load_module, ranch}, 110 | {load_module, ranch_acceptor}, 111 | {update, ranch_acceptors_sup, supervisor}, 112 | {load_module, ranch_app}, 113 | {update, ranch_server, {advanced, []}}, 114 | {update, ranch_conns_sup_sup, supervisor}, 115 | %% See comments at the top of the file about ranch_conns_sup. 116 | {update, ranch_conns_sup, {advanced, []}}, 117 | {load_module, ranch_crc32c}, 118 | {update, ranch_embedded_sup, supervisor}, 119 | {update, ranch_listener_sup, supervisor}, 120 | {load_module, ranch_protocol}, 121 | {load_module, ranch_proxy_header}, 122 | {update, ranch_server_proxy, {advanced, []}}, 123 | {load_module, ranch_ssl}, 124 | {update, ranch_sup, supervisor}, 125 | {load_module, ranch_tcp}, 126 | {load_module, ranch_transport}, 127 | {apply, {ranch, restart_all_acceptors, []}} 128 | ]}], 129 | [{<<"2\\.0\\.[0-9]+.*">>, [ 130 | {apply, {ranch, stop_all_acceptors, []}}, 131 | {load_module, ranch}, 132 | {load_module, ranch_acceptor}, 133 | {update, ranch_acceptors_sup, supervisor}, 134 | {load_module, ranch_app}, 135 | %% See comments at the top of the file about ranch_conns_sup. 136 | {update, ranch_conns_sup, {advanced, []}}, 137 | {update, ranch_conns_sup_sup, supervisor}, 138 | {load_module, ranch_crc32c}, 139 | {update, ranch_embedded_sup, supervisor}, 140 | {update, ranch_listener_sup, supervisor}, 141 | {load_module, ranch_protocol}, 142 | {load_module, ranch_proxy_header}, 143 | {update, ranch_server, {advanced, []}}, 144 | {update, ranch_server_proxy, {advanced, []}}, 145 | {load_module, ranch_ssl}, 146 | {update, ranch_sup, supervisor}, 147 | {load_module, ranch_tcp}, 148 | {load_module, ranch_transport}, 149 | {apply, {ranch, restart_all_acceptors, []}} 150 | ]}] 151 | }. 152 | -------------------------------------------------------------------------------- /src/ranch_acceptor.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_acceptor). 16 | 17 | -export([start_link/5]). 18 | -export([init/4]). 19 | -export([loop/5]). 20 | 21 | -spec start_link(ranch:ref(), pos_integer(), inet:socket(), module(), module()) 22 | -> {ok, pid()}. 23 | start_link(Ref, AcceptorId, LSocket, Transport, Logger) -> 24 | ConnsSup = ranch_server:get_connections_sup(Ref, AcceptorId), 25 | Pid = spawn_link(?MODULE, init, [LSocket, Transport, Logger, ConnsSup]), 26 | {ok, Pid}. 27 | 28 | -spec init(inet:socket(), module(), module(), pid()) -> no_return(). 29 | init(LSocket, Transport, Logger, ConnsSup) -> 30 | MonitorRef = monitor(process, ConnsSup), 31 | loop(LSocket, Transport, Logger, ConnsSup, MonitorRef). 32 | 33 | -spec loop(inet:socket(), module(), module(), pid(), reference()) -> no_return(). 34 | loop(LSocket, Transport, Logger, ConnsSup, MonitorRef) -> 35 | _ = case Transport:accept(LSocket, infinity) of 36 | {ok, CSocket} -> 37 | case Transport:controlling_process(CSocket, ConnsSup) of 38 | ok -> 39 | %% This call will not return until process has been started 40 | %% AND we are below the maximum number of connections. 41 | ranch_conns_sup:start_protocol(ConnsSup, MonitorRef, 42 | CSocket); 43 | {error, _} -> 44 | Transport:close(CSocket) 45 | end; 46 | %% Reduce the accept rate if we run out of file descriptors. 47 | %% We can't accept anymore anyway, so we might as well wait 48 | %% a little for the situation to resolve itself. 49 | {error, emfile} -> 50 | ranch:log(warning, 51 | "Ranch acceptor reducing accept rate: out of file descriptors~n", 52 | [], Logger), 53 | receive after 100 -> ok end; 54 | %% Exit if the listening socket got closed. 55 | {error, closed} -> 56 | exit(closed); 57 | %% Continue otherwise. 58 | {error, _} -> 59 | ok 60 | end, 61 | flush(Logger), 62 | ?MODULE:loop(LSocket, Transport, Logger, ConnsSup, MonitorRef). 63 | 64 | flush(Logger) -> 65 | receive Msg -> 66 | ranch:log(warning, 67 | "Ranch acceptor received unexpected message: ~p~n", 68 | [Msg], Logger), 69 | flush(Logger) 70 | after 0 -> 71 | ok 72 | end. 73 | -------------------------------------------------------------------------------- /src/ranch_acceptors_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% Copyright (c) Jan Uhlig 3 | %% 4 | %% Permission to use, copy, modify, and/or distribute this software for any 5 | %% purpose with or without fee is hereby granted, provided that the above 6 | %% copyright notice and this permission notice appear in all copies. 7 | %% 8 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | -module(ranch_acceptors_sup). 17 | -behaviour(supervisor). 18 | 19 | -export([start_link/3]). 20 | -export([init/1]). 21 | 22 | -spec start_link(ranch:ref(), module(), module()) 23 | -> {ok, pid()}. 24 | start_link(Ref, Transport, Logger) -> 25 | supervisor:start_link(?MODULE, [Ref, Transport, Logger]). 26 | 27 | -spec init([term()]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. 28 | init([Ref, Transport, Logger]) -> 29 | TransOpts = ranch_server:get_transport_options(Ref), 30 | NumAcceptors = maps:get(num_acceptors, TransOpts, 10), 31 | NumListenSockets = maps:get(num_listen_sockets, TransOpts, 1), 32 | LSockets = case get(lsockets) of 33 | undefined -> 34 | LSockets1 = start_listen_sockets(Ref, NumListenSockets, Transport, TransOpts, Logger), 35 | put(lsockets, LSockets1), 36 | LSockets1; 37 | LSockets1 -> 38 | LSockets1 39 | end, 40 | Procs = [begin 41 | LSocketId = (AcceptorId rem NumListenSockets) + 1, 42 | {_, LSocket} = lists:keyfind(LSocketId, 1, LSockets), 43 | #{ 44 | id => {acceptor, self(), AcceptorId}, 45 | start => {ranch_acceptor, start_link, [Ref, AcceptorId, LSocket, Transport, Logger]}, 46 | shutdown => brutal_kill 47 | } 48 | end || AcceptorId <- lists:seq(1, NumAcceptors)], 49 | {ok, {#{intensity => 1 + ceil(math:log2(NumAcceptors))}, Procs}}. 50 | 51 | -spec start_listen_sockets(any(), pos_integer(), module(), map(), module()) 52 | -> [{pos_integer(), inet:socket()}]. 53 | start_listen_sockets(Ref, NumListenSockets, Transport, TransOpts0, Logger) when NumListenSockets > 0 -> 54 | BaseSocket = start_listen_socket(Ref, Transport, TransOpts0, Logger), 55 | {ok, Addr} = Transport:sockname(BaseSocket), 56 | ExtraSockets = case Addr of 57 | {local, _} when NumListenSockets > 1 -> 58 | listen_error(Ref, Transport, TransOpts0, reuseport_local, Logger); 59 | {local, _} -> 60 | []; 61 | {_, Port} -> 62 | SocketOpts = maps:get(socket_opts, TransOpts0, []), 63 | SocketOpts1 = lists:keystore(port, 1, SocketOpts, {port, Port}), 64 | TransOpts1 = TransOpts0#{socket_opts => SocketOpts1}, 65 | [{N, start_listen_socket(Ref, Transport, TransOpts1, Logger)} 66 | || N <- lists:seq(2, NumListenSockets)] 67 | end, 68 | ranch_server:set_addr(Ref, Addr), 69 | [{1, BaseSocket}|ExtraSockets]. 70 | 71 | -spec start_listen_socket(any(), module(), map(), module()) -> inet:socket(). 72 | start_listen_socket(Ref, Transport, TransOpts, Logger) -> 73 | case Transport:listen(TransOpts) of 74 | {ok, Socket} -> 75 | PostListenCb = maps:get(post_listen_callback, TransOpts, fun (_) -> ok end), 76 | case PostListenCb(Socket) of 77 | ok -> 78 | Socket; 79 | {error, Reason} -> 80 | listen_error(Ref, Transport, TransOpts, Reason, Logger) 81 | end; 82 | {error, Reason} -> 83 | listen_error(Ref, Transport, TransOpts, Reason, Logger) 84 | end. 85 | 86 | -spec listen_error(any(), module(), any(), atom(), module()) -> no_return(). 87 | listen_error(Ref, Transport, TransOpts0, Reason, Logger) -> 88 | SocketOpts0 = maps:get(socket_opts, TransOpts0, []), 89 | SocketOpts = hide_socket_opts(SocketOpts0), 90 | TransOpts = TransOpts0#{socket_opts => SocketOpts}, 91 | ranch:log(error, 92 | "Failed to start Ranch listener ~p in ~p:listen(~0p) for reason ~p (~s)~n", 93 | [Ref, Transport, TransOpts, Reason, format_error(Transport, Reason)], Logger), 94 | exit({listen_error, Ref, Reason}). 95 | 96 | hide_socket_opts([]) -> 97 | []; 98 | hide_socket_opts([{cert, _}|SocketOpts]) -> 99 | [{cert, '...'}|hide_socket_opts(SocketOpts)]; 100 | hide_socket_opts([{key, _}|SocketOpts]) -> 101 | [{key, '...'}|hide_socket_opts(SocketOpts)]; 102 | hide_socket_opts([{cacerts, _}|SocketOpts]) -> 103 | [{cacerts, '...'}|hide_socket_opts(SocketOpts)]; 104 | hide_socket_opts([{password, _}|SocketOpts]) -> 105 | [{password, '...'}|hide_socket_opts(SocketOpts)]; 106 | hide_socket_opts([{certs_keys, _}|SocketOpts]) -> 107 | [{certs_keys, '...'}|hide_socket_opts(SocketOpts)]; 108 | hide_socket_opts([SocketOpt|SocketOpts]) -> 109 | [SocketOpt|hide_socket_opts(SocketOpts)]. 110 | 111 | %% Handling of no_cert really should be done in ranch_ssl. We leave it here for 112 | %% backwards compatibility with possibly existing custom transports without a 113 | %% format_error/1 implementation that may rely on this module handling it. 114 | %% TODO: Remove in Ranch 3.0 115 | format_error(_, no_cert) -> 116 | "no certificate provided; see cert, certfile, sni_fun or sni_hosts options"; 117 | format_error(_, reuseport_local) -> 118 | "num_listen_sockets must be set to 1 for local sockets"; 119 | format_error(Transport, Reason) -> 120 | %% TODO: Required callback in Ranch 3.0 121 | case erlang:function_exported(Transport, format_error, 1) of 122 | true -> 123 | Transport:format_error(Reason); 124 | false -> 125 | lists:flatten(io_lib:format("~0p", [Reason])) 126 | end. 127 | -------------------------------------------------------------------------------- /src/ranch_app.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_app). 16 | -behaviour(application). 17 | 18 | -export([start/2]). 19 | -export([stop/1]). 20 | -export([profile_output/0]). 21 | 22 | -spec start(application:start_type(), term()) -> {ok, pid()} | {error, term()}. 23 | start(_, _) -> 24 | _ = consider_profiling(), 25 | ranch_server = ets:new(ranch_server, [ 26 | ordered_set, public, named_table]), 27 | ranch_sup:start_link(). 28 | 29 | -spec stop(term()) -> ok. 30 | stop(_) -> 31 | ok. 32 | 33 | -spec profile_output() -> ok. 34 | profile_output() -> 35 | eprof:stop_profiling(), 36 | eprof:log("procs.profile"), 37 | eprof:analyze(procs), 38 | eprof:log("total.profile"), 39 | eprof:analyze(total). 40 | 41 | consider_profiling() -> 42 | case application:get_env(profile) of 43 | {ok, true} -> 44 | {ok, _Pid} = eprof:start(), 45 | eprof:start_profiling([self()]); 46 | _ -> 47 | not_profiling 48 | end. 49 | -------------------------------------------------------------------------------- /src/ranch_conns_sup_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Jan Uhlig 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_conns_sup_sup). 16 | 17 | -behaviour(supervisor). 18 | 19 | -export([start_link/4]). 20 | -export([init/1]). 21 | 22 | -spec start_link(ranch:ref(), module(), module(), module()) -> {ok, pid()}. 23 | start_link(Ref, Transport, Protocol, Logger) -> 24 | ok = ranch_server:cleanup_connections_sups(Ref), 25 | supervisor:start_link(?MODULE, { 26 | Ref, Transport, Protocol, Logger 27 | }). 28 | 29 | -spec init({ranch:ref(), module(), module(), module()}) 30 | -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. 31 | init({Ref, Transport, Protocol, Logger}) -> 32 | TransOpts = ranch_server:get_transport_options(Ref), 33 | NumAcceptors = maps:get(num_acceptors, TransOpts, 10), 34 | NumConnsSups = maps:get(num_conns_sups, TransOpts, NumAcceptors), 35 | StatsCounters = counters:new(2*NumConnsSups, []), 36 | ok = ranch_server:set_stats_counters(Ref, StatsCounters), 37 | ChildSpecs = [#{ 38 | id => {ranch_conns_sup, N}, 39 | start => {ranch_conns_sup, start_link, [Ref, N, Transport, TransOpts, Protocol, Logger]}, 40 | type => supervisor 41 | } || N <- lists:seq(1, NumConnsSups)], 42 | {ok, {#{intensity => 1 + ceil(math:log2(NumConnsSups))}, ChildSpecs}}. 43 | -------------------------------------------------------------------------------- /src/ranch_crc32c.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_crc32c). 16 | 17 | -export([crc32c/1]). 18 | -export([crc32c/2]). 19 | 20 | -define(CRC32C_TABLE, { 21 | 16#00000000, 16#F26B8303, 16#E13B70F7, 16#1350F3F4, 22 | 16#C79A971F, 16#35F1141C, 16#26A1E7E8, 16#D4CA64EB, 23 | 16#8AD958CF, 16#78B2DBCC, 16#6BE22838, 16#9989AB3B, 24 | 16#4D43CFD0, 16#BF284CD3, 16#AC78BF27, 16#5E133C24, 25 | 16#105EC76F, 16#E235446C, 16#F165B798, 16#030E349B, 26 | 16#D7C45070, 16#25AFD373, 16#36FF2087, 16#C494A384, 27 | 16#9A879FA0, 16#68EC1CA3, 16#7BBCEF57, 16#89D76C54, 28 | 16#5D1D08BF, 16#AF768BBC, 16#BC267848, 16#4E4DFB4B, 29 | 16#20BD8EDE, 16#D2D60DDD, 16#C186FE29, 16#33ED7D2A, 30 | 16#E72719C1, 16#154C9AC2, 16#061C6936, 16#F477EA35, 31 | 16#AA64D611, 16#580F5512, 16#4B5FA6E6, 16#B93425E5, 32 | 16#6DFE410E, 16#9F95C20D, 16#8CC531F9, 16#7EAEB2FA, 33 | 16#30E349B1, 16#C288CAB2, 16#D1D83946, 16#23B3BA45, 34 | 16#F779DEAE, 16#05125DAD, 16#1642AE59, 16#E4292D5A, 35 | 16#BA3A117E, 16#4851927D, 16#5B016189, 16#A96AE28A, 36 | 16#7DA08661, 16#8FCB0562, 16#9C9BF696, 16#6EF07595, 37 | 16#417B1DBC, 16#B3109EBF, 16#A0406D4B, 16#522BEE48, 38 | 16#86E18AA3, 16#748A09A0, 16#67DAFA54, 16#95B17957, 39 | 16#CBA24573, 16#39C9C670, 16#2A993584, 16#D8F2B687, 40 | 16#0C38D26C, 16#FE53516F, 16#ED03A29B, 16#1F682198, 41 | 16#5125DAD3, 16#A34E59D0, 16#B01EAA24, 16#42752927, 42 | 16#96BF4DCC, 16#64D4CECF, 16#77843D3B, 16#85EFBE38, 43 | 16#DBFC821C, 16#2997011F, 16#3AC7F2EB, 16#C8AC71E8, 44 | 16#1C661503, 16#EE0D9600, 16#FD5D65F4, 16#0F36E6F7, 45 | 16#61C69362, 16#93AD1061, 16#80FDE395, 16#72966096, 46 | 16#A65C047D, 16#5437877E, 16#4767748A, 16#B50CF789, 47 | 16#EB1FCBAD, 16#197448AE, 16#0A24BB5A, 16#F84F3859, 48 | 16#2C855CB2, 16#DEEEDFB1, 16#CDBE2C45, 16#3FD5AF46, 49 | 16#7198540D, 16#83F3D70E, 16#90A324FA, 16#62C8A7F9, 50 | 16#B602C312, 16#44694011, 16#5739B3E5, 16#A55230E6, 51 | 16#FB410CC2, 16#092A8FC1, 16#1A7A7C35, 16#E811FF36, 52 | 16#3CDB9BDD, 16#CEB018DE, 16#DDE0EB2A, 16#2F8B6829, 53 | 16#82F63B78, 16#709DB87B, 16#63CD4B8F, 16#91A6C88C, 54 | 16#456CAC67, 16#B7072F64, 16#A457DC90, 16#563C5F93, 55 | 16#082F63B7, 16#FA44E0B4, 16#E9141340, 16#1B7F9043, 56 | 16#CFB5F4A8, 16#3DDE77AB, 16#2E8E845F, 16#DCE5075C, 57 | 16#92A8FC17, 16#60C37F14, 16#73938CE0, 16#81F80FE3, 58 | 16#55326B08, 16#A759E80B, 16#B4091BFF, 16#466298FC, 59 | 16#1871A4D8, 16#EA1A27DB, 16#F94AD42F, 16#0B21572C, 60 | 16#DFEB33C7, 16#2D80B0C4, 16#3ED04330, 16#CCBBC033, 61 | 16#A24BB5A6, 16#502036A5, 16#4370C551, 16#B11B4652, 62 | 16#65D122B9, 16#97BAA1BA, 16#84EA524E, 16#7681D14D, 63 | 16#2892ED69, 16#DAF96E6A, 16#C9A99D9E, 16#3BC21E9D, 64 | 16#EF087A76, 16#1D63F975, 16#0E330A81, 16#FC588982, 65 | 16#B21572C9, 16#407EF1CA, 16#532E023E, 16#A145813D, 66 | 16#758FE5D6, 16#87E466D5, 16#94B49521, 16#66DF1622, 67 | 16#38CC2A06, 16#CAA7A905, 16#D9F75AF1, 16#2B9CD9F2, 68 | 16#FF56BD19, 16#0D3D3E1A, 16#1E6DCDEE, 16#EC064EED, 69 | 16#C38D26C4, 16#31E6A5C7, 16#22B65633, 16#D0DDD530, 70 | 16#0417B1DB, 16#F67C32D8, 16#E52CC12C, 16#1747422F, 71 | 16#49547E0B, 16#BB3FFD08, 16#A86F0EFC, 16#5A048DFF, 72 | 16#8ECEE914, 16#7CA56A17, 16#6FF599E3, 16#9D9E1AE0, 73 | 16#D3D3E1AB, 16#21B862A8, 16#32E8915C, 16#C083125F, 74 | 16#144976B4, 16#E622F5B7, 16#F5720643, 16#07198540, 75 | 16#590AB964, 16#AB613A67, 16#B831C993, 16#4A5A4A90, 76 | 16#9E902E7B, 16#6CFBAD78, 16#7FAB5E8C, 16#8DC0DD8F, 77 | 16#E330A81A, 16#115B2B19, 16#020BD8ED, 16#F0605BEE, 78 | 16#24AA3F05, 16#D6C1BC06, 16#C5914FF2, 16#37FACCF1, 79 | 16#69E9F0D5, 16#9B8273D6, 16#88D28022, 16#7AB90321, 80 | 16#AE7367CA, 16#5C18E4C9, 16#4F48173D, 16#BD23943E, 81 | 16#F36E6F75, 16#0105EC76, 16#12551F82, 16#E03E9C81, 82 | 16#34F4F86A, 16#C69F7B69, 16#D5CF889D, 16#27A40B9E, 83 | 16#79B737BA, 16#8BDCB4B9, 16#988C474D, 16#6AE7C44E, 84 | 16#BE2DA0A5, 16#4C4623A6, 16#5F16D052, 16#AD7D5351 85 | }). 86 | 87 | %% The interface mirrors erlang:crc32/1,2. 88 | -spec crc32c(iodata()) -> non_neg_integer(). 89 | crc32c(Data) -> 90 | do_crc32c(16#ffffffff, iolist_to_binary(Data)). 91 | 92 | -spec crc32c(CRC, iodata()) -> CRC when CRC::non_neg_integer(). 93 | crc32c(OldCrc, Data) -> 94 | do_crc32c(OldCrc bxor 16#ffffffff, iolist_to_binary(Data)). 95 | 96 | do_crc32c(OldCrc, <>) -> 97 | do_crc32c((OldCrc bsr 8) bxor element(1 + ((OldCrc bxor C) band 16#ff), ?CRC32C_TABLE), 98 | Rest); 99 | do_crc32c(OldCrc, <<>>) -> 100 | OldCrc bxor 16#ffffffff. 101 | 102 | -ifdef(TEST). 103 | crc32c_test_() -> 104 | Tests = [ 105 | %% Tests from RFC3720 B.4. 106 | {<<0:32/unit:8>>, 16#8a9136aa}, 107 | {iolist_to_binary([16#ff || _ <- lists:seq(1, 32)]), 16#62a8ab43}, 108 | {iolist_to_binary([N || N <- lists:seq(0, 16#1f)]), 16#46dd794e}, 109 | {iolist_to_binary([N || N <- lists:seq(16#1f, 0, -1)]), 16#113fdb5c}, 110 | {<<16#01c00000:32, 0:32, 0:32, 0:32, 16#14000000:32, 16#00000400:32, 16#00000014:32, 111 | 16#00000018:32, 16#28000000:32, 0:32, 16#02000000:32, 0:32>>, 16#d9963a56} 112 | ], 113 | [{iolist_to_binary(io_lib:format("16#~8.16.0b", [R])), 114 | fun() -> R = crc32c(V) end} || {V, R} <- Tests]. 115 | -endif. 116 | -------------------------------------------------------------------------------- /src/ranch_embedded_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Jan Uhlig 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_embedded_sup). 16 | 17 | -behavior(supervisor). 18 | 19 | -export([start_link/5]). 20 | -export([init/1]). 21 | 22 | -spec start_link(ranch:ref(), module(), any(), module(), any()) 23 | -> {ok, pid()}. 24 | start_link(Ref, Transport, TransOpts, Protocol, ProtoOpts) -> 25 | supervisor:start_link(?MODULE, {Ref, Transport, TransOpts, Protocol, ProtoOpts}). 26 | 27 | -spec init({ranch:ref(), module(), any(), module(), any()}) 28 | -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. 29 | init({Ref, Transport, TransOpts, Protocol, ProtoOpts}) -> 30 | Proxy = #{id => ranch_server_proxy, 31 | start => {ranch_server_proxy, start_link, []}, 32 | shutdown => brutal_kill}, 33 | Listener = #{id => {ranch_listener_sup, Ref}, 34 | start => {ranch_listener_sup, start_link, [Ref, Transport, TransOpts, Protocol, ProtoOpts]}, 35 | type => supervisor}, 36 | {ok, {#{strategy => rest_for_one}, [Proxy, Listener]}}. 37 | -------------------------------------------------------------------------------- /src/ranch_listener_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_listener_sup). 16 | -behaviour(supervisor). 17 | 18 | -export([start_link/5]). 19 | -export([init/1]). 20 | 21 | -spec start_link(ranch:ref(), module(), any(), module(), any()) 22 | -> {ok, pid()}. 23 | start_link(Ref, Transport, TransOpts, Protocol, ProtoOpts) -> 24 | MaxConns = maps:get(max_connections, TransOpts, 1024), 25 | Logger = maps:get(logger, TransOpts, logger), 26 | ranch_server:set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts, 27 | [Ref, Transport, TransOpts, Protocol, ProtoOpts]), 28 | supervisor:start_link(?MODULE, { 29 | Ref, Transport, Protocol, Logger 30 | }). 31 | 32 | -spec init({ranch:ref(), module(), module(), module()}) 33 | -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. 34 | init({Ref, Transport, Protocol, Logger}) -> 35 | ok = ranch_server:set_listener_sup(Ref, self()), 36 | ChildSpecs = [ 37 | #{ 38 | id => ranch_conns_sup_sup, 39 | start => {ranch_conns_sup_sup, start_link, [Ref, Transport, Protocol, Logger]}, 40 | type => supervisor 41 | }, 42 | #{ 43 | id => ranch_acceptors_sup, 44 | start => {ranch_acceptors_sup, start_link, [Ref, Transport, Logger]}, 45 | type => supervisor 46 | } 47 | ], 48 | {ok, {#{strategy => rest_for_one}, ChildSpecs}}. 49 | -------------------------------------------------------------------------------- /src/ranch_protocol.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_protocol). 16 | 17 | %% Start a new connection process for the given socket. 18 | -callback start_link( 19 | Ref::ranch:ref(), 20 | Transport::module(), 21 | ProtocolOptions::any()) 22 | -> {ok, ConnectionPid::pid()} 23 | | {ok, SupPid::pid(), ConnectionPid::pid()}. 24 | -------------------------------------------------------------------------------- /src/ranch_server_proxy.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Jan Uhlig 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_server_proxy). 16 | 17 | -behavior(gen_server). 18 | 19 | -export([start_link/0]). 20 | -export([init/1]). 21 | -export([handle_call/3]). 22 | -export([handle_cast/2]). 23 | -export([handle_info/2]). 24 | -export([code_change/3]). 25 | 26 | -spec start_link() -> {ok, pid()} | {error, term()}. 27 | start_link() -> 28 | gen_server:start_link(?MODULE, [], []). 29 | 30 | -spec init([]) -> {ok, pid()} | {stop, term()}. 31 | init([]) -> 32 | case wait_ranch_server(50) of 33 | {ok, Monitor} -> 34 | {ok, Monitor, hibernate}; 35 | {error, Reason} -> 36 | {stop, Reason} 37 | end. 38 | 39 | -spec handle_call(_, _, reference()) -> {noreply, reference(), hibernate}. 40 | handle_call(_, _, Monitor) -> 41 | {noreply, Monitor, hibernate}. 42 | 43 | -spec handle_cast(_, reference()) -> {noreply, reference(), hibernate}. 44 | handle_cast(_, Monitor) -> 45 | {noreply, Monitor, hibernate}. 46 | 47 | -spec handle_info(term(), reference()) -> {noreply, reference(), hibernate} | {stop, term(), reference()}. 48 | handle_info({'DOWN', Monitor, process, _, Reason}, Monitor) -> 49 | {stop, Reason, Monitor}; 50 | handle_info(_, Monitor) -> 51 | {noreply, Monitor, hibernate}. 52 | 53 | -spec code_change(term() | {down, term()}, reference(), term()) -> {ok, reference()}. 54 | code_change(_, Monitor, _) -> 55 | {ok, Monitor}. 56 | 57 | wait_ranch_server(N) -> 58 | case whereis(ranch_server) of 59 | undefined when N > 0 -> 60 | receive after 100 -> ok end, 61 | wait_ranch_server(N - 1); 62 | undefined -> 63 | {error, noproc}; 64 | Pid -> 65 | Monitor = monitor(process, Pid), 66 | {ok, Monitor} 67 | end. 68 | -------------------------------------------------------------------------------- /src/ranch_sup.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% Copyright (c) Jan Uhlig 3 | %% 4 | %% Permission to use, copy, modify, and/or distribute this software for any 5 | %% purpose with or without fee is hereby granted, provided that the above 6 | %% copyright notice and this permission notice appear in all copies. 7 | %% 8 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | -module(ranch_sup). 17 | -behaviour(supervisor). 18 | 19 | -export([start_link/0]). 20 | -export([init/1]). 21 | 22 | -spec start_link() -> {ok, pid()}. 23 | start_link() -> 24 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 25 | 26 | -spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. 27 | init([]) -> 28 | Intensity = case application:get_env(ranch_sup_intensity) of 29 | {ok, Value1} -> Value1; 30 | undefined -> 1 31 | end, 32 | Period = case application:get_env(ranch_sup_period) of 33 | {ok, Value2} -> Value2; 34 | undefined -> 5 35 | end, 36 | Procs = [ 37 | #{id => ranch_server, start => {ranch_server, start_link, []}} 38 | ], 39 | {ok, {#{intensity => Intensity, period => Period}, Procs}}. 40 | -------------------------------------------------------------------------------- /src/ranch_transport.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% Copyright (c) Jan Uhlig 3 | %% 4 | %% Permission to use, copy, modify, and/or distribute this software for any 5 | %% purpose with or without fee is hereby granted, provided that the above 6 | %% copyright notice and this permission notice appear in all copies. 7 | %% 8 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | -module(ranch_transport). 17 | 18 | -export([sendfile/6]). 19 | 20 | -type socket() :: any(). 21 | -export_type([socket/0]). 22 | 23 | -type opts() :: any(). 24 | -type stats() :: any(). 25 | -type sendfile_opts() :: [{chunk_size, non_neg_integer()}]. 26 | -export_type([sendfile_opts/0]). 27 | 28 | -callback name() -> atom(). 29 | -callback secure() -> boolean(). 30 | -callback messages() -> {OK::atom(), Closed::atom(), Error::atom(), Passive::atom()}. 31 | -callback listen(ranch:transport_opts(any())) -> {ok, socket()} | {error, atom()}. 32 | -callback accept(socket(), timeout()) 33 | -> {ok, socket()} | {error, closed | timeout | atom()}. 34 | -callback handshake(socket(), timeout()) -> {ok, socket()} | {ok, socket(), any()} | {error, any()}. 35 | -callback handshake(socket(), opts(), timeout()) -> {ok, socket()} | {ok, socket(), any()} | {error, any()}. 36 | -callback handshake_continue(socket(), timeout()) -> {ok, socket()} | {error, any()}. 37 | -callback handshake_continue(socket(), opts(), timeout()) -> {ok, socket()} | {error, any()}. 38 | -callback handshake_cancel(socket()) -> ok. 39 | -callback connect(string(), inet:port_number(), opts()) 40 | -> {ok, socket()} | {error, atom()}. 41 | -callback connect(string(), inet:port_number(), opts(), timeout()) 42 | -> {ok, socket()} | {error, atom()}. 43 | -callback recv(socket(), non_neg_integer(), timeout()) 44 | -> {ok, any()} | {error, closed | timeout | atom()}. 45 | -callback recv_proxy_header(socket(), timeout()) 46 | -> {ok, ranch_proxy_header:proxy_info()} 47 | | {error, closed | atom()} 48 | | {error, protocol_error, atom()}. 49 | -callback send(socket(), iodata()) -> ok | {error, atom()}. 50 | -callback sendfile(socket(), file:name_all() | file:fd()) 51 | -> {ok, non_neg_integer()} | {error, atom()}. 52 | -callback sendfile(socket(), file:name_all() | file:fd(), non_neg_integer(), 53 | non_neg_integer()) -> {ok, non_neg_integer()} | {error, atom()}. 54 | -callback sendfile(socket(), file:name_all() | file:fd(), non_neg_integer(), 55 | non_neg_integer(), sendfile_opts()) 56 | -> {ok, non_neg_integer()} | {error, atom()}. 57 | -callback setopts(socket(), opts()) -> ok | {error, atom()}. 58 | -callback getopts(socket(), [atom()]) -> {ok, opts()} | {error, atom()}. 59 | -callback getstat(socket()) -> {ok, stats()} | {error, atom()}. 60 | -callback getstat(socket(), [atom()]) -> {ok, stats()} | {error, atom()}. 61 | -callback controlling_process(socket(), pid()) 62 | -> ok | {error, closed | not_owner | atom()}. 63 | -callback peername(socket()) 64 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 65 | -callback sockname(socket()) 66 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 67 | -callback shutdown(socket(), read | write | read_write) 68 | -> ok | {error, atom()}. 69 | -callback close(socket()) -> ok. 70 | -callback cleanup(ranch:transport_opts(any())) -> ok. 71 | -callback format_error(term()) -> string(). 72 | 73 | %% TODO: Required callback in Ranch 3.0 74 | -optional_callbacks([format_error/1]). 75 | 76 | %% A fallback for transports that don't have a native sendfile implementation. 77 | %% Note that the ordering of arguments is different from file:sendfile/5 and 78 | %% that this function accepts either a raw file or a file name. 79 | -spec sendfile(module(), socket(), file:name_all() | file:fd(), 80 | non_neg_integer(), non_neg_integer(), sendfile_opts()) 81 | -> {ok, non_neg_integer()} | {error, atom()}. 82 | sendfile(Transport, Socket, Filename, Offset, Bytes, Opts) 83 | when is_list(Filename) orelse is_atom(Filename) 84 | orelse is_binary(Filename) -> 85 | ChunkSize = chunk_size(Opts), 86 | case file:open(Filename, [read, raw, binary]) of 87 | {ok, RawFile} -> 88 | _ = case Offset of 89 | 0 -> 90 | ok; 91 | _ -> 92 | {ok, _} = file:position(RawFile, {bof, Offset}) 93 | end, 94 | try 95 | sendfile_loop(Transport, Socket, RawFile, Bytes, 0, ChunkSize) 96 | after 97 | ok = file:close(RawFile) 98 | end; 99 | {error, _Reason} = Error -> 100 | Error 101 | end; 102 | sendfile(Transport, Socket, RawFile, Offset, Bytes, Opts) -> 103 | ChunkSize = chunk_size(Opts), 104 | Initial2 = case file:position(RawFile, {cur, 0}) of 105 | {ok, Offset} -> 106 | Offset; 107 | {ok, Initial} -> 108 | {ok, _} = file:position(RawFile, {bof, Offset}), 109 | Initial 110 | end, 111 | case sendfile_loop(Transport, Socket, RawFile, Bytes, 0, ChunkSize) of 112 | {ok, _Sent} = Result -> 113 | {ok, _} = file:position(RawFile, {bof, Initial2}), 114 | Result; 115 | {error, _Reason} = Error -> 116 | Error 117 | end. 118 | 119 | -spec chunk_size(sendfile_opts()) -> pos_integer(). 120 | chunk_size(Opts) -> 121 | case lists:keyfind(chunk_size, 1, Opts) of 122 | {chunk_size, ChunkSize} 123 | when is_integer(ChunkSize) andalso ChunkSize > 0 -> 124 | ChunkSize; 125 | {chunk_size, 0} -> 126 | 16#1FFF; 127 | false -> 128 | 16#1FFF 129 | end. 130 | 131 | -spec sendfile_loop(module(), socket(), file:fd(), non_neg_integer(), 132 | non_neg_integer(), pos_integer()) 133 | -> {ok, non_neg_integer()} | {error, any()}. 134 | sendfile_loop(_Transport, _Socket, _RawFile, Sent, Sent, _ChunkSize) 135 | when Sent =/= 0 -> 136 | %% All requested data has been read and sent, return number of bytes sent. 137 | {ok, Sent}; 138 | sendfile_loop(Transport, Socket, RawFile, Bytes, Sent, ChunkSize) -> 139 | ReadSize = read_size(Bytes, Sent, ChunkSize), 140 | case file:read(RawFile, ReadSize) of 141 | {ok, IoData} -> 142 | case Transport:send(Socket, IoData) of 143 | ok -> 144 | Sent2 = iolist_size(IoData) + Sent, 145 | sendfile_loop(Transport, Socket, RawFile, Bytes, Sent2, 146 | ChunkSize); 147 | {error, _Reason} = Error -> 148 | Error 149 | end; 150 | eof -> 151 | {ok, Sent}; 152 | {error, _Reason} = Error -> 153 | Error 154 | end. 155 | 156 | -spec read_size(non_neg_integer(), non_neg_integer(), non_neg_integer()) -> 157 | non_neg_integer(). 158 | read_size(0, _Sent, ChunkSize) -> 159 | ChunkSize; 160 | read_size(Bytes, Sent, ChunkSize) -> 161 | min(Bytes - Sent, ChunkSize). 162 | -------------------------------------------------------------------------------- /test/active_echo_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(active_echo_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | loop(Socket, Transport). 14 | 15 | loop(Socket, Transport) -> 16 | {OK, Closed, Error, _Passive} = Transport:messages(), 17 | Transport:setopts(Socket, [{active, once}]), 18 | receive 19 | {OK, Socket, Data} -> 20 | Transport:send(Socket, Data), 21 | loop(Socket, Transport); 22 | {Closed, Socket} -> 23 | ok; 24 | {Error, Socket, _} -> 25 | ok = Transport:close(Socket) 26 | end. 27 | -------------------------------------------------------------------------------- /test/batch_echo_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(batch_echo_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, [{batch_size, N}]) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, N]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, N) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | Transport:setopts(Socket, [{active, N}]), 14 | loop(Socket, Transport, N, <<>>). 15 | 16 | loop(Socket, Transport, N, Acc) -> 17 | {OK, Closed, Error, Passive} = Transport:messages(), 18 | receive 19 | {OK, Socket, Data} -> 20 | Transport:send(Socket, <<"OK">>), 21 | loop(Socket, Transport, N, <>); 22 | {Passive, Socket} -> 23 | Transport:send(Socket, Acc), 24 | Transport:setopts(Socket, [{active, N}]), 25 | loop(Socket, Transport, N, <<>>); 26 | {Closed, Socket} -> 27 | ok; 28 | {Error, Socket, _} -> 29 | ok = Transport:close(Socket) 30 | end. 31 | -------------------------------------------------------------------------------- /test/check_tcp_options.erl: -------------------------------------------------------------------------------- 1 | -module(check_tcp_options). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, _, [{pid, TestPid}|TcpOptions]) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, TestPid, TcpOptions]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Pid, TcpOptions) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | {ok, RealTcpOptions} = inet:getopts(Socket, [Key || {Key, _} <- TcpOptions]), 14 | true = TcpOptions =:= RealTcpOptions, 15 | Pid ! checked, 16 | receive after 2500 -> ok end. 17 | -------------------------------------------------------------------------------- /test/cover.spec: -------------------------------------------------------------------------------- 1 | {incl_app, ranch, details}. 2 | -------------------------------------------------------------------------------- /test/crash_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(crash_protocol). 2 | 3 | -export([start_link/4]). 4 | 5 | -spec start_link(_, _, _, _) -> no_return(). 6 | start_link(_, _, _, _) -> 7 | exit(crash). 8 | -------------------------------------------------------------------------------- /test/echo_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(echo_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | loop(Socket, Transport). 14 | 15 | loop(Socket, Transport) -> 16 | case Transport:recv(Socket, 0, 5000) of 17 | {ok, Data} -> 18 | Transport:send(Socket, Data), 19 | loop(Socket, Transport); 20 | _ -> 21 | ok = Transport:close(Socket) 22 | end. 23 | -------------------------------------------------------------------------------- /test/embedded_sup.erl: -------------------------------------------------------------------------------- 1 | -module(embedded_sup). 2 | -behaviour(supervisor). 3 | -export([init/1]). 4 | 5 | -export([start_link/0]). 6 | -export([stop/1]). 7 | -export([start_listener/6]). 8 | -export([stop_listener/2]). 9 | 10 | start_link() -> 11 | supervisor:start_link(?MODULE, []). 12 | 13 | stop(SupPid) -> 14 | erlang:exit(SupPid, normal). 15 | 16 | init([]) -> 17 | {ok, {{one_for_one, 10, 10}, []}}. 18 | 19 | start_listener(SupPid, Ref, Transport, TransOpts, Protocol, ProtoOpts) -> 20 | supervisor:start_child( 21 | SupPid, 22 | ranch:child_spec(Ref, Transport, TransOpts, Protocol, ProtoOpts) 23 | ). 24 | 25 | stop_listener(SupPid, Ref) -> 26 | ok = supervisor:terminate_child(SupPid, {ranch_embedded_sup, Ref}), 27 | ok = supervisor:delete_child(SupPid, {ranch_embedded_sup, Ref}), 28 | ranch_server:cleanup_listener_opts(Ref). 29 | -------------------------------------------------------------------------------- /test/handshake_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(handshake_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, Opts) -> 12 | SniHost = case ranch:handshake(Ref) of 13 | %% Due to a bug in ssl (https://bugs.erlang.org/browse/ERL-951, 14 | %% fixed in OTP 22.0.3) the value for sni may be {sni, Hostname} 15 | %% instead of Hostname. 16 | {continue, #{sni := {sni, Hostname}}} -> 17 | Hostname; 18 | {continue, #{sni := Hostname}} -> 19 | Hostname 20 | end, 21 | SniHostOpts = maps:get(SniHost, Opts), 22 | {ok, Socket} = ranch:handshake_continue(Ref, SniHostOpts), 23 | loop(Socket, Transport). 24 | 25 | loop(Socket, Transport) -> 26 | case Transport:recv(Socket, 0, 5000) of 27 | {ok, Data} -> 28 | Transport:send(Socket, Data), 29 | loop(Socket, Transport); 30 | _ -> 31 | ok = Transport:close(Socket) 32 | end. 33 | -------------------------------------------------------------------------------- /test/notify_and_wait_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(notify_and_wait_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/4]). 6 | 7 | start_link(_, _, Opts = #{pid := TestPid}) -> 8 | Msg = maps:get(msg, Opts, connected), 9 | TerminateMsg = maps:get(terminate_msg, Opts, stop), 10 | Timeout = maps:get(timeout, Opts, infinity), 11 | Pid = spawn_link(?MODULE, init, [Msg, TestPid, TerminateMsg, Timeout]), 12 | {ok, Pid}. 13 | 14 | init(Msg, Pid, TerminateMsg, Timeout) -> 15 | Pid ! {self(), Msg}, 16 | receive TerminateMsg -> ok after Timeout -> ok end. 17 | -------------------------------------------------------------------------------- /test/proxy_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(proxy_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | {ok, ProxyInfo} = ranch:recv_proxy_header(Ref, 1000), 13 | {ok, Socket} = ranch:handshake(Ref), 14 | Pid = case Transport of 15 | ranch_tcp -> ct_helper:get_remote_pid_tcp(Socket); 16 | ranch_ssl -> ct_helper:get_remote_pid_tls(Socket) 17 | end, 18 | Pid ! {?MODULE, ProxyInfo}, 19 | loop(Socket, Transport). 20 | 21 | loop(Socket, Transport) -> 22 | case Transport:recv(Socket, 0, 5000) of 23 | {ok, Data} -> 24 | _ = Transport:send(Socket, Data), 25 | loop(Socket, Transport); 26 | _ -> 27 | ok = Transport:close(Socket) 28 | end. 29 | -------------------------------------------------------------------------------- /test/ranch_concuerror.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_concuerror). 16 | -compile(export_all). 17 | -compile(nowarn_export_all). 18 | 19 | -concuerror_options([ 20 | {after_timeout, 5000}, 21 | {treat_as_normal, [ 22 | killed, %% Acceptors are killed on shutdown. 23 | shutdown %% This is a normal exit reason in OTP. 24 | ]} 25 | ]). 26 | 27 | %% Convenience functions. 28 | 29 | do_start() -> 30 | {ok, SupPid} = ranch_app:start(normal, []), 31 | SupPid. 32 | 33 | -spec do_stop(pid()) -> no_return(). 34 | do_stop(SupPid) -> 35 | exit(SupPid, shutdown), 36 | %% We make sure that SupPid terminated before the test ends, 37 | %% because otherwise the shutdown will not be ordered and 38 | %% can produce error exit reasons. 39 | receive after infinity -> ok end. 40 | 41 | %% Tests. 42 | 43 | -spec start_stop() -> no_return(). 44 | start_stop() -> 45 | %% Start a listener then stop it. 46 | SupPid = do_start(), 47 | {ok, _} = ranch:start_listener(?FUNCTION_NAME, 48 | ranch_erlang_transport, #{ 49 | num_acceptors => 1 50 | }, 51 | echo_protocol, []), 52 | ok = ranch:stop_listener(?FUNCTION_NAME), 53 | do_stop(SupPid). 54 | 55 | %% @todo This takes a huge amount of time. 56 | %start_stop_twice() -> 57 | % %% Start a listener then stop it. Then start and stop it again. 58 | % SupPid = do_start(), 59 | % {ok, _} = ranch:start_listener(?FUNCTION_NAME, 60 | % ranch_erlang_transport, #{ 61 | % num_acceptors => 1 62 | % }, 63 | % echo_protocol, []), 64 | % ok = ranch:stop_listener(?FUNCTION_NAME), 65 | % {ok, _} = ranch:start_listener(?FUNCTION_NAME, 66 | % ranch_erlang_transport, #{ 67 | % num_acceptors => 1 68 | % }, 69 | % echo_protocol, []), 70 | % ok = ranch:stop_listener(?FUNCTION_NAME), 71 | % do_stop(SupPid). 72 | 73 | -spec info() -> no_return(). 74 | info() -> 75 | %% Ensure we can call ranch:info/1 after starting a listener. 76 | SupPid = do_start(), 77 | {ok, _} = ranch:start_listener(?FUNCTION_NAME, 78 | ranch_erlang_transport, #{ 79 | num_acceptors => 1 80 | }, 81 | echo_protocol, []), 82 | #{} = ranch:info(?FUNCTION_NAME), 83 | do_stop(SupPid). 84 | -------------------------------------------------------------------------------- /test/ranch_ct_hook.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_ct_hook). 16 | 17 | -export([init/2]). 18 | 19 | init(_, _) -> 20 | %% Allow a more relaxed restart intensity because 21 | %% some tests will cause quick restarts of several 22 | %% ranch_sup children. 23 | application:set_env(ranch, ranch_sup_intensity, 10), 24 | application:set_env(ranch, ranch_sup_period, 1), 25 | ok = application:load(ssl), 26 | case {os:type(), application:get_key(ssl, vsn)} of 27 | %% Internal active,N is broken on Windows since 28 | %% OTP 21.2/ssl 9.1. 29 | %% @todo Put an upper limit on the version when 30 | %% this is fixed in a future OTP version. 31 | {_, {ok, "9.0"++_}} -> 32 | ok; 33 | {{win32, nt}, {ok, "9."++_}} -> 34 | application:set_env(ssl, internal_active_n, 1); 35 | {{win32, nt}, {ok, "10."++_}} -> 36 | application:set_env(ssl, internal_active_n, 1); 37 | _ -> 38 | ok 39 | end, 40 | ct_helper:start([ranch]), 41 | ct_helper:make_certs_in_ets(), 42 | error_logger:add_report_handler(ct_helper_error_h), 43 | {ok, undefined}. 44 | -------------------------------------------------------------------------------- /test/ranch_erlang_transport.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_erlang_transport). 16 | -behaviour(ranch_transport). 17 | 18 | -export([name/0]). 19 | -export([secure/0]). 20 | -export([messages/0]). 21 | -export([listen/1]). 22 | -export([accept/2]). 23 | -export([handshake/2]). 24 | -export([handshake/3]). 25 | -export([handshake_continue/2]). 26 | -export([handshake_continue/3]). 27 | -export([handshake_cancel/1]). 28 | -export([connect/3]). 29 | -export([connect/4]). 30 | -export([recv/3]). 31 | -export([recv_proxy_header/2]). 32 | -export([send/2]). 33 | -export([sendfile/2]). 34 | -export([sendfile/4]). 35 | -export([sendfile/5]). 36 | -export([setopts/2]). 37 | -export([getopts/2]). 38 | -export([getstat/1]). 39 | -export([getstat/2]). 40 | -export([controlling_process/2]). 41 | -export([peername/1]). 42 | -export([sockname/1]). 43 | -export([shutdown/2]). 44 | -export([close/1]). 45 | -export([cleanup/1]). 46 | 47 | -type opts() :: []. 48 | -export_type([opts/0]). 49 | 50 | -spec name() -> erlang. 51 | name() -> erlang. 52 | 53 | -spec secure() -> boolean(). 54 | secure() -> 55 | false. 56 | 57 | -spec messages() -> {erlang, erlang_closed, erlang_error, erlang_passive}. 58 | messages() -> {erlang, erlang_closed, erlang_error, erlang_passive}. 59 | 60 | -spec listen(ranch:transport_opts(opts())) -> {ok, reference()}. 61 | listen(_TransOpts) -> 62 | {ok, make_ref()}. 63 | 64 | -spec accept(reference(), timeout()) -> no_return(). % {ok, reference()}. 65 | accept(_LSocket, _Timeout) -> 66 | receive after infinity -> {ok, make_ref()} end. 67 | 68 | -spec handshake(reference(), timeout()) -> {ok, reference()}. 69 | handshake(CSocket, Timeout) -> 70 | handshake(CSocket, [], Timeout). 71 | 72 | -spec handshake(reference(), opts(), timeout()) -> {ok, reference()}. 73 | handshake(CSocket, _, _) -> 74 | {ok, CSocket}. 75 | 76 | -spec handshake_continue(reference(), timeout()) -> no_return(). 77 | handshake_continue(CSocket, Timeout) -> 78 | handshake_continue(CSocket, [], Timeout). 79 | 80 | -spec handshake_continue(reference(), opts(), timeout()) -> no_return(). 81 | handshake_continue(_, _, _) -> 82 | error(not_supported). 83 | 84 | -spec handshake_cancel(reference()) -> no_return(). 85 | handshake_cancel(_) -> 86 | error(not_supported). 87 | 88 | -spec connect(inet:ip_address() | inet:hostname(), 89 | inet:port_number(), any()) 90 | -> {ok, reference()}. 91 | connect(_Host, Port, _Opts) when is_integer(Port) -> 92 | {ok, make_ref()}. 93 | 94 | -spec connect(inet:ip_address() | inet:hostname(), 95 | inet:port_number(), any(), timeout()) 96 | -> {ok, reference()}. 97 | connect(_Host, Port, _Opts, _Timeout) when is_integer(Port) -> 98 | {ok, make_ref()}. 99 | 100 | -spec recv(reference(), non_neg_integer(), timeout()) 101 | -> {ok, any()} | {error, closed | atom()}. 102 | recv(_Socket, _Length, _Timeout) -> 103 | {ok, <<>>}. 104 | 105 | -spec recv_proxy_header(reference(), timeout()) -> no_return(). 106 | recv_proxy_header(_Socket, _Timeout) -> 107 | error(not_supported). 108 | 109 | -spec send(reference(), iodata()) -> ok | {error, atom()}. 110 | send(_Socket, _Packet) -> 111 | ok. 112 | 113 | -spec sendfile(reference(), file:name_all() | file:fd()) 114 | -> no_return(). 115 | sendfile(Socket, Filename) -> 116 | sendfile(Socket, Filename, 0, 0, []). 117 | 118 | -spec sendfile(reference(), file:name_all() | file:fd(), non_neg_integer(), 119 | non_neg_integer()) 120 | -> no_return(). 121 | sendfile(Socket, File, Offset, Bytes) -> 122 | sendfile(Socket, File, Offset, Bytes, []). 123 | 124 | -spec sendfile(reference(), file:name_all() | file:fd(), non_neg_integer(), 125 | non_neg_integer(), [{chunk_size, non_neg_integer()}]) 126 | -> no_return(). 127 | sendfile(_Socket, Filename, _Offset, _Bytes, _Opts) 128 | when is_list(Filename) orelse is_atom(Filename) 129 | orelse is_binary(Filename) -> 130 | error(not_supported). 131 | 132 | -spec setopts(reference(), list()) -> ok. 133 | setopts(_Socket, _Opts) -> 134 | ok. 135 | 136 | -spec getopts(reference(), [atom()]) -> {ok, list()} | {error, atom()}. 137 | getopts(_Socket, _Opts) -> 138 | {ok, []}. 139 | 140 | -spec getstat(reference()) -> {ok, list()} | {error, atom()}. 141 | getstat(_Socket) -> 142 | {ok, []}. 143 | 144 | -spec getstat(reference(), [atom()]) -> {ok, list()} | {error, atom()}. 145 | getstat(_Socket, _OptionNames) -> 146 | {ok, []}. 147 | 148 | -spec controlling_process(reference(), pid()) 149 | -> ok | {error, closed | not_owner | atom()}. 150 | controlling_process(_Socket, _Pid) -> 151 | ok. 152 | 153 | -spec peername(reference()) 154 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 155 | peername(_Socket) -> 156 | {ok, {{127, 0, 0, 1}, 12701}}. 157 | 158 | -spec sockname(reference()) 159 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 160 | sockname(_Socket) -> 161 | {ok, {{127, 0, 0, 1}, 12710}}. 162 | 163 | -spec shutdown(reference(), read | write | read_write) 164 | -> ok | {error, atom()}. 165 | shutdown(_Socket, _How) -> 166 | ok. 167 | 168 | -spec close(reference()) -> ok. 169 | close(_Socket) -> 170 | ok. 171 | 172 | -spec cleanup(ranch:transport_opts(opts())) -> ok. 173 | cleanup(_) -> 174 | ok. 175 | -------------------------------------------------------------------------------- /test/ranch_listen_error_transport.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Jan Uhlig 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(ranch_listen_error_transport). 16 | -behaviour(ranch_transport). 17 | 18 | -export([name/0]). 19 | -export([secure/0]). 20 | -export([messages/0]). 21 | -export([listen/1]). 22 | -export([disallowed_listen_options/0]). 23 | -export([accept/2]). 24 | -export([handshake/2]). 25 | -export([handshake/3]). 26 | -export([handshake_continue/2]). 27 | -export([handshake_continue/3]). 28 | -export([handshake_cancel/1]). 29 | -export([connect/3]). 30 | -export([connect/4]). 31 | -export([recv/3]). 32 | -export([recv_proxy_header/2]). 33 | -export([send/2]). 34 | -export([sendfile/2]). 35 | -export([sendfile/4]). 36 | -export([sendfile/5]). 37 | -export([setopts/2]). 38 | -export([getopts/2]). 39 | -export([getstat/1]). 40 | -export([getstat/2]). 41 | -export([controlling_process/2]). 42 | -export([peername/1]). 43 | -export([sockname/1]). 44 | -export([shutdown/2]). 45 | -export([close/1]). 46 | -export([cleanup/1]). 47 | -export([format_error/1]). 48 | 49 | -type opt() :: ranch_tcp:opt(). 50 | -export_type([opt/0]). 51 | 52 | -type opts() :: ranch_tcp:opts(). 53 | -export_type([opts/0]). 54 | 55 | -spec name() -> tcp. 56 | name() -> tcp. 57 | 58 | -spec secure() -> boolean(). 59 | secure() -> 60 | false. 61 | 62 | -spec messages() -> {tcp, tcp_closed, tcp_error, tcp_passive}. 63 | messages() -> {tcp, tcp_closed, tcp_error, tcp_passive}. 64 | 65 | -spec listen(ranch:transport_opts(opts())) -> {ok, inet:socket()} | {error, atom()}. 66 | listen(_TransOpts) -> 67 | {error, {?MODULE, listen_error}}. 68 | 69 | -spec disallowed_listen_options() -> [atom()]. 70 | disallowed_listen_options() -> 71 | ranch_tcp:disallowed_listen_options(). 72 | 73 | -spec accept(inet:socket(), timeout()) 74 | -> {ok, inet:socket()} | {error, closed | timeout | atom()}. 75 | accept(LSocket, Timeout) -> 76 | ranch_tcp:accept(LSocket, Timeout). 77 | 78 | -spec handshake(inet:socket(), timeout()) -> {ok, inet:socket()}. 79 | handshake(CSocket, Timeout) -> 80 | iranch_tcp:handshake(CSocket, Timeout). 81 | 82 | -spec handshake(inet:socket(), opts(), timeout()) -> {ok, inet:socket()}. 83 | handshake(CSocket, Opts, Timeout) -> 84 | ranch_tcp:handshake(CSocket, Opts, Timeout). 85 | 86 | -spec handshake_continue(inet:socket(), timeout()) -> no_return(). 87 | handshake_continue(CSocket, Timeout) -> 88 | ranch_tcp:handshake_continue(CSocket, Timeout). 89 | 90 | -spec handshake_continue(inet:socket(), opts(), timeout()) -> no_return(). 91 | handshake_continue(CSocket, Opts, Timeout) -> 92 | ranch_tcp:handshake_continue(CSocket, Opts, Timeout). 93 | 94 | -spec handshake_cancel(inet:socket()) -> no_return(). 95 | handshake_cancel(CSocket) -> 96 | ranch_tcp:handshake_cancel(CSocket). 97 | 98 | %% @todo Probably filter Opts? 99 | -spec connect(inet:ip_address() | inet:hostname(), 100 | inet:port_number(), any()) 101 | -> {ok, inet:socket()} | {error, atom()}. 102 | connect(Host, Port, Opts) when is_integer(Port) -> 103 | ranch_tcp:connect(Host, Port, Opts). 104 | 105 | %% @todo Probably filter Opts? 106 | -spec connect(inet:ip_address() | inet:hostname(), 107 | inet:port_number(), any(), timeout()) 108 | -> {ok, inet:socket()} | {error, atom()}. 109 | connect(Host, Port, Opts, Timeout) when is_integer(Port) -> 110 | ranch_tcp:connect(Host, Port, Opts, Timeout). 111 | 112 | -spec recv(inet:socket(), non_neg_integer(), timeout()) 113 | -> {ok, any()} | {error, closed | atom()}. 114 | recv(Socket, Length, Timeout) -> 115 | ranch_tcp:recv(Socket, Length, Timeout). 116 | 117 | -spec recv_proxy_header(inet:socket(), timeout()) 118 | -> {ok, ranch_proxy_header:proxy_info()} 119 | | {error, closed | atom()} 120 | | {error, protocol_error, atom()}. 121 | recv_proxy_header(Socket, Timeout) -> 122 | ranch_tcp:recv_proxy_header(Socket, Timeout). 123 | 124 | -spec send(inet:socket(), iodata()) -> ok | {error, atom()}. 125 | send(Socket, Packet) -> 126 | ranch_tcp:send(Socket, Packet). 127 | 128 | -spec sendfile(inet:socket(), file:name_all() | file:fd()) 129 | -> {ok, non_neg_integer()} | {error, atom()}. 130 | sendfile(Socket, Filename) -> 131 | ranch_tcp:sendfile(Socket, Filename). 132 | 133 | -spec sendfile(inet:socket(), file:name_all() | file:fd(), non_neg_integer(), 134 | non_neg_integer()) 135 | -> {ok, non_neg_integer()} | {error, atom()}. 136 | sendfile(Socket, File, Offset, Bytes) -> 137 | ranch_tcp:sendfile(Socket, File, Offset, Bytes). 138 | 139 | -spec sendfile(inet:socket(), file:name_all() | file:fd(), non_neg_integer(), 140 | non_neg_integer(), [{chunk_size, non_neg_integer()}]) 141 | -> {ok, non_neg_integer()} | {error, atom()}. 142 | sendfile(Socket, Filename, Offset, Bytes, Opts) -> 143 | ranch_tcp:sendfile(Socket, Filename, Offset, Bytes, Opts). 144 | 145 | %% @todo Probably filter Opts? 146 | -spec setopts(inet:socket(), list()) -> ok | {error, atom()}. 147 | setopts(Socket, Opts) -> 148 | ranch_tcp:setopts(Socket, Opts). 149 | 150 | -spec getopts(inet:socket(), [atom()]) -> {ok, list()} | {error, atom()}. 151 | getopts(Socket, Opts) -> 152 | ranch_tcp:getopts(Socket, Opts). 153 | 154 | -spec getstat(inet:socket()) -> {ok, list()} | {error, atom()}. 155 | getstat(Socket) -> 156 | ranch_tcp:getstat(Socket). 157 | 158 | -spec getstat(inet:socket(), [atom()]) -> {ok, list()} | {error, atom()}. 159 | getstat(Socket, OptionNames) -> 160 | ranch_tcp:getstat(Socket, OptionNames). 161 | 162 | -spec controlling_process(inet:socket(), pid()) 163 | -> ok | {error, closed | not_owner | atom()}. 164 | controlling_process(Socket, Pid) -> 165 | ranch_tcp:controlling_process(Socket, Pid). 166 | 167 | -spec peername(inet:socket()) 168 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 169 | peername(Socket) -> 170 | ranch_tcp:peername(Socket). 171 | 172 | -spec sockname(inet:socket()) 173 | -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. 174 | sockname(Socket) -> 175 | ranch_tcp:sockname(Socket). 176 | 177 | -spec shutdown(inet:socket(), read | write | read_write) 178 | -> ok | {error, atom()}. 179 | shutdown(Socket, How) -> 180 | ranch_tcp:shutdown(Socket, How). 181 | 182 | -spec close(inet:socket()) -> ok. 183 | close(Socket) -> 184 | ranch_tcp:close(Socket). 185 | 186 | -spec cleanup(ranch:transport_opts(opts())) -> ok. 187 | cleanup(Opts) -> 188 | ranch_tcp:cleanup(Opts). 189 | 190 | -spec format_error(inet:posix() | system_limit) -> string(). 191 | format_error({?MODULE, Reason}) -> 192 | io_lib:format("There was an error in ~0p: ~0p", [?MODULE, Reason]); 193 | format_error(Reason) -> 194 | ranch_tcp:format_error(Reason). 195 | -------------------------------------------------------------------------------- /test/remove_conn_and_wait_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(remove_conn_and_wait_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, _, [{remove, MaybeRemove, Timeout}]) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, MaybeRemove, Timeout]), 9 | {ok, Pid}. 10 | 11 | init(Ref, MaybeRemove, Timeout) -> 12 | {ok, _} = ranch:handshake(Ref), 13 | _ = case MaybeRemove of 14 | true -> 15 | ranch:remove_connection(Ref); 16 | false -> 17 | ok; 18 | N -> 19 | [ranch:remove_connection(Ref) || _ <- lists:seq(1, N)] 20 | end, 21 | receive after Timeout -> ok end. 22 | -------------------------------------------------------------------------------- /test/shutdown_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(shutdown_SUITE). 16 | -compile(export_all). 17 | -compile(nowarn_export_all). 18 | 19 | -import(ct_helper, [doc/1]). 20 | -import(ct_helper, [name/0]). 21 | 22 | %% ct. 23 | 24 | all() -> 25 | ct_helper:all(?MODULE). 26 | 27 | %% Tests. 28 | 29 | brutal_kill(_) -> 30 | doc("Shutdown Ranch listener with shutdown option set to brutal_kill."), 31 | Name = name(), 32 | {ok, ListenerSup} = ranch:start_listener(Name, 33 | ranch_tcp, #{shutdown => brutal_kill}, 34 | echo_protocol, []), 35 | Port = ranch:get_port(Name), 36 | ok = do_connect_and_ping(Port), 37 | ListenerSupChildren = supervisor:which_children(ListenerSup), 38 | {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren), 39 | [Pid] = do_get_conn_pids(ConnsSupSup), 40 | true = is_process_alive(Pid), 41 | ok = ranch:stop_listener(Name), 42 | receive after 100 -> ok end, 43 | false = is_process_alive(Pid), 44 | false = is_process_alive(ListenerSup), 45 | {error, _} = gen_tcp:connect("localhost", Port, []), 46 | ok. 47 | 48 | infinity(_) -> 49 | doc("Shutdown Ranch listener with shutdown option set to infinity."), 50 | Name = name(), 51 | {ok, ListenerSup} = ranch:start_listener(Name, 52 | ranch_tcp, #{shutdown => infinity}, 53 | echo_protocol, []), 54 | Port = ranch:get_port(Name), 55 | ok = do_connect_and_ping(Port), 56 | ListenerSupChildren = supervisor:which_children(ListenerSup), 57 | {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren), 58 | [Pid] = do_get_conn_pids(ConnsSupSup), 59 | true = is_process_alive(Pid), 60 | ok = ranch:stop_listener(Name), 61 | receive after 100 -> ok end, 62 | false = is_process_alive(Pid), 63 | false = is_process_alive(ListenerSup), 64 | {error, _} = gen_tcp:connect("localhost", Port, []), 65 | ok. 66 | 67 | infinity_trap_exit(_) -> 68 | doc("Shutdown Ranch listener with shutdown option set to infinity " 69 | "and protocol process trapping exits. The listener must not stop " 70 | "until the protocol process terminates."), 71 | Name = name(), 72 | {ok, ListenerSup} = ranch:start_listener(Name, 73 | ranch_tcp, #{shutdown => infinity}, 74 | trap_exit_protocol, []), 75 | Port = ranch:get_port(Name), 76 | ok = do_connect_and_ping(Port), 77 | ListenerSupChildren = supervisor:which_children(ListenerSup), 78 | {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren), 79 | [Pid] = do_get_conn_pids(ConnsSupSup), 80 | true = is_process_alive(Pid), 81 | %% This call will block infinitely. 82 | SpawnPid = spawn(fun() -> ok = ranch:stop_listener(Name) end), 83 | receive after 100 -> ok end, 84 | %% The protocol traps exit signals, and ignore them, so it won't die. 85 | true = is_process_alive(Pid), 86 | %% The listener will stay up forever too. 87 | true = is_process_alive(ListenerSup), 88 | %% We can't connect, though. 89 | {error, _} = gen_tcp:connect("localhost", Port, []), 90 | %% Killing the process unblocks everything. 91 | exit(Pid, kill), 92 | receive after 100 -> ok end, 93 | false = is_process_alive(ListenerSup), 94 | false = is_process_alive(SpawnPid), 95 | ok. 96 | 97 | timeout(_) -> 98 | doc("Shutdown Ranch listener with shutdown option set to 500ms."), 99 | Name = name(), 100 | {ok, ListenerSup} = ranch:start_listener(Name, 101 | ranch_tcp, #{shutdown => 500}, 102 | echo_protocol, []), 103 | Port = ranch:get_port(Name), 104 | ok = do_connect_and_ping(Port), 105 | ListenerSupChildren = supervisor:which_children(ListenerSup), 106 | {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren), 107 | [Pid] = do_get_conn_pids(ConnsSupSup), 108 | true = is_process_alive(Pid), 109 | ok = ranch:stop_listener(Name), 110 | receive after 100 -> ok end, 111 | false = is_process_alive(Pid), 112 | false = is_process_alive(ListenerSup), 113 | {error, _} = gen_tcp:connect("localhost", Port, []), 114 | ok. 115 | 116 | timeout_trap_exit(_) -> 117 | doc("Shutdown Ranch listener with shutdown option set to 500ms " 118 | "and protocol process trapping exits. The listener will only stop " 119 | "after the 500ms timeout."), 120 | Name = name(), 121 | {ok, ListenerSup} = ranch:start_listener(Name, 122 | ranch_tcp, #{shutdown => 500}, 123 | trap_exit_protocol, []), 124 | Port = ranch:get_port(Name), 125 | ok = do_connect_and_ping(Port), 126 | ListenerSupChildren = supervisor:which_children(ListenerSup), 127 | {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren), 128 | [Pid] = do_get_conn_pids(ConnsSupSup), 129 | true = is_process_alive(Pid), 130 | %% This call will block for the duration of the shutdown. 131 | SpawnPid = spawn(fun() -> ok = ranch:stop_listener(Name) end), 132 | receive after 100 -> ok end, 133 | %% The protocol traps exit signals, and ignore them, so it won't die. 134 | true = is_process_alive(Pid), 135 | %% The listener will stay up for now too. 136 | true = is_process_alive(ListenerSup), 137 | %% We can't connect, though. 138 | {error, _} = gen_tcp:connect("localhost", Port, []), 139 | %% Wait for the timeout to finish and see that everything is killed. 140 | receive after 500 -> ok end, 141 | false = is_process_alive(Pid), 142 | false = is_process_alive(ListenerSup), 143 | false = is_process_alive(SpawnPid), 144 | ok. 145 | 146 | do_get_conn_pids(ConnsSupSup) -> 147 | ConnsSups = [ConnsSup || 148 | {_, ConnsSup, _, _} <- supervisor:which_children(ConnsSupSup)], 149 | ConnChildren = lists:flatten( 150 | [supervisor:which_children(ConnsSup) || ConnsSup <- ConnsSups]), 151 | [ConnPid || {_, ConnPid, _, _} <- ConnChildren]. 152 | 153 | do_connect_and_ping(Port) -> 154 | {ok, Conn} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]), 155 | ok = gen_tcp:send(Conn, <<"PING">>), 156 | {ok, <<"PING">>} = gen_tcp:recv(Conn, 4, 1000), 157 | ok. 158 | -------------------------------------------------------------------------------- /test/ssl_upgrade_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(ssl_upgrade_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | loop(Socket, Transport). 14 | 15 | loop(Socket, Transport) -> 16 | case Transport:recv(Socket, 0, 5000) of 17 | {ok, <<"UPGRADE">>} when Transport =:= ranch_tcp -> 18 | ok = Transport:send(Socket, <<"READY">>), 19 | Opts = ct_helper:get_certs_from_ets(), 20 | {ok, NewSocket} = ranch_ssl:handshake(Socket, 21 | [{fail_if_no_peer_cert, false}, {verify, verify_none}|Opts], 1000), 22 | loop(NewSocket, ranch_ssl); 23 | {ok, <<"ECHO ", More/binary>>} -> 24 | ok = Transport:send(Socket, More), 25 | loop(Socket, Transport); 26 | _ -> 27 | ok = Transport:close(Socket) 28 | end. 29 | -------------------------------------------------------------------------------- /test/stampede_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% Copyright (c) Loïc Hoguin 2 | %% 3 | %% Permission to use, copy, modify, and/or distribute this software for any 4 | %% purpose with or without fee is hereby granted, provided that the above 5 | %% copyright notice and this permission notice appear in all copies. 6 | %% 7 | %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -module(stampede_SUITE). 16 | -compile(export_all). 17 | -compile(nowarn_export_all). 18 | 19 | -import(ct_helper, [doc/1]). 20 | -import(ct_helper, [name/0]). 21 | 22 | %% ct. 23 | 24 | all() -> 25 | [{group, tcp}, {group, tcp_socket}, {group, ssl}]. 26 | 27 | groups() -> 28 | [ 29 | { 30 | tcp, 31 | [], 32 | [ 33 | stampede_tcp, 34 | stampede_embedded 35 | ] 36 | }, 37 | { 38 | tcp_socket, 39 | [], 40 | [ 41 | stampede_tcp, 42 | stampede_embedded 43 | ] 44 | }, 45 | { 46 | ssl, 47 | [], 48 | [ 49 | stampede_ssl 50 | ] 51 | } 52 | ]. 53 | 54 | init_per_group(tcp_socket, Config) -> 55 | %% The socket backend for inet/gen_tcp was introduced as an experimental 56 | %% feature in OTP/23.0, and bugs https://bugs.erlang.org/browse/ERL-1284, 57 | %% 1287 and 1293 were solved in OTP/23.1. socket:use_registry/1 first 58 | %% appears in this release. 59 | %% Due to https://bugs.erlang.org/browse/ERL-1401, the socket backend 60 | %% is not working on Windows. 61 | case 62 | os:type() =/= {win32, nt} andalso 63 | code:ensure_loaded(socket) =:= {module, socket} andalso 64 | erlang:function_exported(socket, use_registry, 1) 65 | of 66 | true -> 67 | [{socket_opts, [{inet_backend, socket}]}|Config]; 68 | false -> 69 | {skip, "No socket backend support"} 70 | end; 71 | init_per_group(_, Config) -> 72 | Config. 73 | 74 | end_per_group(_, _) -> 75 | ok. 76 | 77 | init_per_suite(Config) -> 78 | {ok, _} = application:ensure_all_started(ranch), 79 | ok = application:start(stampede), 80 | %% Enable logging of progress reports. 81 | %% They will only be available in the HTML reports by default. 82 | ok = logger:set_primary_config(level, none), 83 | ok = logger:set_module_level(?MODULE, info), 84 | ok = logger:set_application_level(stampede, error), 85 | Config. 86 | 87 | end_per_suite(_) -> 88 | ok = application:stop(stampede), 89 | ok = application:stop(ranch). 90 | 91 | %% Tests. 92 | 93 | stampede_tcp(Config) -> 94 | doc("Start a TCP listener, establish a hundred connections, " 95 | "run stampede, confirm we can still connect."), 96 | %% Start a TCP listener. 97 | Name = name(), 98 | SockOpts = do_get_sockopts(Config), 99 | {ok, _} = ranch:start_listener(Name, 100 | ranch_tcp, #{socket_opts => SockOpts}, 101 | echo_protocol, []), 102 | %% Set restart frequency of ranch_sup. 103 | do_set_sup_frequencies([ranch_sup], 999999, 1), 104 | %% Run stampede. 105 | {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch}, 106 | #{interval => {100, 100}, before_kill => fun do_log/1}), 107 | %% Establish a hundred connections. 108 | ok = do_connect(100, ranch_tcp, ranch:get_port(Name), 1000), 109 | ok = stampede:activate(ranch_stampede), 110 | timer:sleep(10000), 111 | ok = stampede:stop_herd(ranch_stampede), 112 | timer:sleep(1000), 113 | %% Confirm we can still connect. 114 | ok = do_connect(1, ranch_tcp, ranch:get_port(Name), 1000), 115 | ok = ranch:stop_listener(Name). 116 | 117 | stampede_ssl(_) -> 118 | doc("Start a SSL listener, establish a hundred connections, " 119 | "run stampede, confirm we can still connect."), 120 | %% Start a TCP listener. 121 | Name = name(), 122 | {ok, _} = ranch:start_listener(Name, 123 | ranch_ssl, ct_helper:get_certs_from_ets(), 124 | echo_protocol, []), 125 | %% Set restart frequencies of ranch_sup and ssl_sup. 126 | do_set_sup_frequencies([ranch_sup, ssl_sup], 999999, 1), 127 | %% Run stampede. 128 | {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch}, 129 | #{interval => {100, 100}, before_kill => fun do_log/1}), 130 | {ok, _} = stampede:start_herd(ssl_stampede, {application, ssl}, 131 | #{interval => {100, 100}, before_kill => fun do_log/1}), 132 | %% Establish a hundred connections. 133 | ok = do_connect(100, ranch_ssl, ranch:get_port(Name), 1000), 134 | ok = stampede:activate(ranch_stampede), 135 | ok = stampede:activate(ssl_stampede), 136 | timer:sleep(10000), 137 | ok = stampede:stop_herd(ssl_stampede), 138 | ok = stampede:stop_herd(ranch_stampede), 139 | timer:sleep(1000), 140 | %% Confirm we can still connect. 141 | ok = do_connect(1, ranch_ssl, ranch:get_port(Name), 1000), 142 | ok = ranch:stop_listener(Name). 143 | 144 | stampede_embedded(Config) -> 145 | doc("Start an embedded TCP listener, establish a hundred connections, " 146 | "run stampede, confirm we can still connect."), 147 | %% Start embedded listener. 148 | Name = name(), 149 | SockOpts = do_get_sockopts(Config), 150 | {ok, SupPid} = embedded_sup:start_link(), 151 | {ok, _} = embedded_sup:start_listener(SupPid, Name, 152 | ranch_tcp, #{socket_opts => SockOpts}, echo_protocol, []), 153 | %% Set restart frequency of ranch_sup and embedded_sup. 154 | do_set_sup_frequencies([ranch_sup, SupPid], 999999, 1), 155 | %% Run stampede. 156 | {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch}, 157 | #{interval => {100, 100}, before_kill => fun do_log/1}), 158 | {ok, _} = stampede:start_herd(embedded_stampede, {supervisor, SupPid}, 159 | #{interval => {100, 100}, before_kill => fun do_log/1}), 160 | %% Establish a hundred connections. 161 | ok = do_connect(100, ranch_tcp, ranch:get_port(Name), 1000), 162 | ok = stampede:activate(ranch_stampede), 163 | ok = stampede:activate(embedded_stampede), 164 | timer:sleep(10000), 165 | ok = stampede:stop_herd(ranch_stampede), 166 | ok = stampede:stop_herd(embedded_stampede), 167 | timer:sleep(1000), 168 | %% Confirm we can still connect. 169 | ok = do_connect(1, ranch_tcp, ranch:get_port(Name), 1000), 170 | ok = embedded_sup:stop_listener(SupPid, Name), 171 | embedded_sup:stop(SupPid), 172 | ok. 173 | 174 | do_set_sup_frequencies(Sups, Intensity, Period) -> 175 | StateFun = fun (S) -> setelement(7, setelement(6, S, Intensity), Period) end, 176 | _ = [sys:replace_state(Sup, StateFun) || Sup <- Sups], 177 | ok. 178 | 179 | do_connect(0, _, _, _) -> 180 | ok; 181 | do_connect(N, Transport, Port, Timeout) -> 182 | {ok, _} = Transport:connect("localhost", Port, [{active, false}], Timeout), 183 | do_connect(N - 1, Transport, Port, Timeout). 184 | 185 | do_log(Pid) when is_pid(Pid) -> 186 | ct:log(info, "~p: ~p~n", [Pid, erlang:process_info(Pid)]), 187 | true; 188 | do_log(Port) when is_port(Port) -> 189 | ct:log(info, "~p: ~p~n", [Port, erlang:port_info(Port)]), 190 | true. 191 | 192 | do_get_sockopts(Config) -> 193 | proplists:get_value(socket_opts, Config, []). 194 | -------------------------------------------------------------------------------- /test/supervisor_separate.erl: -------------------------------------------------------------------------------- 1 | -module(supervisor_separate). 2 | -behavior(supervisor). 3 | -behavior(ranch_protocol). 4 | 5 | -export([start_link/3]). 6 | -export([init/1]). 7 | 8 | start_link(Ref, Transport, Opts) -> 9 | {ok, SupPid} = supervisor:start_link(?MODULE, []), 10 | {ok, ConnPid} = supervisor:start_child(SupPid, 11 | {echo_protocol, {echo_protocol, start_link, [Ref, Transport, Opts]}, 12 | temporary, 5000, worker, [echo_protocol]}), 13 | {ok, SupPid, ConnPid}. 14 | 15 | init([]) -> 16 | {ok, {{one_for_one, 1, 1}, []}}. 17 | -------------------------------------------------------------------------------- /test/transport_capabilities_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(transport_capabilities_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | {ok, Socket} = ranch:handshake(Ref), 13 | loop(Socket, Transport). 14 | 15 | loop(Socket, Transport) -> 16 | case Transport:recv(Socket, 0, 5000) of 17 | {ok, Data} -> 18 | Reply = 19 | case check(Socket, Transport, Data) of 20 | ok -> 21 | <<"OK">>; 22 | error -> 23 | <<"ERROR">> 24 | end, 25 | Transport:send(Socket, Reply), 26 | loop(Socket, Transport); 27 | _ -> 28 | ok = Transport:close(Socket) 29 | end. 30 | 31 | check(Socket, Transport, <<"getopts/2">>) -> 32 | case catch Transport:getopts(Socket, []) of 33 | {ok, _} -> 34 | ok; 35 | _ -> 36 | error 37 | end; 38 | 39 | check(Socket, Transport, <<"getstat/1">>) -> 40 | case catch Transport:getstat(Socket) of 41 | {ok, _} -> 42 | ok; 43 | _ -> 44 | error 45 | end; 46 | 47 | check(Socket, Transport, <<"getstat/2">>) -> 48 | case catch Transport:getstat(Socket, []) of 49 | {ok, _} -> 50 | ok; 51 | _ -> 52 | error 53 | end. 54 | -------------------------------------------------------------------------------- /test/trap_exit_protocol.erl: -------------------------------------------------------------------------------- 1 | -module(trap_exit_protocol). 2 | -behaviour(ranch_protocol). 3 | 4 | -export([start_link/3]). 5 | -export([init/3]). 6 | 7 | start_link(Ref, Transport, Opts) -> 8 | Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]), 9 | {ok, Pid}. 10 | 11 | init(Ref, Transport, _Opts = []) -> 12 | process_flag(trap_exit, true), 13 | {ok, Socket} = ranch:handshake(Ref), 14 | loop(Socket, Transport). 15 | 16 | loop(Socket, Transport) -> 17 | case Transport:recv(Socket, 0, infinity) of 18 | {ok, Data} -> 19 | Transport:send(Socket, Data), 20 | loop(Socket, Transport); 21 | _ -> 22 | ok = Transport:close(Socket) 23 | end. 24 | --------------------------------------------------------------------------------