From fb4bd38ffd2c330cbd677d958477aa909210a0b3 Mon Sep 17 00:00:00 2001 From: Juan Facorro Date: Sun, 21 Jun 2015 20:09:10 -0300 Subject: Monitor owner and terminate when it dies --- src/gun.erl | 11 +++++++++-- test/gun_SUITE.erl | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/gun.erl b/src/gun.erl index 4304299..16397c9 100644 --- a/src/gun.erl +++ b/src/gun.erl @@ -99,6 +99,7 @@ -record(state, { parent :: pid(), owner :: pid(), + owner_ref :: reference(), host :: inet:hostname(), port :: inet:port_number(), opts :: opts(), @@ -487,7 +488,9 @@ init(Parent, Owner, Host, Port, Opts) -> tcp -> ranch_tcp; ssl -> ranch_ssl end, - connect(#state{parent=Parent, owner=Owner, host=Host, port=Port, opts=Opts, transport=Transport}, Retry). + OwnerRef = monitor(process, Owner), + connect(#state{parent=Parent, owner=Owner, owner_ref=OwnerRef, + host=Host, port=Port, opts=Opts, transport=Transport}, Retry). default_transport(443) -> ssl; default_transport(_) -> tcp. @@ -576,7 +579,7 @@ before_loop(State=#state{opts=Opts, protocol=Protocol}) -> KeepaliveRef = erlang:send_after(Keepalive, self(), keepalive), loop(State#state{keepalive_ref=KeepaliveRef}). -loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port, opts=Opts, +loop(State=#state{parent=Parent, owner=Owner, owner_ref=OwnerRef, host=Host, port=Port, opts=Opts, socket=Socket, transport=Transport, protocol=Protocol, protocol_state=ProtoState}) -> {OK, Closed, Error} = Transport:messages(), Transport:setopts(Socket, [{active, once}]), @@ -636,6 +639,10 @@ loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port, opts=Opts, {shutdown, Owner} -> %% @todo Protocol:shutdown? ok; + {'DOWN', OwnerRef, process, Owner, Reason} -> + Protocol:close(ProtoState), + Transport:close(Socket), + error({owner_gone, Reason}); {system, From, Request} -> sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {loop, State}); diff --git a/test/gun_SUITE.erl b/test/gun_SUITE.erl index c62c600..64b8885 100644 --- a/test/gun_SUITE.erl +++ b/test/gun_SUITE.erl @@ -42,6 +42,28 @@ connect_timeout_infinity(_) -> error(timeout) end. +detect_owner_gone(_) -> + Self = self(), + spawn(fun() -> + {ok, ConnPid} = gun:open("google.com", 80), + Self ! {conn, ConnPid}, + gun:await_up(ConnPid) + end), + Pid = receive + {conn, C} -> + C + after 1000 -> + error(timeout) + end, + Ref = monitor(process, Pid), + receive + {'DOWN', Ref, process, Pid, {owner_gone, _}} -> + ok + after 1000 -> + true = erlang:is_process_alive(Pid), + error(timeout) + end. + gone_reason(_) -> doc("The last connection failure must be propagated."), {ok, Pid} = gun:open("localhost", 12345, #{retry => 0}), -- cgit v1.2.3