diff options
Diffstat (limited to 'erts/epmd/test/epmd_SUITE.erl')
-rw-r--r-- | erts/epmd/test/epmd_SUITE.erl | 1261 |
1 files changed, 601 insertions, 660 deletions
diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl index a752abf33b..0f0a5acde7 100644 --- a/erts/epmd/test/epmd_SUITE.erl +++ b/erts/epmd/test/epmd_SUITE.erl @@ -1,82 +1,80 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% -module(epmd_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). % Timeout for test cases (rather long to work on slow machines) --define(SHORT_TEST_TIMEOUT, ?t:seconds(30)). % Default --define(MEDIUM_TEST_TIMEOUT, ?t:minutes(3)). --define(LONG_TEST_TIMEOUT, ?t:minutes(10)). +-define(MEDIUM_TEST_TIMEOUT, {minutes,3}). +-define(LONG_TEST_TIMEOUT, {minutes,10}). % Delay inserted into code -define(SHORT_PAUSE, 100). --define(MEDIUM_PAUSE, ?t:seconds(1)). --define(LONG_PAUSE, ?t:seconds(5)). +-define(MEDIUM_PAUSE, 1000). +-define(LONG_PAUSE, 5000). % Information about nodes -record(node_info, {port, node_type, prot, lvsn, hvsn, node_name, extra}). % Test server specific exports --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, end_per_testcase/2]). - --export( - [ - register_name/1, - register_names_1/1, - register_names_2/1, - register_duplicate_name/1, - unicode_name/1, - long_unicode_name/1, - get_port_nr/1, - slow_get_port_nr/1, - unregister_others_name_1/1, - unregister_others_name_2/1, - register_overflow/1, - name_with_null_inside/1, - name_null_terminated/1, - stupid_names_req/1, - - no_data/1, - one_byte/1, - two_bytes/1, - partial_packet/1, - zero_length/1, - too_large/1, - alive_req_too_small_1/1, - alive_req_too_small_2/1, - alive_req_too_large/1, - - returns_valid_empty_extra/1, - returns_valid_populated_extra_with_nulls/1, - - names_stdout/1, - - buffer_overrun_1/1, - buffer_overrun_2/1, - no_nonlocal_register/1, - no_nonlocal_kill/1, - no_live_killing/1 - ]). +-export([all/0, suite/0, groups/0, init_per_testcase/2, end_per_testcase/2]). + +-export([register_name/1, + register_name_ipv6/1, + register_names_1/1, + register_names_2/1, + register_duplicate_name/1, + unicode_name/1, + long_unicode_name/1, + get_port_nr/1, + slow_get_port_nr/1, + unregister_others_name_1/1, + unregister_others_name_2/1, + register_overflow/1, + name_with_null_inside/1, + name_null_terminated/1, + stupid_names_req/1, + + no_data/1, + one_byte/1, + two_bytes/1, + partial_packet/1, + zero_length/1, + too_large/1, + alive_req_too_small_1/1, + alive_req_too_small_2/1, + alive_req_too_large/1, + + returns_valid_empty_extra/1, + returns_valid_populated_extra_with_nulls/1, + + names_stdout/1, + + buffer_overrun_1/1, + buffer_overrun_2/1, + no_nonlocal_register/1, + no_nonlocal_kill/1, + no_live_killing/1, + + socket_reset_before_alive2_reply_is_written/1]). % Port we use for testing @@ -84,7 +82,7 @@ -define(EPMDARGS,"-packet_timeout 1"). -define(DUMMY_PORT, 1000). % Port number to register - % not in real use. +% not in real use. % Timeouts etc inside test cases. Time is in milliseconds. -define(CONN_RETRY, 4). % Times to retry connecting @@ -107,10 +105,13 @@ %% all/1 %% -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap, ?MEDIUM_TEST_TIMEOUT}]. all() -> - [register_name, register_names_1, register_names_2, + [register_name, register_name_ipv6, + register_names_1, register_names_2, register_duplicate_name, unicode_name, long_unicode_name, get_port_nr, slow_get_port_nr, unregister_others_name_1, unregister_others_name_2, @@ -122,93 +123,78 @@ all() -> returns_valid_populated_extra_with_nulls, names_stdout, {group, buffer_overrun}, no_nonlocal_register, - no_nonlocal_kill, no_live_killing]. + no_nonlocal_kill, no_live_killing, + socket_reset_before_alive2_reply_is_written]. groups() -> [{buffer_overrun, [], [buffer_overrun_1, buffer_overrun_2]}]. -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - %% %% Run before and after each test case %% init_per_testcase(_Func, Config) -> - Dog = test_server:timetrap(?MEDIUM_TEST_TIMEOUT), cleanup(), - [{watchdog, Dog} | Config]. + Config. -end_per_testcase(_Func, Config) -> +end_per_testcase(_Func, _Config) -> cleanup(), - Dog = ?config(watchdog, Config), - catch test_server:timetrap_cancel(Dog), % We may have canceled already ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -register_name(doc) -> - ["Register a name"]; -register_name(suite) -> - []; +%% Register a name register_name(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = register_node("foobar"), - ?line ok = close(Sock), % Unregister + ok = epmdrun(), + {ok,Sock} = register_node("foobar"), + ok = close(Sock), % Unregister ok. -register_names_1(doc) -> - ["Register and unregister two nodes"]; -register_names_1(suite) -> - []; +%% Register a name over IPv6 +register_name_ipv6(Config) when is_list(Config) -> + % Test if the host has an IPv6 loopback address + Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]), + case Res of + {ok,LSock} -> + gen_tcp:close(LSock), + ok = epmdrun(), + {ok,Sock} = register_node6("foobar6"), + ok = close(Sock), % Unregister + ok; + _Error -> + {skip, "Host does not have an IPv6 loopback address"} + end. + +%% Register and unregister two nodes register_names_1(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock1} = register_node("foobar"), - ?line {ok,Sock2} = register_node("foozap"), - ?line ok = close(Sock1), % Unregister - ?line ok = close(Sock2), % Unregister + ok = epmdrun(), + {ok,Sock1} = register_node("foobar"), + {ok,Sock2} = register_node("foozap"), + ok = close(Sock1), % Unregister + ok = close(Sock2), % Unregister ok. -register_names_2(doc) -> - ["Register and unregister two nodes"]; -register_names_2(suite) -> - []; +%% Register and unregister two nodes register_names_2(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock1} = register_node("foobar"), - ?line {ok,Sock2} = register_node("foozap"), - ?line ok = close(Sock2), % Unregister - ?line ok = close(Sock1), % Unregister + ok = epmdrun(), + {ok,Sock1} = register_node("foobar"), + {ok,Sock2} = register_node("foozap"), + ok = close(Sock2), % Unregister + ok = close(Sock1), % Unregister ok. -register_duplicate_name(doc) -> - ["Two nodes with the same name"]; -register_duplicate_name(suite) -> - []; +%% Two nodes with the same name register_duplicate_name(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = register_node("foobar"), - ?line error = register_node("foobar"), - ?line ok = close(Sock), % Unregister + ok = epmdrun(), + {ok,Sock} = register_node("foobar"), + error = register_node("foobar"), + ok = close(Sock), % Unregister ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -unicode_name(doc) -> - ["Check that we can register and lookup a unicode name"]; -unicode_name(suite) -> - []; +%% Check that we can register and lookup a unicode name unicode_name(Config) when is_list(Config) -> ok = epmdrun(), NodeName = [16#1f608], @@ -220,10 +206,7 @@ unicode_name(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -long_unicode_name(doc) -> - ["Check that we can register and lookup a long unicode name"]; -long_unicode_name(suite) -> - []; +%% Check that we can register and lookup a long unicode name long_unicode_name(Config) when is_list(Config) -> ok = epmdrun(), BaseChar = 16#1f600, @@ -241,108 +224,93 @@ register_node(Name) -> register_node(Name,Port) -> register_node_v2(Port,$M,0,5,5,Name,""). +register_node6(Name) -> + register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,""). + register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> - Utf8Name = unicode:characters_to_binary(Name), - Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot, - put16(HVsn), put16(LVsn), - put16(size(Utf8Name)), binary_to_list(Utf8Name), - size16(Extra), Extra], - case send_req(Req) of - {ok,Sock} -> - case recv(Sock,4) of - {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} -> - {ok,Sock}; - Other -> - test_server:format("recv on sock ~w: ~p~n", - [Sock,Other]), - error - end; - error -> - error + register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra). +register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> + Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra), + case send_req(Req, Addr) of + {ok,Sock} -> + case recv(Sock,4) of + {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} -> + {ok,Sock}; + Other -> + io:format("recv on sock ~w: ~p~n", [Sock,Other]), + error + end; + error -> + error end. % Internal function to fetch information about a node port_please_v2(Name) -> case send_req([?EPMD_PORT_PLEASE2_REQ, - binary_to_list(unicode:characters_to_binary(Name))]) of - {ok,Sock} -> - case recv_until_sock_closes(Sock) of - {ok, Resp} -> - parse_port2_resp(Resp); - Other -> - test_server:format("recv on sock ~w: ~p~n", - [Sock,Other]), - error - end; - error -> - error + binary_to_list(unicode:characters_to_binary(Name))]) of + {ok,Sock} -> + case recv_until_sock_closes(Sock) of + {ok, Resp} -> + parse_port2_resp(Resp); + Other -> + io:format("recv on sock ~w: ~p~n", [Sock,Other]), + error + end; + error -> + error end. parse_port2_resp(Resp) -> case list_to_binary(Resp) of - <<?EPMD_PORT2_RESP,Res,Port:16,NodeType,Prot,HVsn:16,LVsn:16, - NLen:16,NodeName:NLen/binary, - ELen:16,Extra:ELen/binary>> when Res =:= 0 -> - {ok, #node_info{port=Port,node_type=NodeType,prot=Prot, - hvsn=HVsn,lvsn=LVsn, - node_name=unicode:characters_to_list(NodeName), - extra=binary_to_list(Extra)}}; - _Other -> - test_server:format("invalid port2 resp: ~p~n", - [Resp]), - error + <<?EPMD_PORT2_RESP,Res,Port:16,NodeType,Prot,HVsn:16,LVsn:16, + NLen:16,NodeName:NLen/binary, + ELen:16,Extra:ELen/binary>> when Res =:= 0 -> + {ok, #node_info{port=Port,node_type=NodeType,prot=Prot, + hvsn=HVsn,lvsn=LVsn, + node_name=unicode:characters_to_list(NodeName), + extra=binary_to_list(Extra)}}; + _Other -> + io:format("invalid port2 resp: ~p~n", [Resp]), + error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -name_with_null_inside(doc) -> - ["Register a name with a null char in it"]; -name_with_null_inside(suite) -> - []; +%% Register a name with a null char in it name_with_null_inside(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line error = register_node("foo\000bar"), + ok = epmdrun(), + error = register_node("foo\000bar"), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -name_null_terminated(doc) -> - ["Register a name with terminating null byte"]; -name_null_terminated(suite) -> - []; +%% Register a name with terminating null byte name_null_terminated(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line error = register_node("foobar\000"), + ok = epmdrun(), + error = register_node("foobar\000"), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -stupid_names_req(doc) -> - ["Read names from epmd in a stupid way"]; -stupid_names_req(suite) -> - []; +%% Read names from epmd in a stupid way stupid_names_req(Config) when is_list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - LongDog = test_server:timetrap(?MEDIUM_TEST_TIMEOUT), - ?line ok = epmdrun(), - ?line [FirstConn | Conn] = register_many(1, ?REG_REPEAT_LIM, "foo"), - ?line unregister_many([FirstConn]), + ok = epmdrun(), + [FirstConn | Conn] = register_many(1, ?REG_REPEAT_LIM, "foo"), + unregister_many([FirstConn]), sleep(?MEDIUM_PAUSE), - ?line ok = check_names(Conn), - ?line ok = unregister_many(Conn), - test_server:timetrap_cancel(LongDog), + ok = check_names(Conn), + ok = unregister_many(Conn), ok. check_names(Conn) -> - ?line {ok,Sock} = connect_active(), - ?line {ok,Reply} = do_get_names(Sock), - ?line SortConn = lists:sort(Conn), - ?line SortReply = lists:sort(Reply), - ?line ok = check_names_cmp(SortConn, SortReply), + {ok,Sock} = connect_active(), + {ok,Reply} = do_get_names(Sock), + SortConn = lists:sort(Conn), + SortReply = lists:sort(Reply), + ok = check_names_cmp(SortConn, SortReply), ok. - + % Compare if the result was the same as was registered @@ -356,43 +324,43 @@ check_names_cmp([{Name,Port,_Sock} | Conn], [{Name,Port} | Reply]) -> -define(int16(X), [(X bsr 8) band 16#ff, X band 16#ff]). -define(u32(X1,X2,X3,X4), - (((X1) bsl 24) bor ((X2) bsl 16) bor ((X3) bsl 8) bor X4)). + (((X1) bsl 24) bor ((X2) bsl 16) bor ((X3) bsl 8) bor X4)). do_get_names(Socket) -> inet_tcp:send(Socket, [?int16(1),?EPMD_NAMES_REQ]), receive - {tcp, Socket, [P0,P1,P2,P3 | T]} -> - EpmdPort = ?u32(P0,P1,P2,P3), - if EpmdPort == ?PORT -> - names_loop(Socket, T, []); - true -> - close(Socket), - {error, address} - end; - {tcp_closed, Socket} -> - {ok, []} + {tcp, Socket, [P0,P1,P2,P3 | T]} -> + EpmdPort = ?u32(P0,P1,P2,P3), + if EpmdPort == ?PORT -> + names_loop(Socket, T, []); + true -> + close(Socket), + {error, address} + end; + {tcp_closed, Socket} -> + {ok, []} end. names_loop(Socket, Acc, Ps) -> receive - {tcp, Socket, Bytes} -> - {NAcc, NPs} = scan_names(Acc ++ Bytes, Ps), - names_loop(Socket, NAcc, NPs); - {tcp_closed, Socket} -> - {_, NPs} = scan_names(Acc, Ps), % Really needed? - {ok, NPs} + {tcp, Socket, Bytes} -> + {NAcc, NPs} = scan_names(Acc ++ Bytes, Ps), + names_loop(Socket, NAcc, NPs); + {tcp_closed, Socket} -> + {_, NPs} = scan_names(Acc, Ps), % Really needed? + {ok, NPs} end. scan_names(Buf, Ps) -> case scan_line(Buf, []) of - {Line, NBuf} -> - case parse_line(Line) of - {ok, Entry} -> - scan_names(NBuf, [Entry | Ps]); - error -> - scan_names(NBuf, Ps) - end; - [] -> {Buf, Ps} + {Line, NBuf} -> + case parse_line(Line) of + {ok, Entry} -> + scan_names(NBuf, [Entry | Ps]); + error -> + scan_names(NBuf, Ps) + end; + [] -> {Buf, Ps} end. scan_line([$\n | Buf], Line) -> {lists:reverse(Line), Buf}; @@ -401,16 +369,16 @@ scan_line([], _) -> []. parse_line([$n,$a,$m,$e,$ | Buf0]) -> case parse_name(Buf0, []) of - {Name, Buf1} -> - case Buf1 of - [$a,$t,$ ,$p,$o,$r,$t,$ | Buf2] -> - case catch list_to_integer(Buf2) of - {'EXIT', _} -> error; - Port -> {ok, {Name, Port}} - end; - _ -> error - end; - error -> error + {Name, Buf1} -> + case Buf1 of + [$a,$t,$ ,$p,$o,$r,$t,$ | Buf2] -> + case catch list_to_integer(Buf2) of + {'EXIT', _} -> error; + Port -> {ok, {Name, Port}} + end; + _ -> error + end; + error -> error end; parse_line(_) -> error. @@ -422,17 +390,11 @@ parse_name([], _Name) -> error. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_port_nr(doc) -> - ["Register a name on a port and ask about port nr"]; -get_port_nr(suite) -> - []; +%% Register a name on a port and ask about port nr get_port_nr(Config) when is_list(Config) -> port_request([?EPMD_PORT_PLEASE2_REQ,"foo"]). -slow_get_port_nr(doc) -> - ["Register with slow write and ask about port nr"]; -slow_get_port_nr(suite) -> - []; +%% Register with slow write and ask about port nr slow_get_port_nr(Config) when is_list(Config) -> port_request([?EPMD_PORT_PLEASE2_REQ,d,$f,d,$o,d,$o]). @@ -440,142 +402,127 @@ slow_get_port_nr(Config) when is_list(Config) -> % Internal function used above port_request(M) -> - ?line ok = epmdrun(), + ok = epmdrun(), Port = 1042, - ?line {ok,RSock} = register_node("foo", Port), - ?line {ok,Sock} = connect(), - ?line ok = send(Sock,[size16(M),M]), - ?line case recv_until_sock_closes(Sock) of - {ok, Resp} -> - ?line close(RSock), - ?line {ok,Rec} = parse_port2_resp(Resp), - ?line Port = Rec#node_info.port, - ok; - Other -> - ?line close(RSock), - ?line test_server:format("recv on sock ~w: ~p~n", - [Sock,Other]), - ?line throw({error,Other}) - end, + {ok,RSock} = register_node("foo", Port), + {ok,Sock} = connect(), + ok = send(Sock,[size16(M),M]), + case recv_until_sock_closes(Sock) of + {ok, Resp} -> + close(RSock), + {ok,Rec} = parse_port2_resp(Resp), + Port = Rec#node_info.port, + ok; + Other -> + close(RSock), + io:format("recv on sock ~w: ~p~n", [Sock,Other]), + throw({error,Other}) + end, ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -unregister_others_name_1(doc) -> - ["Unregister name of other node"]; -unregister_others_name_1(suite) -> - []; +%% Unregister name of other node unregister_others_name_1(Config) when is_list(Config) -> - ?line ok = epmdrun("-relaxed_command_check"), - ?line {ok,RSock} = register_node("foo"), - ?line {ok,Sock} = connect(), + ok = epmdrun("-relaxed_command_check"), + {ok,RSock} = register_node("foo"), + {ok,Sock} = connect(), M = [?EPMD_STOP_REQ,"foo"], - ?line ok = send(Sock,[size16(M),M]), + ok = send(Sock,[size16(M),M]), R = "STOPPED", - ?line {ok,R} = recv(Sock,length(R)), - ?line ok = close(RSock), + {ok,R} = recv(Sock,length(R)), + ok = close(RSock), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -unregister_others_name_2(doc) -> - ["Unregister name of other node"]; -unregister_others_name_2(suite) -> - []; +%% Unregister name of other node unregister_others_name_2(Config) when is_list(Config) -> - ?line ok = epmdrun("-relaxed_command_check"), - ?line {ok,Sock} = connect(), + ok = epmdrun("-relaxed_command_check"), + {ok,Sock} = connect(), M = [?EPMD_STOP_REQ,"xxx42"], - ?line ok = send(Sock,[size16(M),M]), + ok = send(Sock,[size16(M),M]), R = "NOEXIST", - ?line {ok,R} = recv(Sock,length(R)), + {ok,R} = recv(Sock,length(R)), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -register_overflow(doc) -> - ["Register too many, clean and redo 10 times"]; -register_overflow(suite) -> - []; +%% Register too many, clean and redo 10 times register_overflow(Config) when is_list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - LongDog = test_server:timetrap(?LONG_TEST_TIMEOUT), - ?line ok = epmdrun(), - ?line Conn = register_many(1, ?REG_REPEAT_LIM, "foo"), + ct:timetrap(?LONG_TEST_TIMEOUT), + ok = epmdrun(), + Conn = register_many(1, ?REG_REPEAT_LIM, "foo"), Count = length(Conn), - ?line ok = unregister_many(Conn), + ok = unregister_many(Conn), sleep(?MEDIUM_PAUSE), - test_server:format("Limit was ~w names, now reg/unreg all 10 times~n", - [Count]), - ?line ok = register_repeat(Count), + io:format("Limit was ~w names, now reg/unreg all 10 times~n", [Count]), + ok = register_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = rregister_repeat(Count), + ok = rregister_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = register_repeat(Count), + ok = register_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = rregister_repeat(Count), + ok = rregister_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = register_repeat(Count), + ok = register_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = rregister_repeat(Count), + ok = rregister_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = register_repeat(Count), + ok = register_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = rregister_repeat(Count), + ok = rregister_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = register_repeat(Count), + ok = register_repeat(Count), sleep(?MEDIUM_PAUSE), - ?line ok = rregister_repeat(Count), - test_server:timetrap_cancel(LongDog), + ok = rregister_repeat(Count), ok. register_repeat(Count) -> Conn = register_many(1, ?REG_REPEAT_LIM, "foo"), ok = unregister_many(Conn), if - length(Conn) == Count -> - ok; - true -> - error + length(Conn) == Count -> + ok; + true -> + error end. rregister_repeat(Count) -> Conn = register_many(1, ?REG_REPEAT_LIM, "foo"), ok = unregister_many(lists:reverse(Conn)), if - length(Conn) == Count -> - ok; - true -> - error + length(Conn) == Count -> + ok; + true -> + error end. % Return count of successful registrations register_many(I, N, _Prefix) when I > N -> - test_server:format("Done with all ~n", []), + io:format("Done with all ~n", []), []; register_many(I, N, Prefix) -> Name = gen_name(Prefix, I), Port = ?DUMMY_PORT + I, % Just make it up case register_node(Name, Port) of - {ok,Sock} -> - [{Name,Port,Sock} | register_many(I + 1, N, Prefix)]; - Any -> - test_server:format("Can't register: ~w of 1..~w ~w~n", - [Name,N,Any]), - [] + {ok,Sock} -> + [{Name,Port,Sock} | register_many(I + 1, N, Prefix)]; + Any -> + test_server:format("Can't register: ~w of 1..~w ~w~n", [Name,N,Any]), + [] end. unregister_many([]) -> ok; unregister_many([{Name,_Port,Sock} | Socks]) -> case close(Sock) of - ok -> - unregister_many(Socks); - Any -> - test_server:format("Can't unregister: ~w reason ~w~n", [Name,Any]), - error + ok -> + unregister_many(Socks); + Any -> + test_server:format("Can't unregister: ~w reason ~w~n", [Name,Any]), + error end. gen_name(Str,Int) -> @@ -583,246 +530,203 @@ gen_name(Str,Int) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -no_data(doc) -> - ["Open but send no data"]; -no_data(suite) -> - []; +%% Open but send no data no_data(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), + ok = epmdrun(), + {ok,Sock} = connect(), sleep(?LONG_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -one_byte(doc) -> - ["Send one byte only"]; -one_byte(suite) -> - []; +%% Send one byte only one_byte(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), - ?line ok = send(Sock,[0]), + ok = epmdrun(), + {ok,Sock} = connect(), + ok = send(Sock,[0]), sleep(?LONG_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -two_bytes(doc) -> - ["Send packet size only"]; -two_bytes(suite) -> - []; +%% Send packet size only two_bytes(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), - ?line ok = send(Sock,[put16(3)]), + ok = epmdrun(), + {ok,Sock} = connect(), + ok = send(Sock,[put16(3)]), sleep(?LONG_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -partial_packet(doc) -> - ["Got only part of a packet"]; -partial_packet(suite) -> - []; +%% Got only part of a packet partial_packet(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), - ?line ok = send(Sock,[put16(100),"only a few bytes"]), + ok = epmdrun(), + {ok,Sock} = connect(), + ok = send(Sock,[put16(100),"only a few bytes"]), sleep(?LONG_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -zero_length(doc) -> - ["Invalid zero packet size"]; -zero_length(suite) -> - []; +%% Invalid zero packet size zero_length(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), - ?line ok = send(Sock,[0,0,0,0,0,0,0,0,0,0]), + ok = epmdrun(), + {ok,Sock} = connect(), + ok = send(Sock,[0,0,0,0,0,0,0,0,0,0]), sleep(?MEDIUM_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -too_large(doc) -> - ["Invalid large packet"]; -too_large(suite) -> - []; +%% Invalid large packet too_large(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), + ok = epmdrun(), + {ok,Sock} = connect(), Size = 63000, M = lists:duplicate(Size, $z), - ?line ok = send(Sock,[put16(Size),M]), + ok = send(Sock,[put16(Size),M]), sleep(?MEDIUM_PAUSE), % With such a large packet, even the writes can fail as the % daemon closes before everything is delivered -> econnaborted case recv(Sock,1) of - closed -> ok; - {error,econnaborted} -> ok; - Other -> exit({unexpected,Other}) + closed -> ok; + {error,econnaborted} -> ok; + Other -> exit({unexpected,Other}) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -alive_req_too_small_1(doc) -> - ["Try to register but not enough data"]; -alive_req_too_small_1(suite) -> - []; +%% Try to register but not enough data alive_req_too_small_1(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), + ok = epmdrun(), + {ok,Sock} = connect(), M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5), - put16(5),put16(0)], - ?line ok = send(Sock, [size16(M), M]), + put16(5),put16(0)], + ok = send(Sock, [size16(M), M]), sleep(?MEDIUM_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -alive_req_too_small_2(doc) -> - ["Try to register but not enough data"]; -alive_req_too_small_2(suite) -> - []; +%% Try to register but not enough data alive_req_too_small_2(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), + ok = epmdrun(), + {ok,Sock} = connect(), M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5), - put16(5)], - ?line ok = send(Sock, [size16(M), M]), + put16(5)], + ok = send(Sock, [size16(M), M]), sleep(?MEDIUM_PAUSE), - ?line closed = recv(Sock,1), + closed = recv(Sock,1), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -alive_req_too_large(doc) -> - ["Try to register but node name too large"]; -alive_req_too_large(suite) -> - []; +%% Try to register but node name too large alive_req_too_large(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = connect(), - L = [ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ], + ok = epmdrun(), + {ok,Sock} = connect(), + L = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], S = length(lists:flatten(L)), M = [?EPMD_ALIVE2_REQ, put16(?DUMMY_PORT),$M,0, put16(5), - put16(5), put16(S),L,put16(0)], - ?line ok = send(Sock, [size16(M), M]), + put16(5), put16(S),L,put16(0)], + ok = send(Sock, [size16(M), M]), sleep(?MEDIUM_PAUSE), - ?line {ok,[?EPMD_ALIVE2_RESP,1]} = recv(Sock,2), + {ok,[?EPMD_ALIVE2_RESP,1]} = recv(Sock,2), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -returns_valid_empty_extra(doc) -> - ["Check that an empty extra is prefixed by a two byte length"]; -returns_valid_empty_extra(suite) -> - []; +%% Check that an empty extra is prefixed by a two byte length returns_valid_empty_extra(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", []), - ?line {ok,#node_info{extra=[]}} = port_please_v2("foo"), - ?line ok = close(Sock), + ok = epmdrun(), + {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", []), + {ok,#node_info{extra=[]}} = port_please_v2("foo"), + ok = close(Sock), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -returns_valid_populated_extra_with_nulls(doc) -> - ["Check a populated extra with embedded null characters"]; -returns_valid_populated_extra_with_nulls(suite) -> - []; +%% Check a populated extra with embedded null characters returns_valid_populated_extra_with_nulls(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", "ABC\000\000"), - ?line {ok,#node_info{extra="ABC\000\000"}} = port_please_v2("foo"), - ?line ok = close(Sock), + ok = epmdrun(), + {ok,Sock} = register_node_v2(4711, 72, 0, 5, 5, "foo", "ABC\000\000"), + {ok,#node_info{extra="ABC\000\000"}} = port_please_v2("foo"), + ok = close(Sock), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -names_stdout(doc) -> - ["Test that epmd -names prints registered nodes to stdout"]; -names_stdout(suite) -> - []; +%% Test that epmd -names prints registered nodes to stdout names_stdout(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,Sock} = register_node("foobar"), - ?line ok = epmdrun("-names"), - ?line {ok, Data} = receive {_Port, {data, D}} -> {ok, D} - after 10000 -> {error, timeout} - end, - ?line {match,_} = re:run(Data, "^epmd: up and running", [multiline]), - ?line {match,_} = re:run(Data, "^name foobar at port", [multiline]), - ?line ok = close(Sock), + ok = epmdrun(), + {ok,Sock} = register_node("foobar"), + ok = epmdrun("-names"), + {ok, Data} = receive {_Port, {data, D}} -> {ok, D} + after 10000 -> {error, timeout} + end, + {match,_} = re:run(Data, "^epmd: up and running", [multiline]), + {match,_} = re:run(Data, "^name foobar at port", [multiline]), + ok = close(Sock), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -buffer_overrun_1(suite) -> - []; -buffer_overrun_1(doc) -> - ["Test security vulnerability in fake extra lengths in alive2_req"]; +%% Test security vulnerability in fake extra lengths in alive2_req buffer_overrun_1(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line true = alltrue([hostile(N) || N <- lists:seq(1,10000)]), + ok = epmdrun(), + true = alltrue([hostile(N) || N <- lists:seq(1,10000)]), ok. -buffer_overrun_2(suite) -> - []; -buffer_overrun_2(doc) -> - ["Test security vulnerability in fake extra lengths in alive2_req"]; + +%% Test security vulnerability in fake extra lengths in alive2_req buffer_overrun_2(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line [false | Rest] = [hostile2(N) || N <- lists:seq(255*4,10000)], - ?line true = alltrue(Rest), + ok = epmdrun(), + [false | Rest] = [hostile2(N) || N <- lists:seq(255*4,10000)], + true = alltrue(Rest), ok. hostile(N) -> try - Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16>>, - S = size(Bin), - {ok,E}=connect_sturdy(), - gen_tcp:send(E,[<<S:16>>,Bin]), - closed = recv(E,1), - gen_tcp:close(E), - true + Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16>>, + S = size(Bin), + {ok,E}=connect_sturdy(), + gen_tcp:send(E,[<<S:16>>,Bin]), + closed = recv(E,1), + gen_tcp:close(E), + true catch - _:_ -> - false + _:_ -> + false end. hostile2(N) -> try - B2 = list_to_binary(lists:duplicate(N,255)), - Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16,B2/binary>>, - S = size(Bin), - {ok,E}=connect_sturdy(), - gen_tcp:send(E,[<<S:16>>,Bin]), - Z = recv(E,2), - gen_tcp:close(E), - (Z =:= closed) or (Z =:= {ok, [$y,1]}) + B2 = list_to_binary(lists:duplicate(N,255)), + Bin= <<$x:8,4747:16,$M:8,0:8,5:16,5:16,5:16,"gurka",N:16,B2/binary>>, + S = size(Bin), + {ok,E}=connect_sturdy(), + gen_tcp:send(E,[<<S:16>>,Bin]), + Z = recv(E,2), + gen_tcp:close(E), + (Z =:= closed) or (Z =:= {ok, [$y,1]}) catch - _A:_B -> - false + _A:_B -> + false end. alltrue([]) -> @@ -832,111 +736,137 @@ alltrue([true|T]) -> alltrue([_|_]) -> false. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -no_nonlocal_register(suite) -> - []; -no_nonlocal_register(doc) -> - ["Ensure that we cannot register throug a nonlocal connection"]; + +%% Ensure that we cannot register throug a nonlocal connection no_nonlocal_register(Config) when is_list(Config) -> - ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of - {SSH,Name} when is_list(Name), is_list(SSH) -> - do_no_nonlocal_register(Config,Name); - {false,_} -> - {skip, "No ssh command found to create proxy"}; - _ -> - {skip, "No ssh_proxy_host configured in ts.config"} - end. + case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of + {SSH,Name} when is_list(Name), is_list(SSH) -> + do_no_nonlocal_register(Config,Name); + {false,_} -> + {skip, "No ssh command found to create proxy"}; + _ -> + {skip, "No ssh_proxy_host configured in ts.config"} + end. do_no_nonlocal_register(Config,SSHHost) when is_list(Config) -> - ?line ok = epmdrun(), - ?line ProxyPort = proxy_port(), - ?line ok = ssh_proxy(SSHHost,ProxyPort), + ok = epmdrun(), + ProxyPort = proxy_port(), + ok = ssh_proxy(SSHHost,ProxyPort), Res = try - ?line Name = "gurka_" - %++ - %integer_to_list(A1)++"_"++ - %integer_to_list(A2)++"_"++ - %integer_to_list(A3)++"_"++ - %integer_to_list(A4) - , - ?line Bname = list_to_binary(Name), - ?line NameS = byte_size(Bname), - ?line Bin= <<$x:8,4747:16,$M:8,0:8,5:16, - 5:16,NameS:16,Bname/binary, - 0:16>>, - ?line S = size(Bin), - ?line {ok, E} = connect("localhost",ProxyPort,passive), - ?line gen_tcp:send(E,[<<S:16>>,Bin]), - ?line closed = recv(E,1), - ?line gen_tcp:close(E), - true - catch - _:_ -> - false - end, + Name = "gurka_" + %++ + %integer_to_list(A1)++"_"++ + %integer_to_list(A2)++"_"++ + %integer_to_list(A3)++"_"++ + %integer_to_list(A4) + , + Bname = list_to_binary(Name), + NameS = byte_size(Bname), + Bin= <<$x:8,4747:16,$M:8,0:8,5:16, + 5:16,NameS:16,Bname/binary, + 0:16>>, + S = size(Bin), + {ok, E} = connect("localhost",ProxyPort,passive), + gen_tcp:send(E,[<<S:16>>,Bin]), + closed = recv(E,1), + gen_tcp:close(E), + true + catch + _:_ -> + false + end, %erlang:display(Res), true = Res, ok. -no_nonlocal_kill(suite) -> - []; -no_nonlocal_kill(doc) -> - ["Ensure that we cannot kill through nonlocal connection"]; +%% Ensure that we cannot kill through nonlocal connection no_nonlocal_kill(Config) when is_list(Config) -> - ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of - {SSH,Name} when is_list(Name), is_list(SSH) -> - do_no_nonlocal_kill(Config,Name); - {false,_} -> - {skip, "No ssh command found to create proxy"}; - _ -> - {skip, "No ssh_proxy_host configured in ts.config"} - end. + case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of + {SSH,Name} when is_list(Name), is_list(SSH) -> + do_no_nonlocal_kill(Config,Name); + {false,_} -> + {skip, "No ssh command found to create proxy"}; + _ -> + {skip, "No ssh_proxy_host configured in ts.config"} + end. do_no_nonlocal_kill(Config,SSHHost) when is_list(Config) -> - ?line ok = epmdrun(), - ?line ProxyPort = proxy_port(), - ?line ok = ssh_proxy(SSHHost,ProxyPort), + ok = epmdrun(), + ProxyPort = proxy_port(), + ok = ssh_proxy(SSHHost,ProxyPort), Res = try - {ok, E} = connect("localhost",ProxyPort,passive), - M = [?EPMD_KILL_REQ], - send(E, [size16(M), M]), - closed = recv(E,2), - gen_tcp:close(E), - sleep(?MEDIUM_PAUSE), - {ok, E2} = connect("localhost",ProxyPort,passive), - gen_tcp:close(E2), - true - catch - _:_ -> - false - end, + {ok, E} = connect("localhost",ProxyPort,passive), + M = [?EPMD_KILL_REQ], + send(E, [size16(M), M]), + closed = recv(E,2), + gen_tcp:close(E), + sleep(?MEDIUM_PAUSE), + {ok, E2} = connect("localhost",ProxyPort,passive), + gen_tcp:close(E2), + true + catch + _:_ -> + false + end, %erlang:display(Res), true = Res, ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -no_live_killing(doc) -> - ["Dont allow killing with live nodes or any unregistering w/o -relaxed_command_check"]; -no_live_killing(suite) -> - []; + +%% Dont allow killing with live nodes or any unregistering w/o -relaxed_command_check no_live_killing(Config) when is_list(Config) -> - ?line ok = epmdrun(), - ?line {ok,RSock} = register_node("foo"), - ?line {ok,Sock} = connect(), - ?line M = [?EPMD_KILL_REQ], - ?line ok = send(Sock,[size16(M),M]), - ?line {ok,"NO"} = recv(Sock,2), - ?line close(Sock), - ?line {ok,Sock2} = connect(), - ?line M2 = [?EPMD_STOP_REQ,"foo"], - ?line ok = send(Sock2,[size16(M2),M2]), - ?line closed = recv(Sock2,1), - ?line close(Sock2), - ?line close(RSock), - ?line sleep(?MEDIUM_PAUSE), - ?line {ok,Sock3} = connect(), - ?line M3 = [?EPMD_KILL_REQ], - ?line ok = send(Sock3,[size16(M3),M3]), - ?line {ok,"OK"} = recv(Sock3,2), - ?line close(Sock3), + ok = epmdrun(), + {ok,RSock} = register_node("foo"), + {ok,Sock} = connect(), + M = [?EPMD_KILL_REQ], + ok = send(Sock,[size16(M),M]), + {ok,"NO"} = recv(Sock,2), + close(Sock), + {ok,Sock2} = connect(), + M2 = [?EPMD_STOP_REQ,"foo"], + ok = send(Sock2,[size16(M2),M2]), + closed = recv(Sock2,1), + close(Sock2), + close(RSock), + sleep(?MEDIUM_PAUSE), + {ok,Sock3} = connect(), + M3 = [?EPMD_KILL_REQ], + ok = send(Sock3,[size16(M3),M3]), + {ok,"OK"} = recv(Sock3,2), + close(Sock3), ok. +%% Check for regression - don't make zombie from node which +%% sends TCP RST at wrong time +socket_reset_before_alive2_reply_is_written(Config) when is_list(Config) -> + %% - delay_write for easier triggering of race condition + %% - relaxed_command_check for gracefull shutdown of epmd even if there + %% is stuck node. + ok = epmdrun("-delay_write 1 -relaxed_command_check"), + + %% We can't use send_req/1 directly as we want to do inet:setopts/2 + %% on our socket. + {ok, Sock} = connect(), + + %% Issuing close/1 on such socket will result in immediate RST packet. + ok = inet:setopts(Sock, [{linger, {true, 0}}]), + + Req = alive2_req(4711, 77, 0, 5, 5, "test", []), + ok = send(Sock, [size16(Req), Req]), + + timer:sleep(500), %% Wait for the first 1/2 of delay_write before closing + ok = close(Sock), + + timer:sleep(500 + ?SHORT_PAUSE), %% Wait for the other 1/2 of delay_write + + %% Wait another delay_write interval, due to delay doubling in epmd. + %% Should be removed when this is issue is fixed there. + timer:sleep(1000), + + {ok, SockForNames} = connect_active(), + + %% And there should be no stuck nodes + {ok, []} = do_get_names(SockForNames), + ok = close(SockForNames), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Terminate all tests with killing epmd. @@ -944,14 +874,14 @@ no_live_killing(Config) when is_list(Config) -> cleanup() -> sleep(?MEDIUM_PAUSE), case connect() of - {ok,Sock} -> - M = [?EPMD_KILL_REQ], - send(Sock, [size16(M), M]), - recv(Sock,length("OK")), - close(Sock), - sleep(?MEDIUM_PAUSE); - _ -> - true + {ok,Sock} -> + M = [?EPMD_KILL_REQ], + send(Sock, [size16(M), M]), + recv(Sock,length("OK")), + close(Sock), + sleep(?MEDIUM_PAUSE); + _ -> + true end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -961,11 +891,11 @@ proxy_port() -> ?PORT+1. ssh_proxy(SSHHost,ProxyPort) -> - ?line Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")), + Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")), % Requires proxy to be a unix host with the command 'read' accessible - ?line osrun("ssh -L "++integer_to_list(ProxyPort)++":"++Host++":" - ++integer_to_list(?PORT)++" "++SSHHost++" read"). - + osrun("ssh -L "++integer_to_list(ProxyPort)++":"++Host++":" + ++integer_to_list(?PORT)++" "++SSHHost++" read"). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -975,21 +905,21 @@ epmdrun() -> epmdrun([]). epmdrun(Args) -> case os:find_executable(epmd) of - false -> - {error, {could_not_find_epmd_in_path}}; - Path -> - epmdrun(Path,Args) + false -> + {error, {could_not_find_epmd_in_path}}; + Path -> + epmdrun(Path,Args) end. epmdrun(Epmd,Args0) -> - %% test_server:format("epmdrun() => Epmd = ~p",[Epmd]), + %% test_server:format("epmdrun() => Epmd = ~p",[Epmd]), Args = case Args0 of - [] -> - []; - O -> - " "++O - end, - osrun("\"" ++ Epmd ++ "\"" ++ " " ?EPMDARGS " -port " ++ integer_to_list(?PORT) ++ Args). + [] -> + []; + O -> + " "++O + end, + osrun("\"" ++ Epmd ++ "\"" ++ " " ?EPMDARGS " -port " ++ integer_to_list(?PORT) ++ Args). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -998,7 +928,7 @@ epmdrun(Epmd,Args0) -> osrun(Cmd) -> _ = open_port({spawn, Cmd}, []), ok. - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Wrappers of TCP functions @@ -1023,16 +953,16 @@ connect(Addr, Port, Mode) -> connect(Addr, Port, Mode, ?CONN_SLEEP, ?CONN_RETRY). connect(Addr, Port, Mode, Sleep, Retry) -> case connect_repeat(Addr, Retry, Port, Mode, Sleep) of - {ok,Sock} -> - {ok,Sock}; - {error,timeout} -> - timeout; - {error,Reason} -> - test_server:format("connect: error: ~w~n",[Reason]), - error; - Any -> - test_server:format("connect: unknown message: ~w~n",[Any]), - exit(1) + {ok,Sock} -> + {ok,Sock}; + {error,timeout} -> + timeout; + {error,Reason} -> + test_server:format("connect: error: ~w~n",[Reason]), + error; + Any -> + test_server:format("connect: unknown message: ~w~n",[Any]), + exit(1) end. @@ -1043,33 +973,33 @@ connect_repeat(Addr, 1, Port, Mode, _Sleep) -> connect_mode(Addr,Port, Mode); connect_repeat(Addr,Retry, Port, Mode, Sleep) -> case connect_mode(Addr,Port, Mode) of - {ok,Sock} -> - {ok,Sock}; - {error,Reason} -> - test_server:format("connect: error: ~w~n",[Reason]), - timer:sleep(Sleep), - connect_repeat(Addr, Retry - 1, Port, Mode, Sleep); - Any -> - test_server:format("connect: unknown message: ~w~n",[Any]), - exit(1) + {ok,Sock} -> + {ok,Sock}; + {error,Reason} -> + test_server:format("connect: error: ~w~n",[Reason]), + timer:sleep(Sleep), + connect_repeat(Addr, Retry - 1, Port, Mode, Sleep); + Any -> + test_server:format("connect: unknown message: ~w~n",[Any]), + exit(1) end. connect_mode(Addr,Port, active) -> gen_tcp:connect(Addr, Port, [{packet, 0}], ?CONN_TIMEOUT); connect_mode(Addr, Port, passive) -> gen_tcp:connect(Addr, Port, [{packet, 0}, {active, false}], - ?CONN_TIMEOUT). + ?CONN_TIMEOUT). close(Sock) -> case gen_tcp:close(Sock) of - {error,_} -> - error; - ok -> - ok; - Any -> - test_server:format("unknown message: ~w~n",[Any]), - exit(1) + {error,_} -> + error; + ok -> + ok; + Any -> + test_server:format("unknown message: ~w~n",[Any]), + exit(1) end. recv(Sock, Len) -> @@ -1077,19 +1007,19 @@ recv(Sock, Len) -> recv(Sock, Len, Timeout) -> case gen_tcp:recv(Sock, Len, Timeout) of - {ok,[]} -> % Should not be the case - recv(Sock, 1, 1); % any longer - {ok,Data} -> - {ok,Data}; - {error,timeout} -> - timeout; - {error,closed} -> - closed; - {error,_}=Error -> - Error; - Any -> - test_server:format("unknown message: ~w~n",[Any]), - exit(1) + {ok,[]} -> % Should not be the case + recv(Sock, 1, 1); % any longer + {ok,Data} -> + {ok,Data}; + {error,timeout} -> + timeout; + {error,closed} -> + closed; + {error,_}=Error -> + Error; + Any -> + test_server:format("unknown message: ~w~n",[Any]), + exit(1) end. %% Send data to socket. The list can be non flat and contain @@ -1098,12 +1028,12 @@ recv(Sock, Len, Timeout) -> send(Sock, SendSpec) -> case send(SendSpec, [], Sock) of - {ok,[]} -> - ok; - {ok,RevBytes} -> - send_direct(Sock, lists:reverse(RevBytes)); - Any -> - Any + {ok,[]} -> + ok; + {ok,RevBytes} -> + send_direct(Sock, lists:reverse(RevBytes)); + Any -> + Any end. @@ -1118,52 +1048,54 @@ send([Byte | Spec], RevBytes, Sock) when is_integer(Byte) -> send(Spec, [Byte | RevBytes], Sock); send([List | Spec], RevBytes, Sock) when is_list(List) -> case send(List, RevBytes, Sock) of - {ok,Left} -> - send(Spec, Left, Sock); - Other -> - Other + {ok,Left} -> + send(Spec, Left, Sock); + Other -> + Other end; send([d | Spec], RevBytes, Sock) -> send([{d,1000} | Spec], RevBytes, Sock); send([{d,S} | Spec], RevBytes, Sock) -> case send_direct(Sock, lists:reverse(RevBytes)) of - ok -> - timer:sleep(S), - send(Spec, [], Sock); - Any -> - Any + ok -> + timer:sleep(S), + send(Spec, [], Sock); + Any -> + Any end. %%%% send_direct(Sock, Bytes) -> case gen_tcp:send(Sock, Bytes) of - ok -> - ok; - {error, closed} -> - closed; - {error, _Reason} -> - error; - Any -> - test_server:format("unknown message: ~w~n",[Any]), - Any + ok -> + ok; + {error, closed} -> + closed; + {error, _Reason} -> + error; + Any -> + test_server:format("unknown message: ~w~n",[Any]), + Any end. send_req(Req) -> - case connect() of - {ok,Sock} -> - case send(Sock, [size16(Req), Req]) of - ok -> - {ok,Sock}; - Other -> - test_server:format("Failed to send ~w on sock ~w: ~w~n", - [Req,Sock,Other]), - error - end; - Other -> - test_server:format("Connect failed when sending ~w: ~p~n", - [Req, Other]), - error + send_req(Req, "localhost"). +send_req(Req, Addr) -> + case connect(Addr) of + {ok,Sock} -> + case send(Sock, [size16(Req), Req]) of + ok -> + {ok,Sock}; + Other -> + test_server:format("Failed to send ~w on sock ~w: ~w~n", + [Req,Sock,Other]), + error + end; + Other -> + test_server:format("Connect failed when sending ~w: ~p~n", + [Req, Other]), + error end. recv_until_sock_closes(Sock) -> @@ -1171,12 +1103,12 @@ recv_until_sock_closes(Sock) -> recv_until_sock_closes_2(Sock,AccData) -> case recv(Sock,0) of - {ok,Data} -> - recv_until_sock_closes_2(Sock,AccData++Data); - closed -> - {ok,AccData}; - Other -> - Other + {ok,Data} -> + recv_until_sock_closes_2(Sock,AccData++Data); + closed -> + {ok,AccData}; + Other -> + Other end. sleep(MilliSeconds) -> @@ -1198,4 +1130,13 @@ flat_count([H|T], N) when is_list(H) -> flat_count([_|T], N) -> flat_count(T, N); flat_count([], N) -> N. - + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> + Utf8Name = unicode:characters_to_binary(Name), + [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot, + put16(HVsn), put16(LVsn), + put16(size(Utf8Name)), binary_to_list(Utf8Name), + size16(Extra), Extra]. |