summaryrefslogtreecommitdiff
path: root/src/rabbit_net.erl
diff options
context:
space:
mode:
authorMatthias Radestock <matthias@rabbitmq.com>2012-09-03 16:31:35 +0100
committerMatthias Radestock <matthias@rabbitmq.com>2012-09-03 16:31:35 +0100
commitfef645432aa37b98ab39d9c4203a067f86ca0932 (patch)
tree54acc9dd120134a3a445f57dc80fa5472344a57e /src/rabbit_net.erl
parentd87576a6349a78a7d1ce2c88c737000f87df69ae (diff)
downloadrabbitmq-server-fef645432aa37b98ab39d9c4203a067f86ca0932.tar.gz
attempt to close ssl connections gracefully but forcefully
gracefully...so that there is a good chance of TLS alerts making it through, but forecfully (after a timeout) so we don't get stuck (or worse, silently) holding on to file descriptors and processes.
Diffstat (limited to 'src/rabbit_net.erl')
-rw-r--r--src/rabbit_net.erl24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/rabbit_net.erl b/src/rabbit_net.erl
index 698a7c9a..eacff141 100644
--- a/src/rabbit_net.erl
+++ b/src/rabbit_net.erl
@@ -77,6 +77,8 @@
%%---------------------------------------------------------------------------
+-define(SSL_CLOSE_TIMEOUT, 5000).
+
-define(IS_SSL(Sock), is_record(Sock, ssl_socket)).
is_ssl(Sock) -> ?IS_SSL(Sock).
@@ -148,8 +150,26 @@ send(Sock, Data) when is_port(Sock) -> gen_tcp:send(Sock, Data).
close(Sock) when ?IS_SSL(Sock) -> ssl:close(Sock#ssl_socket.ssl);
close(Sock) when is_port(Sock) -> gen_tcp:close(Sock).
-fast_close(Sock) when ?IS_SSL(Sock) -> ok;
-fast_close(Sock) when is_port(Sock) -> erlang:port_close(Sock), ok.
+fast_close(Sock) when ?IS_SSL(Sock) ->
+ %% We cannot simply port_close the underlying tcp socket since the
+ %% TLS protocol is quite insistent that a proper closing handshake
+ %% should take place (see RFC 5245 s7.2.1). So we call ssl:close
+ %% instead, but that can block for a very long time if the socket
+ %% is in a funny state. Since there is no timeout variant of
+ %% ssl:close, we construct our own.
+ {Pid, MRef} = spawn_monitor(fun () -> ssl:close(Sock#ssl_socket.ssl) end),
+ erlang:send_after(?SSL_CLOSE_TIMEOUT, self(), {Pid, ssl_close_timeout}),
+ receive
+ {Pid, ssl_close_timeout} ->
+ erlang:demonitor(MRef, [flush]),
+ exit(Pid, kill);
+ {'DOWN', MRef, process, Pid, _Reason} ->
+ ok
+ end,
+ catch port_close(Sock#ssl_socket.tcp),
+ ok;
+fast_close(Sock) when is_port(Sock) ->
+ catch port_close(Sock), ok.
sockname(Sock) when ?IS_SSL(Sock) -> ssl:sockname(Sock#ssl_socket.ssl);
sockname(Sock) when is_port(Sock) -> inet:sockname(Sock).