diff --git a/src/enoise_connection.erl b/src/enoise_connection.erl index f1a10f2..ad36c7e 100644 --- a/src/enoise_connection.erl +++ b/src/enoise_connection.erl @@ -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). diff --git a/test/enoise_tests.erl b/test/enoise_tests.erl index 4cfb6d9..d68b65a 100644 --- a/test/enoise_tests.erl +++ b/test/enoise_tests.erl @@ -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),