From a700368b2cb021bb1cd007697db4a3bae0099f2d Mon Sep 17 00:00:00 2001
From: James Fish <james@fishcakez.com>
Date: Mon, 1 Apr 2013 23:15:45 +0100
Subject: Fix ranch_server:set_connections_sup/2 race conditions

A ranch_conns_sup could be (re)started and call
ranch_server:set_connections_sup/2 before ranch_server has handled the
predecessor's exit. This would cause the ranch_server to crash because
ets:insert_new/2 would return false.

This change allows ranch_server to handle this case by crashing the
calling process instead of itself.
---
 src/ranch_server.erl | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/ranch_server.erl b/src/ranch_server.erl
index 7557d53..200e29c 100644
--- a/src/ranch_server.erl
+++ b/src/ranch_server.erl
@@ -68,7 +68,8 @@ cleanup_listener_opts(Ref) ->
 %% @doc Set a connection supervisor associated with specific listener.
 -spec set_connections_sup(any(), pid()) -> ok.
 set_connections_sup(Ref, Pid) ->
-	gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}).
+	true = gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}),
+	ok.
 
 %% @doc Return the connection supervisor used by specific listener.
 -spec get_connections_sup(any()) -> pid().
@@ -125,10 +126,14 @@ handle_call({set_new_listener_opts, Ref, MaxConns, Opts}, _, State) ->
 	{reply, ok, State};
 handle_call({set_connections_sup, Ref, Pid}, _,
 		State=#state{monitors=Monitors}) ->
-	true = ets:insert_new(?TAB, {{conns_sup, Ref}, Pid}),
-	MonitorRef = erlang:monitor(process, Pid),
-	{reply, ok, State#state{
-		monitors=[{{MonitorRef, Pid}, Ref}|Monitors]}};
+	case ets:insert_new(?TAB, {{conns_sup, Ref}, Pid}) of
+		true ->
+			MonitorRef = erlang:monitor(process, Pid),
+			{reply, true,
+				State#state{monitors=[{{MonitorRef, Pid}, Ref}|Monitors]}};
+		false ->
+			{reply, false, State}
+	end;
 handle_call({set_port, Ref, Port}, _, State) ->
 	true = ets:insert(?TAB, {{port, Ref}, Port}),
 	{reply, ok, State};
-- 
cgit v1.2.3