Browse Source

Add support for listening on random port numbers (port 0)

ranch:get_port/1 returns the given listener's port.
Loïc Hoguin 13 years ago
parent
commit
45348170f4
5 changed files with 31 additions and 5 deletions
  1. 1 1
      src/ranch.app.src
  2. 8 0
      src/ranch.erl
  3. 2 0
      src/ranch_acceptors_sup.erl
  4. 17 0
      src/ranch_listener.erl
  5. 3 4
      test/acceptor_SUITE.erl

+ 1 - 1
src/ranch.app.src

@@ -14,7 +14,7 @@
 
 {application, ranch, [
 	{description, "Socket acceptor pool for TCP protocols."},
-	{vsn, "0.2.1"},
+	{vsn, git},
 	{modules, []},
 	{registered, [ranch_sup]},
 	{applications, [

+ 8 - 0
src/ranch.erl

@@ -19,6 +19,7 @@
 -export([stop_listener/1]).
 -export([child_spec/6]).
 -export([accept_ack/1]).
+-export([get_port/1]).
 -export([get_protocol_options/1]).
 -export([set_protocol_options/2]).
 
@@ -88,6 +89,13 @@ child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
 accept_ack(ListenerPid) ->
 	receive {shoot, ListenerPid} -> ok end.
 
+%% @doc Return the listener's port.
+-spec get_port(any()) -> inet:port_number().
+get_port(Ref) ->
+	ListenerPid = ref_to_listener_pid(Ref),
+	{ok, Port} = ranch_listener:get_port(ListenerPid),
+	Port.
+
 %% @doc Return the current protocol options for the given listener.
 -spec get_protocol_options(any()) -> any().
 get_protocol_options(Ref) ->

+ 2 - 0
src/ranch_acceptors_sup.erl

@@ -36,6 +36,8 @@ start_link(NbAcceptors, Transport, TransOpts,
 init([NbAcceptors, Transport, TransOpts,
 		Protocol, ProtoOpts, ListenerPid, ConnsPid]) ->
 	{ok, LSocket} = Transport:listen(TransOpts),
+	{ok, {_, Port}} = Transport:sockname(LSocket),
+	ranch_listener:set_port(ListenerPid, Port),
 	Procs = [{{acceptor, self(), N}, {ranch_acceptor, start_link, [
 				LSocket, Transport, Protocol, ProtoOpts,
 				ListenerPid, ConnsPid

+ 17 - 0
src/ranch_listener.erl

@@ -23,6 +23,8 @@
 -export([move_connection/3]).
 -export([remove_connection/2]).
 -export([check_upgrades/2]).
+-export([get_port/1]).
+-export([set_port/2]).
 -export([get_protocol_options/1]).
 -export([set_protocol_options/2]).
 
@@ -41,6 +43,7 @@
 	conns_table :: ets:tid(),
 	queue = undefined :: queue(),
 	max_conns = undefined :: non_neg_integer(),
+	port = undefined :: undefined | inet:port_number(),
 	proto_opts :: any(),
 	proto_opts_vsn = 1 :: non_neg_integer()
 }).
@@ -102,6 +105,16 @@ remove_connection(ServerPid, ConnPid) ->
 check_upgrades(ServerPid, OptsVsn) ->
 	gen_server:call(ServerPid, {check_upgrades, OptsVsn}).
 
+%% @doc Return the listener's port.
+-spec get_port(pid()) -> {ok, inet:port_number()}.
+get_port(ServerPid) ->
+	gen_server:call(ServerPid, get_port).
+
+%% @private
+-spec set_port(pid(), inet:port_number()) -> ok.
+set_port(ServerPid, Port) ->
+	gen_server:cast(ServerPid, {set_port, Port}).
+
 %% @doc Return the current protocol options.
 -spec get_protocol_options(pid()) -> {ok, any()}.
 get_protocol_options(ServerPid) ->
@@ -143,6 +156,8 @@ handle_call({check_upgrades, AccOptsVsn}, _From, State=#state{
 		true ->
 			{reply, ok, State}
 	end;
+handle_call(get_port, _From, State=#state{port=Port}) ->
+	{reply, {ok, Port}, State};
 handle_call(get_protocol_options, _From, State=#state{proto_opts=ProtoOpts}) ->
 	{reply, {ok, ProtoOpts}, State};
 handle_call({set_protocol_options, ProtoOpts}, _From,
@@ -154,6 +169,8 @@ handle_call(_, _From, State) ->
 	{reply, ignored, State}.
 
 %% @private
+handle_cast({set_port, Port}, State) ->
+	{noreply, State#state{port=Port}};
 handle_cast({move_connection, DestPool, ConnPid}, State=#state{
 		conn_pools=Pools, conns_table=ConnsTable}) ->
 	Pools2 = move_pid(ConnPid, DestPool, Pools, ConnsTable),

+ 3 - 4
test/acceptor_SUITE.erl

@@ -39,11 +39,10 @@ end_per_suite(_) ->
 %% tcp.
 
 tcp_echo(_) ->
-	%% @todo Don't use a fixed port. start_listener should return the port used?
 	{ok, _} = ranch:start_listener(tcp_echo, 1,
-		ranch_tcp, [{port, 33333}],
-		echo_protocol, []),
-	{ok, Socket} = gen_tcp:connect("localhost", 33333,
+		ranch_tcp, [{port, 0}], echo_protocol, []),
+	Port = ranch:get_port(tcp_echo),
+	{ok, Socket} = gen_tcp:connect("localhost", Port,
 		[binary, {active, false}, {packet, raw}]),
 	ok = gen_tcp:send(Socket, <<"Ranch is working!">>),
 	{ok, <<"Ranch is working!">>} = gen_tcp:recv(Socket, 0, 1000),