Move monitor of owner into the connection process. Add test case.

This commit is contained in:
Ulf Wiger 2018-08-17 12:53:00 +02:00
parent c3bdb02e53
commit cff15e0bfb
2 changed files with 79 additions and 8 deletions

View File

@ -33,8 +33,7 @@ start_link(TcpSock, Rx, Tx, Owner, {Active0, Buf}) ->
true -> true;
once -> {once, false}
end,
OwnerRef = erlang:monitor(process, Owner),
State = #state{ rx = Rx, tx = Tx, owner = Owner, owner_ref = OwnerRef,
State = #state{ rx = Rx, tx = Tx, owner = Owner,
tcp_sock = TcpSock, active = Active },
case gen_server:start_link(?MODULE, [State], []) of
@ -67,8 +66,9 @@ controlling_process(Noise, NewPid) ->
gen_server:call(Noise, {controlling_process, self(), NewPid}, 100).
%% -- gen_server callbacks ---------------------------------------------------
init([State]) ->
{ok, State}.
init([#state{owner = Owner} = State]) ->
OwnerRef = erlang:monitor(process, Owner),
{ok, State#state{owner_ref = OwnerRef}}.
handle_call(close, _From, S) ->
{stop, normal, ok, S};
@ -103,7 +103,7 @@ handle_info({tcp_closed, TS}, S = #state{ tcp_sock = TS, owner = O }) ->
{noreply, S#state{ tcp_sock = closed }};
handle_info({'DOWN', OwnerRef, process, _, normal},
S = #state { tcp_sock = TS, owner_ref = OwnerRef }) ->
gen_tcp:close(TS),
close_tcp(TS),
{stop, normal, S#state{ tcp_sock = closed, owner_ref = undefined }};
handle_info({'DOWN', _, _, _, _}, S) ->
%% Ignore non-normal monitor messages - we are linked.
@ -190,3 +190,8 @@ flush_tcp(Pid, TcpSock) ->
flush_tcp(Pid, TcpSock)
after 1 -> ok
end.
close_tcp(closed) ->
ok;
close_tcp(Sock) ->
gen_tcp:close(Sock).

View File

@ -81,6 +81,15 @@ noise_dh25519_test_() ->
end
}.
noise_monitor_test_() ->
{setup,
fun() -> setup_dh25519() end,
fun(_X) -> ok end,
fun({[T|Tests] = _Tests, SKP, CKP}) ->
[ {T, fun() -> noise_monitor_test(T, SKP, CKP) end} ]
end
}.
setup_dh25519() ->
%% Generate a static key-pair for Client and Server
SrvKeyPair = enoise_keypair:new(dh25519),
@ -93,6 +102,52 @@ setup_dh25519() ->
{Configurations, SrvKeyPair, CliKeyPair}.
noise_test(Conf, SKP, CKP) ->
#{econn := EConn, echo_srv := EchoSrv} = noise_test_run(Conf, SKP, CKP),
enoise:close(EConn),
echo_srv_stop(EchoSrv),
ok.
noise_test_run(Conf, SKP, CKP) ->
{Pid, MRef} = spawn_monitor_proxy(
fun() -> noise_test_run_(Conf, SKP, CKP) end),
receive
{Pid, #{} = Info} ->
Info#{proxy => Pid, proxy_mref => MRef}
after 5000 ->
erlang:error(timeout)
end.
spawn_monitor_proxy(F) ->
Me = self(),
spawn_monitor(fun() ->
MRef = erlang:monitor(process, Me),
Res = F(),
Me ! {self(), Res},
proxy_loop(Me, MRef)
end).
proxy_loop(Parent, MRef) ->
receive
{Parent, Ref, F} when is_function(F, 0) ->
Parent ! {Ref, F()},
proxy_loop(Parent, MRef);
{'DOWN', MRef, process, Parent, _} ->
done
end.
proxy_exec(P, F) when is_function(F, 0) ->
R = erlang:monitor(process, P),
P ! {self(), R, F},
receive
{R, Res} ->
Res;
{'DOWN', R, _, _, Reason} ->
erlang:error(Reason)
after 5000 ->
erlang:error(timeout)
end.
noise_test_run_(Conf, SKP, CKP) ->
Protocol = enoise_protocol:from_name(Conf),
Port = 4556,
@ -114,10 +169,21 @@ noise_test(Conf, SKP, CKP) ->
receive
{noise, _, <<"Goodbye!">>} -> ok
after 100 -> error(timeout) end,
#{ econn => EConn
, tcp_sock => TcpSock
, echo_srv => EchoSrv }.
enoise:close(EConn),
echo_srv_stop(EchoSrv),
ok.
noise_monitor_test(Conf, SKP, CKP) ->
#{ econn := {enoise, EConnPid}
, proxy := Proxy
, tcp_sock := TcpSock } = noise_test_run(Conf, SKP, CKP),
try proxy_exec(Proxy, fun() -> exit(normal) end)
catch
error:normal ->
receive after 100 ->
false = is_process_alive(EConnPid)
end
end.
echo_srv_start(Port, Protocol, SKP, CPub) ->
Pid = spawn(fun() -> echo_srv(Port, Protocol, SKP, CPub) end),