From 8f3aff4d8bdb662a1d2588784c93057700d28386 Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Tue, 13 Mar 2018 23:22:42 +0100 Subject: [PATCH] Support {active, true} and {active, once} in gen_tcp-wrapper In the implemented TCP-wrapper (enoise_connection) we now properly support {active, true} and {active, once} and switching between them (previously no switching was supported). --- README.md | 5 ++ src/enoise.erl | 112 ++++++++++++++----------- src/enoise_connection.erl | 169 ++++++++++++-------------------------- src/enoise_hs_state.erl | 3 +- test/enoise_tests.erl | 49 ++++++----- 5 files changed, 152 insertions(+), 186 deletions(-) diff --git a/README.md b/README.md index 4331879..e74fb5c 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,8 @@ Build ----- $ rebar3 compile + +Test +---- + + $ rebar3 eunit diff --git a/src/enoise.erl b/src/enoise.erl index 2c494ed..a720a11 100644 --- a/src/enoise.erl +++ b/src/enoise.erl @@ -22,9 +22,8 @@ , close/1 , connect/2 , controlling_process/2 - , recv/2 - , recv/3 - , send/2 ]). + , send/2 + , set_active/2 ]). -record(enoise, { pid }). @@ -43,13 +42,31 @@ | {s, noise_keypair()} | {re, noise_key()} | {rs, noise_key()} - | {prologue, binary()}. %% Optional + | {prologue, binary()} %% Optional + | {timeout, integer() | infinity}. %% Optional -type noise_protocol_option() :: enoise_protocol:protocol() | string() | binary(). %% Either an instantiated Noise protocol configuration or the name of a Noise %% configuration (either as a string or a binary string). +-type com_state_state() :: term(). +%% The state part of a communiction state + +-type recv_msg_fun() :: fun((com_state_state(), integer() | infinity) -> + {ok, binary(), com_state_state()} | {error, term()}). +%% Function that receive a message + +-type send_msg_fun() :: fun((com_state_state(), binary()) -> ok). +%% Function that sends a message + +-type noise_com_state() :: #{ recv_msg := recv_msg_fun(), + send_msg := send_msg_fun(), + state := term() }. +%% Noise communication state - used to parameterize a handshake. Consists of a +%% send function one receive function and an internal state. + + -opaque noise_socket() :: #enoise{}. %% An abstract Noise socket - holds a reference to a socket that has completed %% a Noise handshake. @@ -61,6 +78,13 @@ binary(). %%==================================================================== %% @doc Start an interactive handshake +%% @end +-spec handshake(Options :: noise_options(), + Role :: enoise_hs_state:noise_role()) -> + {in, enoise_hs_state:state()} + | {out, binary(), enoise_hs_state:state()} + | {done, enoise_hs_state:state()} + | {error, term()}. handshake(Options, Role) -> HState = create_hstate(Options, Role), step_handshake(HState, <<>>). @@ -68,15 +92,24 @@ handshake(Options, Role) -> step_handshake(HState, Data) -> do_step_handshake(HState, Data). -%% @doc The main function - performs a Noise handshake +%% @doc Perform a Noise handshake +%% @end +-spec handshake(Options :: noise_options(), + Role :: enoise_hs_state:noise_role(), + ComState :: noise_com_state()) -> + {ok, map(), noise_com_state()} | {error, term()}. handshake(Options, Role, ComState) -> HState = create_hstate(Options, Role), - do_handshake(HState, ComState). + Timeout = proplists:get_value(timeout, Options, infinity), + do_handshake(HState, ComState, Timeout). %% @doc Upgrades a gen_tcp, or equivalent, connected socket to a Noise socket, %% that is, performs the client-side noise handshake. %% +%% Note: The TCP socket has to be in mode `{active, true}' or `{active, once}', +%% passive receive is not supported. +%% %% {@link noise_options()} is a proplist. %% @end -spec connect(TcpSock :: gen_tcp:socket(), @@ -88,6 +121,9 @@ connect(TcpSock, Options) -> %% @doc Upgrades a gen_tcp, or equivalent, connected socket to a Noise socket, %% that is, performs the server-side noise handshake. %% +%% Note: The TCP socket has to be in mode `{active, true}' or `{active, once}', +%% passive receive is not supported. +%% %% {@link noise_options()} is a proplist. %% @end -spec accept(TcpSock :: gen_tcp:socket(), @@ -102,29 +138,6 @@ accept(TcpSock, Options) -> send(#enoise{ pid = Pid }, Data) -> enoise_connection:send(Pid, Data). -%% @equiv recv(Socket, Length, infinity) --spec recv(Socket :: noise_socket(), Length :: integer()) -> - {ok, binary()} | {error, term()}. -recv(Socket, Length) -> - recv(Socket, Length, infinity). - -%% @doc Receives a packet from a socket in passive mode. A closed socket is -%% indicated by return value `{error, closed}'. -%% -%% Argument `Length' denotes the number of bytes to read. If Length = 0, all -%% available bytes are returned. If Length > 0, exactly Length bytes are -%% returned, or an error; possibly discarding less than Length bytes of data -%% when the socket gets closed from the other side. -%% -%% Optional argument `Timeout' specifies a time-out in milliseconds. The -%% default value is `infinity'. -%% @end --spec recv(Socket :: noise_socket(), Length :: integer(), - Timeout :: integer() | infinity) -> - {ok, binary()} | {error, term()}. -recv(#enoise{ pid = Pid }, Length, Timeout) -> - enoise_connection:recv(Pid, Length, Timeout). - %% @doc Closes a Noise connection. %% @end -spec close(NoiseSock :: noise_socket()) -> ok | {error, term()}. @@ -140,30 +153,38 @@ close(#enoise{ pid = Pid }) -> controlling_process(#enoise{ pid = Pid }, NewPid) -> enoise_connection:controlling_process(Pid, NewPid). +%% @doc Set the active option `true | once'. Note that `N' and `false' are +%% not valid options for a Noise socket. +%% @end +-spec set_active(Socket :: noise_socket(), Mode :: true | once) -> + ok | {error, term()}. +set_active(#enoise{ pid = Pid }, ActiveMode) -> + enoise_connection:set_active(Pid, ActiveMode). + %%==================================================================== %% Internal functions %%==================================================================== -do_handshake(HState, ComState) -> +do_handshake(HState, ComState, Timeout) -> case enoise_hs_state:next_message(HState) of in -> - case hs_recv_msg(ComState) of + case hs_recv_msg(ComState, Timeout) of {ok, Data, ComState1} -> {ok, HState1, _Msg} = enoise_hs_state:read_message(HState, Data), - do_handshake(HState1, ComState1); + do_handshake(HState1, ComState1, Timeout); Err = {error, _} -> Err end; out -> {ok, HState1, Msg} = enoise_hs_state:write_message(HState, <<>>), {ok, ComState1} = hs_send_msg(ComState, Msg), - do_handshake(HState1, ComState1); + do_handshake(HState1, ComState1, Timeout); done -> {ok, Res} = enoise_hs_state:finalize(HState), {ok, Res, ComState} end. -hs_recv_msg(CS = #{ recv_msg := Recv, state := S }) -> - case Recv(S) of +hs_recv_msg(CS = #{ recv_msg := Recv, state := S }, Timeout) -> + case Recv(S, Timeout) of {ok, Data, S1} -> {ok, Data, CS#{ state := S1 }}; Err = {error, _} -> Err end. @@ -193,7 +214,7 @@ tcp_handshake(TcpSock, Role, Options) -> case check_gen_tcp(TcpSock) of ok -> {ok, [{active, Active}]} = inet:getopts(TcpSock, [active]), - ComState = #{ recv_msg => fun gen_tcp_rcv_msg/1, + ComState = #{ recv_msg => fun gen_tcp_rcv_msg/2, send_msg => fun gen_tcp_snd_msg/2, state => {TcpSock, Active, <<>>} }, @@ -228,12 +249,13 @@ create_hstate(Options, Role) -> Prologue, {S, E, RS, RE}). check_gen_tcp(TcpSock) -> - {ok, TcpOpts} = inet:getopts(TcpSock, [mode, packet, header, packet_size]), + {ok, TcpOpts} = inet:getopts(TcpSock, [mode, packet, active, header, packet_size]), Packet = proplists:get_value(packet, TcpOpts, 0), + Active = proplists:get_value(active, TcpOpts, 0), Header = proplists:get_value(header, TcpOpts, 0), PSize = proplists:get_value(packet_size, TcpOpts, undefined), Mode = proplists:get_value(mode, TcpOpts, binary), - case (Packet == 0 orelse Packet == raw) + case (Packet == 0 orelse Packet == raw) andalso (Active == true orelse Active == once) andalso Header == 0 andalso PSize == 0 andalso Mode == binary of true -> gen_tcp:controlling_process(TcpSock, self()); @@ -246,22 +268,18 @@ gen_tcp_snd_msg(S = {TcpSock, _, _}, Msg) -> ok = gen_tcp:send(TcpSock, <>), {ok, S}. -gen_tcp_rcv_msg({TcpSock, true, Buf}) -> +gen_tcp_rcv_msg({TcpSock, Active, Buf}, Timeout) -> receive {tcp, TcpSock, Data} -> + %% Immediately re-set {active, once} + [ inet:setopts(TcpSock, [{active, once}]) || Active == once ], case <> of Buf1 = <> when byte_size(Rest) < Len -> - gen_tcp_rcv_msg({TcpSock, true, Buf1}); + gen_tcp_rcv_msg({TcpSock, true, Buf1}, Timeout); <> -> <> = Rest, {ok, Data1, {TcpSock, true, Buf1}} end - after 1000 -> + after Timeout -> {error, timeout} - end; -gen_tcp_rcv_msg(S = {TcpSock, false, <<>>}) -> - {ok, <>} = gen_tcp:recv(TcpSock, 2, 1000), - case gen_tcp:recv(TcpSock, Len, 1000) of - {ok, Data} -> {ok, Data, S}; - Err = {error, _} -> Err end. diff --git a/src/enoise_connection.erl b/src/enoise_connection.erl index b61390b..a540a9f 100644 --- a/src/enoise_connection.erl +++ b/src/enoise_connection.erl @@ -14,8 +14,8 @@ -export([ controlling_process/2 , close/1 - , recv/3 , send/2 + , set_active/2 , start_link/5 ]). @@ -25,23 +25,23 @@ -record(enoise, { pid }). --record(state, {rx, tx, owner, tcp_sock, active, buf = <<>>, rawbuf = <<>>}). +-record(state, {rx, tx, owner, tcp_sock, active, msgbuf = [], rawbuf = <<>>}). %% -- API -------------------------------------------------------------------- -start_link(TcpSock, Rx, Tx, Owner, {Active, Buf}) -> - State0 = #state{ rx = Rx, tx = Tx, owner = Owner, - tcp_sock = TcpSock, active = Active }, - State = case Active of - true -> State0; - false -> State0#state{ rawbuf = Buf } - end, +start_link(TcpSock, Rx, Tx, Owner, {Active0, Buf}) -> + Active = case Active0 of + true -> true; + once -> {once, false} + end, + State = #state{ rx = Rx, tx = Tx, owner = Owner, + tcp_sock = TcpSock, active = Active }, case gen_server:start_link(?MODULE, [State], []) of {ok, Pid} -> ok = gen_tcp:controlling_process(TcpSock, Pid), - %% Changing controlling process if active requires a bit - %% of fiddling with already received content... - [ Pid ! {tcp, TcpSock, Buf} || Buf /= <<>>, Active ], - flush_tcp(Active, Pid, TcpSock), + %% Changing controlling process require a bit of + %% fiddling with already received and delivered content... + [ Pid ! {tcp, TcpSock, Buf} || Buf /= <<>> ], + flush_tcp(Pid, TcpSock), {ok, Pid}; Err = {error, _} -> Err @@ -50,10 +50,8 @@ start_link(TcpSock, Rx, Tx, Owner, {Active, Buf}) -> send(Noise, Data) -> gen_server:call(Noise, {send, Data}). -recv(Noise, Length, infinity) -> - gen_server:call(Noise, {recv, Length, infinity}, infinity); -recv(Noise, Length, Timeout) -> - gen_server:call(Noise, {recv, Length, Timeout}, Timeout + 100). +set_active(Noise, Active) -> + gen_server:call(Noise, {active, self(), Active}). close(Noise) -> gen_server:call(Noise, close). @@ -72,13 +70,11 @@ handle_call(_Call, _From, S = #state{ tcp_sock = closed }) -> handle_call({send, Data}, _From, S) -> {Res, S1} = handle_send(S, Data), {reply, Res, S1}; -handle_call({recv, _Length, _Timeout}, _From, S = #state{ active = true }) -> - {reply, {error, active_socket}, S}; -handle_call({recv, Length, Timeout}, _From, S) -> - {Res, S1} = handle_recv(S, Length, Timeout), - {reply, Res, S1}; handle_call({controlling_process, OldPid, NewPid}, _From, S) -> {Res, S1} = handle_control_change(S, OldPid, NewPid), + {reply, Res, S1}; +handle_call({active, Pid, NewActive}, _From, S) -> + {Res, S1} = handle_active(S, Pid, NewActive), {reply, Res, S1}. handle_cast(_Msg, S) -> @@ -86,10 +82,11 @@ handle_cast(_Msg, S) -> handle_info({tcp, TS, Data}, S = #state{ tcp_sock = TS }) -> {S1, Msgs} = handle_data(S, Data), - S2 = handle_msgs(S1, Msgs), + S2 = handle_msgs(S1#state{ msgbuf = S1#state.msgbuf ++ Msgs }), + set_active(S2), {noreply, S2}; -handle_info({tcp_closed, TS}, S = #state{ tcp_sock = TS, active = A, owner = O }) -> - [ O ! {tcp_closed, TS} || A ], +handle_info({tcp_closed, TS}, S = #state{ tcp_sock = TS, owner = O }) -> + O ! {tcp_closed, TS}, {noreply, S#state{ tcp_sock = closed }}; handle_info(Msg, S) -> io:format("Unexpected info: ~p\n", [Msg]), @@ -112,10 +109,23 @@ handle_control_change(S = #state{ owner = Pid, tcp_sock = TcpSock }, Pid, NewPid handle_control_change(S, _OldPid, _NewPid) -> {{error, not_owner}, S}. +handle_active(S = #state{ owner = Pid, tcp_sock = TcpSock }, Pid, Active) -> + case Active of + true -> + gen_tcp:setopts(TcpSock, [{active, true}]), + {ok, handle_msgs(S#state{ active = true })}; + once -> + S1 = handle_msgs(S#state{ active = {once, false} }), + set_active(S1), + {ok, S1} + end; +handle_active(S, _Pid, _NewActive) -> + {{error, not_owner}, S}. + handle_data(S = #state{ rawbuf = Buf, rx = Rx }, Data) -> case <> of B = <> when Len > byte_size(Rest) -> - {S#state{ rawbuf = B }, []}; %% Not a full message - save it + {S#state{ rawbuf = B }, []}; %% Not a full Noise message - save it <> -> <> = Rest, case enoise_cipher_state:decrypt_with_ad(Rx, <<>>, Msg) of @@ -129,106 +139,33 @@ handle_data(S = #state{ rawbuf = Buf, rx = Rx }, Data) -> {S#state{ rawbuf = EmptyOrSingleByte }, []} end. -handle_msgs(S, []) -> +handle_msgs(S = #state{ msgbuf = [] }) -> S; -handle_msgs(S = #state{ active = true, owner = Owner, buf = <<>> }, Msgs) -> +handle_msgs(S = #state{ msgbuf = Msgs, active = true, owner = Owner }) -> [ Owner ! {noise, #enoise{ pid = self() }, Msg} || Msg <- Msgs ], - S; -handle_msgs(S = #state{ active = true, owner = Owner, buf = Buf }, Msgs) -> - %% First send stuff in buffer (only when switching to active true) - Owner ! {noise, #enoise{ pid = self() }, Buf}, - handle_msgs(S#state{ buf = <<>> }, Msgs); -handle_msgs(S = #state{ buf = Buf }, Msgs) -> - NewBuf = lists:foldl(fun(Msg, B) -> <> end, Buf, Msgs), - S#state{ buf = NewBuf }. + S#state{ msgbuf = [] }; +handle_msgs(S = #state{ msgbuf = [Msg | Msgs], active = {once, Delivered}, owner = Owner }) -> + case Delivered of + true -> + S; + false -> + Owner ! {noise, #enoise{ pid = self() }, Msg}, + S#state{ msgbuf = Msgs, active = {once, true} } + end. handle_send(S = #state{ tcp_sock = TcpSock, tx = Tx }, Data) -> {ok, Tx1, Msg} = enoise_cipher_state:encrypt_with_ad(Tx, <<>>, Data), gen_tcp:send(TcpSock, <<(byte_size(Msg)):16, Msg/binary>>), {ok, S#state{ tx = Tx1 }}. -%% Some special cases -%% - Length = 0 (get all available data) -%% This may leave raw (encrypted) data in rawbuf (but: buf = <<>>) -%% - Length N when there is stuff in rawbuf -handle_recv(S = #state{ buf = Buf, tcp_sock = TcpSock }, 0, TO) -> - %% Get all available data - {ok, Data} = gen_tcp:recv(TcpSock, 0, TO), - %% Use handle_data to process it - {S1, Msgs} = handle_data(S, Data), - Res = lists:foldl(fun(Msg, B) -> <> end, Buf, Msgs), - {{ok, Res}, S1#state{ buf = <<>> }}; -handle_recv(S = #state{ buf = Buf, rx = Rx }, Len, TO) - when byte_size(Buf) < Len -> - case recv_noise_msg(S, TO) of - {ok, S1, Data} -> - case enoise_cipher_state:decrypt_with_ad(Rx, <<>>, Data) of - {ok, Rx1, Msg1} -> - NewBuf = <>, - handle_recv(S1#state{ buf = NewBuf, rx = Rx1 }, Len, TO); - {error, _} -> - %% Return error and drop the data we could not decrypt - %% Unlikely that we can recover from this, but leave the - %% closing to the user... - {{error, decrypt_input_failed}, S1} - end; - {error, S1, Reason} -> - {{error, Reason}, S1} - end; -handle_recv(S = #state{ buf = Buf }, Len, _TO) -> - <> = Buf, - {{ok, Data}, S#state{ buf = NewBuf }}. +set_active(#state{ msgbuf = [], active = {once, _}, tcp_sock = TcpSock }) -> + inet:setopts(TcpSock, [{active, once}]); +set_active(_) -> + ok. -%% A tad bit tricky, we need to be careful not to lose read data, and -%% also not spend (much) more than TO - while at the same time we can -%% have some previously received Raw data in rawbuf... -recv_noise_msg(S = #state{ rawbuf = RBuf, tcp_sock = TcpSock }, TO) -> - case recv_noise_msg_len(TcpSock, RBuf, TO) of - {error, Reason} -> - {error, S, Reason}; - {ok, TimeSpent, RBuf1} -> - TO1 = case TO of infinity -> infinity; _ -> TO - TimeSpent end, - case recv_noise_msg_data(TcpSock, RBuf1, TO1) of - {error, Reason} -> - {error, S#state{ rawbuf = RBuf1 }, Reason}; - {ok, Data} -> - {ok, S#state{rawbuf = <<>>}, Data} - end - end. - -recv_noise_msg_len(TcpSock, <<>>, TO) -> - timed_recv(TcpSock, 2, TO); -%% I wouldn't expect the following clause to ever be used -%% unless mocked tests are thrown at this! -recv_noise_msg_len(TcpSock, <>, TO) -> - case timed_recv(TcpSock, 1, TO) of - {ok, TimeSpent, <>} -> {ok, TimeSpent, <>}; - Err = {error, _} -> Err - end; -recv_noise_msg_len(_, Buf, _) -> - {ok, 0, Buf}. - -recv_noise_msg_data(TcpSock, <>, TO) -> - case gen_tcp:recv(TcpSock, MsgLen - byte_size(PreData), TO) of - {ok, Data} -> {ok, <>}; - Err = {error, _} -> Err - end. - -timed_recv(TcpSock, Len, TO) -> - Start = erlang:timestamp(), - case gen_tcp:recv(TcpSock, Len, TO) of - {ok, Data} -> - Diff = timer:now_diff(erlang:timestamp(), Start) div 1000, - {ok, Diff, Data}; - Err = {error, _} -> - Err - end. - -flush_tcp(false, _Pid, _TcpSock) -> - ok; -flush_tcp(true, Pid, TcpSock) -> +flush_tcp(Pid, TcpSock) -> receive {tcp, TcpSock, Data} -> Pid ! {tcp, TcpSock, Data}, - flush_tcp(true, Pid, TcpSock) + flush_tcp(Pid, TcpSock) after 1 -> ok end. diff --git a/src/enoise_hs_state.erl b/src/enoise_hs_state.erl index bcf26cf..d51f2e2 100644 --- a/src/enoise_hs_state.erl +++ b/src/enoise_hs_state.erl @@ -26,7 +26,8 @@ , dh = dh25519 :: noise_dh() , msgs = [] :: [enoise_protocol:noise_msg()] }). --export_type([noise_dh/0, noise_role/0, noise_token/0]). +-opaque state() :: #noise_hs{}. +-export_type([noise_dh/0, noise_role/0, noise_token/0, state/0]). -spec init(Protocol :: string() | enoise_protocol:protocol(), Role :: noise_role(), Prologue :: binary(), diff --git a/test/enoise_tests.erl b/test/enoise_tests.erl index b994e60..9f67424 100644 --- a/test/enoise_tests.erl +++ b/test/enoise_tests.erl @@ -33,17 +33,22 @@ noise_test(Conf, SKP, CKP) -> EchoSrv = echo_srv_start(Port, Protocol, SKP, CKP), - {ok, TcpSock} = gen_tcp:connect("localhost", Port, [{active, false}, binary, {reuseaddr, true}], 100), + {ok, TcpSock} = gen_tcp:connect("localhost", Port, [{active, once}, binary, {reuseaddr, true}], 100), Opts = [{noise, Protocol}, {s, CKP}] ++ [{rs, SKP} || need_rs(initiator, Conf) ], {ok, EConn} = enoise:connect(TcpSock, Opts), ok = enoise:send(EConn, <<"Hello World!">>), - {ok, <<"Hello World!">>} = enoise:recv(EConn, 12, 100), + receive + {noise, _, <<"Hello World!">>} -> ok + after 100 -> error(timeout) end, + + enoise:set_active(EConn, once), ok = enoise:send(EConn, <<"Goodbye!">>), - timer:sleep(10), - {ok, <<"Goodbye!">>} = enoise:recv(EConn, 0, 100), + receive + {noise, _, <<"Goodbye!">>} -> ok + after 100 -> error(timeout) end, enoise:close(EConn), echo_srv_stop(EchoSrv), @@ -86,27 +91,27 @@ need_rs(Role, Protocol) -> lists:member({in, [s]}, PreMsgs). %% Talks to local echo-server (noise-c) -%% client_test() -> -%% TestProtocol = enoise_protocol:from_name("Noise_XK_25519_ChaChaPoly_BLAKE2b"), -%% ClientPrivKey = <<64,168,119,119,151,194,94,141,86,245,144,220,78,53,243,231,168,216,66,199,49,148,202,117,98,40,61,109,170,37,133,122>>, -%% ClientPubKey = <<115,39,86,77,44,85,192,176,202,11,4,6,194,144,127,123, 34,67,62,180,190,232,251,5,216,168,192,190,134,65,13,64>>, -%% ServerPubKey = <<112,91,141,253,183,66,217,102,211,40,13,249,238,51,77,114,163,159,32,1,162,219,76,106,89,164,34,71,149,2,103,59>>, +client_test() -> + TestProtocol = enoise_protocol:from_name("Noise_XK_25519_ChaChaPoly_BLAKE2b"), + ClientPrivKey = <<64,168,119,119,151,194,94,141,86,245,144,220,78,53,243,231,168,216,66,199,49,148,202,117,98,40,61,109,170,37,133,122>>, + ClientPubKey = <<115,39,86,77,44,85,192,176,202,11,4,6,194,144,127,123, 34,67,62,180,190,232,251,5,216,168,192,190,134,65,13,64>>, + ServerPubKey = <<112,91,141,253,183,66,217,102,211,40,13,249,238,51,77,114,163,159,32,1,162,219,76,106,89,164,34,71,149,2,103,59>>, -%% {ok, TcpSock} = gen_tcp:connect("localhost", 7890, [{active, false}, binary, {reuseaddr, true}], 1000), -%% gen_tcp:send(TcpSock, <<0,8,0,0,3>>), %% "Noise_XK_25519_ChaChaPoly_Blake2b" + {ok, TcpSock} = gen_tcp:connect("localhost", 7890, [{active, once}, binary, {reuseaddr, true}], 1000), + gen_tcp:send(TcpSock, <<0,8,0,0,3>>), %% "Noise_XK_25519_ChaChaPoly_Blake2b" -%% Opts = [ {noise, TestProtocol} -%% , {s, enoise_keypair:new(dh25519, ClientPrivKey, ClientPubKey)} -%% , {rs, enoise_keypair:new(dh25519, ServerPubKey)} -%% , {prologue, <<0,8,0,0,3>>}], + Opts = [ {noise, TestProtocol} + , {s, enoise_keypair:new(dh25519, ClientPrivKey, ClientPubKey)} + , {rs, enoise_keypair:new(dh25519, ServerPubKey)} + , {prologue, <<0,8,0,0,3>>}], -%% {ok, EConn} = enoise:connect(TcpSock, Opts), -%% ok = enoise:send(EConn, <<"ok\n">>), -%% %% receive -%% %% {noise, EConn, <<"ok\n">>} -> ok -%% %% after 1000 -> error(timeout) end, -%% {ok, <<"ok\n">>} = enoise:recv(EConn, 3, 1000), -%% enoise:close(EConn). + {ok, EConn} = enoise:connect(TcpSock, Opts), + ok = enoise:send(EConn, <<"ok\n">>), + receive + {noise, EConn, <<"ok\n">>} -> ok + after 1000 -> error(timeout) end, + %% {ok, <<"ok\n">>} = enoise:recv(EConn, 3, 1000), + enoise:close(EConn). %% Expects a call-in from a local echo-client (noise-c)