diff options
author | Péter Dimitrov <[email protected]> | 2018-03-20 11:26:01 +0100 |
---|---|---|
committer | Péter Dimitrov <[email protected]> | 2018-03-28 10:19:38 +0200 |
commit | 09ccfa2a6a8f8df55c7d808f5ad26324ac1e81b6 (patch) | |
tree | db6e9a1172ee8bb761041e352b6dc637fd765d28 /lib/inets/test | |
parent | 3c41882115f2cd9bfda8318925b4352cd1ec06b7 (diff) | |
download | otp-09ccfa2a6a8f8df55c7d808f5ad26324ac1e81b6.tar.gz otp-09ccfa2a6a8f8df55c7d808f5ad26324ac1e81b6.tar.bz2 otp-09ccfa2a6a8f8df55c7d808f5ad26324ac1e81b6.zip |
inets,tftp: Break out TFTP from inets
- Create directory structure
- Move code, tests, documentation from inets
- Add inets_tftp_wrapper
- Add tftp app to run-dialyzer script
Change-Id: I6a142ae66cecb9a1821cbf9ea6a45f66a836763d
Diffstat (limited to 'lib/inets/test')
-rw-r--r-- | lib/inets/test/Makefile | 15 | ||||
-rw-r--r-- | lib/inets/test/inets_SUITE.erl | 38 | ||||
-rw-r--r-- | lib/inets/test/inets_socketwrap_SUITE.erl | 34 | ||||
-rw-r--r-- | lib/inets/test/inets_sup_SUITE.erl | 24 | ||||
-rw-r--r-- | lib/inets/test/tftp_SUITE.erl | 949 | ||||
-rw-r--r-- | lib/inets/test/tftp_test_lib.erl | 308 | ||||
-rw-r--r-- | lib/inets/test/tftp_test_lib.hrl | 44 |
7 files changed, 7 insertions, 1405 deletions
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile index 4dab4e14c6..0e33b72095 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -138,8 +138,6 @@ MODULES = \ httpd_test_lib \ inets_sup_SUITE \ inets_SUITE \ - tftp_test_lib \ - tftp_SUITE \ uri_SUITE \ inets_socketwrap_SUITE @@ -149,8 +147,7 @@ EBIN = . HRL_FILES = inets_test_lib.hrl \ inets_internal.hrl \ httpc_internal.hrl \ - http_internal.hrl \ - tftp_test_lib.hrl + http_internal.hrl ERL_FILES = $(MODULES:%=%.erl) @@ -165,8 +162,7 @@ INETS_FILES = inets.config $(INETS_SPECS) # SUB_SUITES = \ # inets_sup_suite \ # inets_httpd_suite \ -# inets_httpc_suite \ -# inets_tftp_suite +# inets_httpc_suite INETS_DATADIRS = inets_SUITE_data inets_socketwrap_SUITE_data @@ -299,10 +295,3 @@ info: @echo "INETS_PRIV_DIR = $(INETS_PRIV_DIR)" @echo "INETS_ROOT = $(INETS_ROOT)" @echo "INETS_FLAGS = $(INETS_FLAGS)" - -tftp: - erlc $(ERL_COMPILE_FLAGS) tftp_test_lib.erl tftp_SUITE.erl && erl -pa ../../inets/ebin -s tftp_SUITE t -s erlang halt - -tftp_work: - echo "tftp_test_lib:t([{tftp_SUITE, all}])." - erlc $(ERL_COMPILE_FLAGS) tftp_test_lib.erl tftp_SUITE.erl && erl -pa ../../inets/ebin diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl index 12db2479d2..07ce594a1d 100644 --- a/lib/inets/test/inets_SUITE.erl +++ b/lib/inets/test/inets_SUITE.erl @@ -41,8 +41,7 @@ groups() -> [{services_test, [], [start_inets, start_httpc, - start_httpd, - start_tftpd + start_httpd ]}, {app_test, [], [app, appup]}]. @@ -297,41 +296,6 @@ start_httpd(Config) when is_list(Config) -> %%------------------------------------------------------------------------- -start_tftpd() -> - [{doc, "Start/stop of tfpd service"}]. -start_tftpd(Config) when is_list(Config) -> - process_flag(trap_exit, true), - ok = inets:start(), - {ok, Pid0} = inets:start(tftpd, [{host, "localhost"}, {port, 0}]), - Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], - true = lists:member(Pid0, Pids0), - [_|_] = inets:services_info(), - inets:stop(tftpd, Pid0), - ct:sleep(100), - Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], - false = lists:member(Pid0, Pids1), - {ok, Pid1} = - inets:start(tftpd, [{host, "localhost"}, {port, 0}], stand_alone), - Pids2 = [ServicePid || {_, ServicePid} <- inets:services()], - false = lists:member(Pid1, Pids2), - ok = inets:stop(stand_alone, Pid1), - receive - {'EXIT', Pid1, shutdown} -> - ok - after 100 -> - ct:fail(stand_alone_not_shutdown) - end, - ok = inets:stop(), - application:load(inets), - application:set_env(inets, services, [{tftpd,[{host, "localhost"}, - {port, 0}]}]), - ok = inets:start(), - (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), - application:unset_env(inets, services), - ok = inets:stop(). - -%%------------------------------------------------------------------------- - httpd_reload() -> [{doc, "Reload httpd configuration without restarting service"}]. httpd_reload(Config) when is_list(Config) -> diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl index 7ea7e08ed1..fc87c595a9 100644 --- a/lib/inets/test/inets_socketwrap_SUITE.erl +++ b/lib/inets/test/inets_socketwrap_SUITE.erl @@ -30,7 +30,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [start_httpd_fd, start_tftpd_fd]. + [start_httpd_fd]. init_per_suite(Config) -> case os:type() of @@ -90,37 +90,7 @@ start_httpd_fd(Config) when is_list(Config) -> ct:fail(open_port_failed) end end. -%%------------------------------------------------------------------------- -start_tftpd_fd() -> - [{doc, "Start/stop of tfpd service with socket wrapper"}]. -start_tftpd_fd(Config) when is_list(Config) -> - DataDir = proplists:get_value(data_dir, Config), - case setup_node_info(node()) of - {skip, _} = Skip -> - Skip; - {Node, NodeArg} -> - InetPort = inets_test_lib:inet_port(node()), - ct:pal("Node: ~p~n", [Node]), - Wrapper = filename:join(DataDir, "setuid_socket_wrap"), - Cmd = Wrapper ++ - " -s -tftpd_69,0:" ++ integer_to_list(InetPort) - ++ " -p " ++ os:find_executable("erl") ++ - " -- " ++ NodeArg, - ct:pal("cmd: ~p~n", [Cmd]), - case open_port({spawn, Cmd}, [stderr_to_stdout]) of - Port when is_port(Port) -> - wait_node_up(Node, 10), - ct:pal("~p", [rpc:call(Node, init, get_argument, [tftpd_69])]), - ok = rpc:call(Node, inets, start, []), - {ok, Pid} = rpc:call(Node, inets, start, - [tftpd,[{host, "localhost"}]]), - {ok, Info} = rpc:call(Node, tftp, info, [Pid]), - {value,{port, InetPort}} = lists:keysearch(port, 1, Info), - rpc:call(Node, erlang, halt, []); - _ -> - ct:fail(open_port_failed) - end - end. + %%------------------------------------------------------------------------- %% Internal functions %%------------------------------------------------------------------------- diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl index d36d4dc53e..727e91e987 100644 --- a/lib/inets/test/inets_sup_SUITE.erl +++ b/lib/inets/test/inets_sup_SUITE.erl @@ -32,8 +32,7 @@ suite() -> ]. all() -> - [default_tree, tftpd_worker, - httpd_config, httpd_subtree, httpd_subtree_profile, + [default_tree, httpd_config, httpd_subtree, httpd_subtree_profile, httpc_subtree]. groups() -> @@ -147,13 +146,11 @@ default_tree() -> "in the default case."}]. default_tree(Config) when is_list(Config) -> TopSupChildren = supervisor:which_children(inets_sup), - 3 = length(TopSupChildren), + 2 = length(TopSupChildren), {value, {httpd_sup, _, supervisor,[httpd_sup]}} = lists:keysearch(httpd_sup, 1, TopSupChildren), {value, {httpc_sup, _,supervisor,[httpc_sup]}} = lists:keysearch(httpc_sup, 1, TopSupChildren), - {value, {tftp_sup,_,supervisor,[tftp_sup]}} = - lists:keysearch(tftp_sup, 1, TopSupChildren), HttpcSupChildren = supervisor:which_children(httpc_sup), {value, {httpc_profile_sup,_, supervisor, [httpc_profile_sup]}} = @@ -168,24 +165,7 @@ default_tree(Config) when is_list(Config) -> = supervisor:which_children(httpc_profile_sup), [] = supervisor:which_children(httpc_handler_sup), - - [] = supervisor:which_children(tftp_sup), - - ok. -tftpd_worker() -> - [{doc, "Makes sure the tftp sub tree is correct."}]. -tftpd_worker(Config) when is_list(Config) -> - [] = supervisor:which_children(tftp_sup), - {ok, Pid0} = inets:start(tftpd, [{host, inets_test_lib:hostname()}, - {port, 0}]), - {ok, _Pid1} = inets:start(tftpd, [{host, inets_test_lib:hostname()}, - {port, 0}], stand_alone), - - [{_,Pid0, worker, _}] = supervisor:which_children(tftp_sup), - inets:stop(tftpd, Pid0), - ct:sleep(5000), - [] = supervisor:which_children(tftp_sup), ok. httpd_config() -> diff --git a/lib/inets/test/tftp_SUITE.erl b/lib/inets/test/tftp_SUITE.erl deleted file mode 100644 index 09049e36af..0000000000 --- a/lib/inets/test/tftp_SUITE.erl +++ /dev/null @@ -1,949 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2016. All Rights Reserved. -%% -%% 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 -%% -%% 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(tftp_SUITE). - --compile(export_all). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Includes and defines -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --include("tftp_test_lib.hrl"). - --define(START_DAEMON(PortX, OptionsX), - fun(Port, Options) -> - {ok, Pid} = ?VERIFY({ok, _Pid}, tftp:start([{port, Port} | Options])), - if - Port == 0 -> - {ok, ActualOptions} = ?IGNORE(tftp:info(Pid)), - {value, {port, ActualPort}} = - lists:keysearch(port, 1, ActualOptions), - {ActualPort, Pid}; - true -> - {Port, Pid} - end - end(PortX, OptionsX)). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% API -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -t() -> - tftp_test_lib:t([{?MODULE, all}]). - -t(Cases) -> - tftp_test_lib:t(Cases, default_config()). - -t(Cases, Config) -> - tftp_test_lib:t(Cases, Config). - -default_config() -> - []. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Test server callbacks -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -init_per_testcase(Case, Config) -> - tftp_test_lib:init_per_testcase(Case, Config). - -end_per_testcase(Case, Config) when is_list(Config) -> - tftp_test_lib:end_per_testcase(Case, Config). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Top test case -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [simple, extra, reuse_connection, resend_client, - resend_server, large_file]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Simple -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -simple(doc) -> - ["Start the daemon and perform simple a read and write."]; -simple(suite) -> - []; -simple(Config) when is_list(Config) -> - ?VERIFY(ok, application:start(inets)), - - {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])), - - %% Read fail - RemoteFilename = "tftp_temporary_remote_test_file.txt", - LocalFilename = "tftp_temporary_local_test_file.txt", - Blob = list_to_binary(lists:duplicate(2000, $1)), - %% Blob = <<"Some file contents\n">>, - Size = size(Blob), - ?IGNORE(file:delete(RemoteFilename)), - ?VERIFY({error, {client_open, enoent, _}}, - tftp:read_file(RemoteFilename, binary, [{port, Port}])), - - %% Write and read - ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, [{port, Port}])), - ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, [{port, Port}])), - ?IGNORE(file:delete(LocalFilename)), - ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])), - - %% Cleanup - unlink(DaemonPid), - exit(DaemonPid, kill), - ?VERIFY(ok, file:delete(LocalFilename)), - ?VERIFY(ok, file:delete(RemoteFilename)), - ?VERIFY(ok, application:stop(inets)), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Extra -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -extra(doc) -> - ["Verify new stuff for IS 1.2."]; -extra(suite) -> - []; -extra(Config) when is_list(Config) -> - ?VERIFY({'EXIT', {badarg,{fake_key, fake_flag}}}, - tftp:start([{port, 0}, {fake_key, fake_flag}])), - - {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])), - - RemoteFilename = "tftp_extra_temporary_remote_test_file.txt", - LocalFilename = "tftp_extra_temporary_local_test_file.txt", - Blob = <<"Some file contents\n">>, - Size = size(Blob), - Host = "127.0.0.1", - Peer = {inet, Host, Port}, - Generic = - [ - {state, []}, - {prepare, fun extra_prepare/6}, - {open, fun extra_open/6}, - {read, fun extra_read/1}, - {write, fun extra_write/2}, - {abort, fun extra_abort/3 } - ], - Options = [{host, Host}, - {port, Port}, - %%{ debug,all}, - {callback, {".*", tftp_test_lib, Generic}}], - ?VERIFY(ok, file:write_file(LocalFilename, Blob)), - ?VERIFY({ok, [{count, Size}, Peer]}, - tftp:write_file(RemoteFilename, LocalFilename, Options)), - ?VERIFY(ok, file:delete(LocalFilename)), - - ?VERIFY({ok,[{bin, Blob}, Peer]}, - tftp:read_file(RemoteFilename, LocalFilename, Options)), - - %% Cleanup - unlink(DaemonPid), - exit(DaemonPid, kill), - ?VERIFY(ok, file:delete(LocalFilename)), - ?VERIFY(ok, file:delete(RemoteFilename)), - ok. - --record(extra_state, {file, blksize, count, acc, peer}). - -%%------------------------------------------------------------------- -%% Prepare -%%------------------------------------------------------------------- - -extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) -> - %% Client side - BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", SuggestedOptions)), - State = #extra_state{blksize = BlkSize, peer = Peer}, - extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State), - {ok, SuggestedOptions, State}; -extra_prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) -> - {error, {undef, "Illegal callback options."}}. - -%%------------------------------------------------------------------- -%% Open -%%------------------------------------------------------------------- - -extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) -> - %% Server side - case extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) of - {ok, AcceptedOptions, []} -> - BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", AcceptedOptions)), - State = #extra_state{blksize = BlkSize, peer = Peer}, - extra_open(Peer, Access, LocalFilename, Mode, AcceptedOptions, State); - {error, {Code, Text}} -> - {error, {Code, Text}} - end; -extra_open(_Peer, Access, LocalFilename, _Mode, NegotiatedOptions, #extra_state{} = State) -> - {File, Acc} = - case Access of - read -> - if - is_binary(LocalFilename) -> - {undefined, LocalFilename}; - is_list(LocalFilename) -> - {ok, Bin} = file:read_file(LocalFilename), - {LocalFilename, Bin} - end; - write -> - {LocalFilename, []} - end, - %% Both sides - State2 = State#extra_state{file = File, acc = Acc, count = 0}, - {ok, NegotiatedOptions, State2}. - -%%------------------------------------------------------------------- -%% Read -%%------------------------------------------------------------------- - -extra_read(#extra_state{acc = Bin} = State) when is_binary(Bin) -> - BlkSize = State#extra_state.blksize, - Count = State#extra_state.count + size(Bin), - if - size(Bin) >= BlkSize -> - <<Block:BlkSize/binary, Bin2/binary>> = Bin, - State2 = State#extra_state{acc = Bin2, count = Count}, - {more, Block, State2}; - size(Bin) < BlkSize -> - Res = [{count, Count}, State#extra_state.peer], - {last, Bin, Res} - end. - -%%------------------------------------------------------------------- -%% Write -%%------------------------------------------------------------------- - -extra_write(Bin, #extra_state{acc = List} = State) when is_binary(Bin), is_list(List) -> - Size = size(Bin), - BlkSize = State#extra_state.blksize, - if - Size == BlkSize -> - {more, State#extra_state{acc = [Bin | List]}}; - Size < BlkSize -> - Bin2 = list_to_binary(lists:reverse([Bin | List])), - Res = [{bin, Bin2}, State#extra_state.peer], - file:write_file(State#extra_state.file, Bin2), - {last, Res} - end. - -%%------------------------------------------------------------------- -%% Abort -%%------------------------------------------------------------------- - -extra_abort(_Code, _Text, #extra_state{}) -> - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Re-send client -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -resend_client(doc) -> - ["Verify that the server behaves correctly when the client re-sends packets."]; -resend_client(suite) -> - []; -resend_client(Config) when is_list(Config) -> - Host = {127, 0, 0, 1}, - {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])), - - ?VERIFY(ok, resend_read_client(Host, Port, 10)), - ?VERIFY(ok, resend_read_client(Host, Port, 512)), - ?VERIFY(ok, resend_read_client(Host, Port, 1025)), - - ?VERIFY(ok, resend_write_client(Host, Port, 10)), - ?VERIFY(ok, resend_write_client(Host, Port, 512)), - ?VERIFY(ok, resend_write_client(Host, Port, 1025)), - - %% Cleanup - unlink(DaemonPid), - exit(DaemonPid, kill), - ok. - -resend_read_client(Host, Port, BlkSize) -> - RemoteFilename = "tftp_resend_read_client.tmp", - Block1 = lists:duplicate(BlkSize, $1), - Block2 = lists:duplicate(BlkSize, $2), - Block3 = lists:duplicate(BlkSize, $3), - Block4 = lists:duplicate(BlkSize, $4), - Block5 = lists:duplicate(BlkSize, $5), - Blocks = [Block1, Block2, Block3, Block4, Block5], - Blob = list_to_binary(Blocks), - ?VERIFY(ok, file:write_file(RemoteFilename, Blob)), - - Timeout = timer:seconds(3), - ?VERIFY(timeout, recv(0)), - - %% Open socket - {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - - ReadList = [0, 1, RemoteFilename, 0, "octet", 0], - Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]), - NewPort = - if - BlkSize =:= 512 -> - %% Send READ - ReadBin = list_to_binary(ReadList), - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)), - - %% Sleep a while in order to provoke the server to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv DATA #1 (the packet that the server think that we have lost) - {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Data1Bin}, recv(Timeout)), - NewPort0; - true -> - %% Send READ - BlkSizeList = integer_to_list(BlkSize), - Options = ["blksize", 0, BlkSizeList, 0], - ReadBin = list_to_binary([ReadList | Options]), - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)), - - %% Recv OACK - OptionAckBin = list_to_binary([0, 6 | Options]), - {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)), - - %% Send ACK #0 - Ack0Bin = <<0, 4, 0, 0>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)), - - %% Send ACK #0 AGAIN (pretend that we timed out) - timer:sleep(timer:seconds(1)), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)), - - %% Recv DATA #1 (the packet that the server think that we have lost) - ?VERIFY({udp, Socket, Host, NewPort0, Data1Bin}, recv(Timeout)), - NewPort0 - end, - - %% Recv DATA #1 AGAIN (the re-sent package) - ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)), - - %% Send ACK #1 - Ack1Bin = <<0, 4, 0, 1>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)), - - %% Recv DATA #2 - Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]), - ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)), - - %% Send ACK #2 - Ack2Bin = <<0, 4, 0, 2>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)), - - %% Recv DATA #3 - Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]), - ?VERIFY({udp, Socket, Host, NewPort, Data3Bin}, recv(Timeout)), - - %% Send ACK #3 - Ack3Bin = <<0, 4, 0, 3>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)), - - %% Send ACK #3 AGAIN (pretend that we timed out) - timer:sleep(timer:seconds(1)), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)), - - %% Recv DATA #4 (the packet that the server think that we have lost) - Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]), - ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)), - - %% Recv DATA #4 AGAIN (the re-sent package) - ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)), - - %% Send ACK #2 which is out of range - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)), - - %% Send ACK #4 - Ack4Bin = <<0, 4, 0, 4>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack4Bin)), - - %% Recv DATA #5 - Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]), - ?VERIFY({udp, Socket, Host, NewPort, Data5Bin}, recv(Timeout)), - - %% Send ACK #5 - Ack5Bin = <<0, 4, 0, 5>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack5Bin)), - - %% Close socket - ?VERIFY(ok, gen_udp:close(Socket)), - - ?VERIFY(timeout, recv(Timeout)), - ?VERIFY(ok, file:delete(RemoteFilename)), - ok. - -resend_write_client(Host, Port, BlkSize) -> - RemoteFilename = "tftp_resend_write_client.tmp", - Block1 = lists:duplicate(BlkSize, $1), - Block2 = lists:duplicate(BlkSize, $2), - Block3 = lists:duplicate(BlkSize, $3), - Block4 = lists:duplicate(BlkSize, $4), - Block5 = lists:duplicate(BlkSize, $5), - Blocks = [Block1, Block2, Block3, Block4, Block5], - Blob = list_to_binary(Blocks), - ?IGNORE(file:delete(RemoteFilename)), - ?VERIFY({error, enoent}, file:read_file(RemoteFilename)), - - Timeout = timer:seconds(3), - ?VERIFY(timeout, recv(0)), - - %% Open socket - {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - - WriteList = [0, 2, RemoteFilename, 0, "octet", 0], - NewPort = - if - BlkSize =:= 512 -> - %% Send WRITE - WriteBin = list_to_binary(WriteList), - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)), - - %% Sleep a while in order to provoke the server to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv ACK #0 (the packet that the server think that we have lost) - Ack0Bin = <<0, 4, 0, 0>>, - ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)), - - %% Recv ACK #0 AGAIN (the re-sent package) - {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)), - NewPort0; - true -> - %% Send WRITE - BlkSizeList = integer_to_list(BlkSize), - WriteBin = list_to_binary([WriteList, "blksize", 0, BlkSizeList, 0]), - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)), - - %% Sleep a while in order to provoke the server to re-send the packet - timer:sleep(timer:seconds(1)), - - %% Recv OACK (the packet that the server think that we have lost) - OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]), - ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)), - - %% Recv OACK AGAIN (the re-sent package) - {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)), - NewPort0 - end, - - %% Send DATA #1 - Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data1Bin)), - - %% Recv ACK #1 - Ack1Bin = <<0, 4, 0, 1>>, - ?VERIFY({udp, Socket, Host, NewPort, Ack1Bin}, recv(Timeout)), - - %% Send DATA #2 - Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)), - - %% Recv ACK #2 - Ack2Bin = <<0, 4, 0, 2>>, - ?VERIFY({udp, Socket, Host, NewPort, Ack2Bin}, recv(Timeout)), - - %% Send DATA #3 - Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)), - - %% Recv ACK #3 - Ack3Bin = <<0, 4, 0, 3>>, - ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)), - - %% Send DATA #3 AGAIN (pretend that we timed out) - timer:sleep(timer:seconds(1)), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)), - - %% Recv ACK #3 AGAIN (the packet that the server think that we have lost) - ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)), - - %% Send DATA #2 which is out of range - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)), - - %% Send DATA #4 - Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data4Bin)), - - %% Recv ACK #4 - Ack4Bin = <<0, 4, 0, 4>>, - ?VERIFY({udp, Socket, Host, NewPort, Ack4Bin}, recv(Timeout)), - - %% Send DATA #5 - Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]), - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data5Bin)), - - %% Recv ACK #5 - Ack5Bin = <<0, 4, 0, 5>>, - ?VERIFY({udp, Socket, Host, NewPort, Ack5Bin}, recv(Timeout)), - - %% Close socket - ?VERIFY(ok, gen_udp:close(Socket)), - - ?VERIFY(timeout, recv(Timeout)), - ?VERIFY({ok, Blob}, file:read_file(RemoteFilename)), - ?VERIFY(ok, file:delete(RemoteFilename)), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Re-send server -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -resend_server(doc) -> - ["Verify that the server behaves correctly when the server re-sends packets."]; -resend_server(suite) -> - []; -resend_server(Config) when is_list(Config) -> - Host = {127, 0, 0, 1}, - - ?VERIFY(ok, resend_read_server(Host, 10)), - ?VERIFY(ok, resend_read_server(Host, 512)), - ?VERIFY(ok, resend_read_server(Host, 1025)), - - ?VERIFY(ok, resend_write_server(Host, 10)), - ?VERIFY(ok, resend_write_server(Host, 512)), - ?VERIFY(ok, resend_write_server(Host, 1025)), - ok. - -resend_read_server(Host, BlkSize) -> - RemoteFilename = "tftp_resend_read_server.tmp", - Block1 = lists:duplicate(BlkSize, $1), - Block2 = lists:duplicate(BlkSize, $2), - Block3 = lists:duplicate(BlkSize, $3), - Block4 = lists:duplicate(BlkSize, $4), - Block5 = lists:duplicate(BlkSize, $5), - Block6 = [], - Blocks = [Block1, Block2, Block3, Block4, Block5, Block6], - Blob = list_to_binary(Blocks), - - Timeout = timer:seconds(3), - ?VERIFY(timeout, recv(0)), - - %% Open daemon socket - {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)), - - %% Open server socket - {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - ?IGNORE(inet:port(ServerSocket)), - - %% Prepare client process - ReplyTo = self(), - ClientFun = - fun(Extra) -> - Options = [{port, DaemonPort}, {debug, brief}] ++ Extra, - Res = ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, Options)), - ReplyTo ! {self(), {tftp_client_reply, Res}}, - exit(normal) - end, - - ReadList = [0, 1, RemoteFilename, 0, "octet", 0], - Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]), - Ack1Bin = <<0, 4, 0, 1>>, - {ClientPort, ClientPid} = - if - BlkSize =:= 512 -> - %% Start client process - ClientPid0 = spawn_link(fun() -> ClientFun([]) end), - - %% Recv READ - ReadBin = list_to_binary(ReadList), - {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)), - - %% Send DATA #1 - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)), - - %% Sleep a while in order to provoke the client to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv ACK #1 (the packet that the server think that we have lost) - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack1Bin}, recv(Timeout)), - - %% Recv ACK #1 AGAIN (the re-sent package) - ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)), - {ClientPort0, ClientPid0}; - true -> - %% Start client process - BlkSizeList = integer_to_list(BlkSize), - ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end), - - %% Recv READ - Options = ["blksize", 0, BlkSizeList, 0], - ReadBin = list_to_binary([ReadList | Options]), - {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)), - - %% Send OACK - BlkSizeList = integer_to_list(BlkSize), - OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)), - - %% Sleep a while in order to provoke the client to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv ACK #0 (the packet that the server think that we have lost) - Ack0Bin = <<0, 4, 0, 0>>, - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)), - - %% Recv ACK #0 AGAIN (the re-sent package) - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)), - - %% Send DATA #1 - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)), - - %% Recv ACK #1 - ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)), - {ClientPort0, ClientPid0} - end, - - %% Send DATA #2 - Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data2Bin)), - - %% Recv ACK #2 - Ack2Bin = <<0, 4, 0, 2>>, - ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack2Bin}, recv(Timeout)), - - %% Send DATA #3 - Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)), - - %% Recv ACK #3 - Ack3Bin = <<0, 4, 0, 3>>, - ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)), - - %% Send DATA #3 AGAIN (pretend that we timed out) - timer:sleep(timer:seconds(1)), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)), - - %% Recv ACK #3 AGAIN (the packet that the server think that we have lost) - ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)), - - %% Send DATA #4 - Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data4Bin)), - - %% Recv ACK #4 - Ack4Bin = <<0, 4, 0, 4>>, - ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack4Bin}, recv(Timeout)), - - %% Send DATA #3 which is out of range - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)), - - %% Send DATA #5 - Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data5Bin)), - - %% Recv ACK #5 - Ack5Bin = <<0, 4, 0, 5>>, - ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack5Bin}, recv(Timeout)), - - %% Send DATA #6 - Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data6Bin)), - - %% Close daemon and server sockets - ?VERIFY(ok, gen_udp:close(ServerSocket)), - ?VERIFY(ok, gen_udp:close(DaemonSocket)), - - ?VERIFY({ClientPid, {tftp_client_reply, {ok, Blob}}}, recv(Timeout)), - - ?VERIFY(timeout, recv(Timeout)), - ok. - -resend_write_server(Host, BlkSize) -> - RemoteFilename = "tftp_resend_write_server.tmp", - Block1 = lists:duplicate(BlkSize, $1), - Block2 = lists:duplicate(BlkSize, $2), - Block3 = lists:duplicate(BlkSize, $3), - Block4 = lists:duplicate(BlkSize, $4), - Block5 = lists:duplicate(BlkSize, $5), - Block6 = [], - Blocks = [Block1, Block2, Block3, Block4, Block5, Block6], - Blob = list_to_binary(Blocks), - Size = size(Blob), - - Timeout = timer:seconds(3), - ?VERIFY(timeout, recv(0)), - - %% Open daemon socket - {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)), - - %% Open server socket - {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - ?IGNORE(inet:port(ServerSocket)), - - %% Prepare client process - ReplyTo = self(), - ClientFun = - fun(Extra) -> - Options = [{port, DaemonPort}, {debug, brief}] ++ Extra, - Res = ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, Options)), - ReplyTo ! {self(), {tftp_client_reply, Res}}, - exit(normal) - end, - - WriteList = [0, 2, RemoteFilename, 0, "octet", 0], - Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]), - {ClientPort, ClientPid} = - if - BlkSize =:= 512 -> - %% Start client process - ClientPid0 = spawn_link(fun() -> ClientFun([]) end), - - %% Recv WRITE - WriteBin = list_to_binary(WriteList), - io:format("WriteBin ~p\n", [WriteBin]), - {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)), - - %% Send ACK #1 - Ack0Bin = <<0, 4, 0, 0>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Ack0Bin)), - - %% Sleep a while in order to provoke the client to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv DATA #1 (the packet that the server think that we have lost) - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)), - - %% Recv DATA #1 AGAIN (the re-sent package) - ?VERIFY({udp, ServerSocket, Host, _, Data1Bin}, recv(Timeout)), - {ClientPort0, ClientPid0}; - true -> - %% Start client process - BlkSizeList = integer_to_list(BlkSize), - ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end), - - %% Recv WRITE - Options = ["blksize", 0, BlkSizeList, 0], - WriteBin = list_to_binary([WriteList | Options]), - {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)), - - %% Send OACK - BlkSizeList = integer_to_list(BlkSize), - OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)), - - %% Sleep a while in order to provoke the client to re-send the packet - timer:sleep(Timeout + timer:seconds(1)), - - %% Recv DATA #1 (the packet that the server think that we have lost) - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)), - - %% Recv DATA #1 AGAIN (the re-sent package) - ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)), - {ClientPort0, ClientPid0} - end, - - %% Send ACK #1 - Ack1Bin = <<0, 4, 0, 1>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack1Bin)), - - %% Recv DATA #2 - Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]), - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data2Bin}, recv(Timeout)), - - %% Send ACK #2 - Ack2Bin = <<0, 4, 0, 2>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack2Bin)), - - %% Recv DATA #3 - Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]), - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data3Bin}, recv(Timeout)), - - %% Send ACK #3 - Ack3Bin = <<0, 4, 0, 3>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)), - - %% Send ACK #3 AGAIN (pretend that we timed out) - timer:sleep(timer:seconds(1)), - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)), - - %% Recv DATA #4 (the packet that the server think that we have lost) - Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]), - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)), - - %% Recv DATA #4 AGAIN (the re-sent package) - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)), - - %% Send ACK #4 - Ack4Bin = <<0, 4, 0, 4>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack4Bin)), - - %% Recv DATA #5 - Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]), - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data5Bin}, recv(Timeout)), - - %% Send ACK #3 which is out of range - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)), - - %% Send ACK #5 - Ack5Bin = <<0, 4, 0, 5>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack5Bin)), - - %% Recv DATA #6 - Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]), - ?VERIFY({udp, ServerSocket, Host, ClientPort, Data6Bin}, recv(Timeout)), - - %% Send ACK #6 - Ack6Bin = <<0, 4, 0, 6>>, - ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack6Bin)), - - %% Close daemon and server sockets - ?VERIFY(ok, gen_udp:close(ServerSocket)), - ?VERIFY(ok, gen_udp:close(DaemonSocket)), - - ?VERIFY({ClientPid, {tftp_client_reply, {ok, Size}}}, recv(Timeout)), - - ?VERIFY(timeout, recv(Timeout)), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -reuse_connection(doc) -> - ["Verify that the server can reuse an ongiong connection when same client resends request."]; -reuse_connection(suite) -> - []; -reuse_connection(Config) when is_list(Config) -> - Host = {127, 0, 0, 1}, - {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])), - - RemoteFilename = "reuse_connection.tmp", - BlkSize = 512, - Block1 = lists:duplicate(BlkSize, $1), - Block2 = lists:duplicate(BlkSize div 2, $2), - Blocks = [Block1, Block2], - Blob = list_to_binary(Blocks), - ?VERIFY(ok, file:write_file(RemoteFilename, Blob)), - - Seconds = 3, - Timeout = timer:seconds(Seconds), - ?VERIFY(timeout, recv(0)), - - %% Open socket - {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])), - - ReadList = [0, 1, RemoteFilename, 0, "octet", 0], - Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]), - - %% Send READ - TimeoutList = integer_to_list(Seconds), - Options = ["timeout", 0, TimeoutList, 0], - ReadBin = list_to_binary([ReadList | Options]), - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)), - - %% Send yet another READ for same file - ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)), - - %% Recv OACK - OptionAckBin = list_to_binary([0, 6 | Options]), - {udp, _, _, NewPort, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)), - - %% Send ACK #0 - Ack0Bin = <<0, 4, 0, 0>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack0Bin)), - - %% Recv DATA #1 - ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)), - - %% Send ACK #1 - Ack1Bin = <<0, 4, 0, 1>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)), - - %% Recv DATA #2 - Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]), - ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)), - - %% Send ACK #2 - Ack2Bin = <<0, 4, 0, 2>>, - ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)), - - %% Close socket - ?VERIFY(ok, gen_udp:close(Socket)), - - ?VERIFY(timeout, recv(Timeout)), - ?VERIFY(ok, file:delete(RemoteFilename)), - - %% Cleanup - unlink(DaemonPid), - exit(DaemonPid, kill), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Large file: transfer > 65535 blocks -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -large_file(doc) -> - ["Start the daemon and test transfer of files greater than 32M."]; -large_file(suite) -> - []; -large_file(Config) when is_list(Config) -> - ?VERIFY(ok, application:start(inets)), - - {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])), - - %% Read fail - RemoteFilename = "tftp_temporary_large_file_remote_test_file.txt", - LocalFilename = "tftp_temporary_large_file_local_test_file.txt", - - {ok, FH} = file:open(LocalFilename, [write,exclusive]), - {ok, Size} = file:position(FH, {eof, 2*512*65535}), - ok = file:truncate(FH), - ?IGNORE(file:close(FH)), - - %% Write and read - ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, LocalFilename, [{port, Port}])), - ?IGNORE(file:delete(LocalFilename)), - ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])), - - %% Cleanup - unlink(DaemonPid), - exit(DaemonPid, kill), - ?VERIFY(ok, file:delete(LocalFilename)), - ?VERIFY(ok, file:delete(RemoteFilename)), - ?VERIFY(ok, application:stop(inets)), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Goodies -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -recv(Timeout) -> - receive - Msg -> - Msg - after Timeout -> - timeout - end. diff --git a/lib/inets/test/tftp_test_lib.erl b/lib/inets/test/tftp_test_lib.erl deleted file mode 100644 index f07795324f..0000000000 --- a/lib/inets/test/tftp_test_lib.erl +++ /dev/null @@ -1,308 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2016. All Rights Reserved. -%% -%% 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 -%% -%% 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(tftp_test_lib). - --compile(export_all). - --include("tftp_test_lib.hrl"). - -%% -%% ----- -%% - -init_per_testcase(_Case, Config) when is_list(Config) -> - io:format("\n ", []), - ?IGNORE(application:stop(inets)), - Config. - -end_per_testcase(_Case, Config) when is_list(Config) -> - ?IGNORE(application:stop(inets)), - Config. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Infrastructure for test suite -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -error(Actual, Mod, Line) -> - (catch global:send(tftp_global_logger, {failed, Mod, Line})), - log("<ERROR> Bad result: ~p\n", [Actual], Mod, Line), - Label = lists:concat([Mod, "(", Line, ") unexpected result"]), - et:report_event(60, Mod, Mod, Label, - [{line, Mod, Line}, {error, Actual}]), - case global:whereis_name(tftp_test_case_sup) of - undefined -> - ignore; - Pid -> - Fail = #'REASON'{mod = Mod, line = Line, desc = Actual}, - Pid ! {fail, self(), Fail} - end, - Actual. - -log(Format, Args, Mod, Line) -> - case global:whereis_name(tftp_global_logger) of - undefined -> - io:format(user, "~p(~p): " ++ Format, - [Mod, Line] ++ Args); - Pid -> - io:format(Pid, "~p(~p): " ++ Format, - [Mod, Line] ++ Args) - end. - -default_config() -> - []. - -t() -> - t([{?MODULE, all}]). - -t(Cases) -> - t(Cases, default_config()). - -t(Cases, Config) -> - process_flag(trap_exit, true), - Res = lists:flatten(do_test(Cases, Config)), - io:format("Res: ~p\n", [Res]), - display_result(Res), - Res. - -do_test({Mod, Fun}, Config) when is_atom(Mod), is_atom(Fun) -> - case catch apply(Mod, Fun, [suite]) of - [] -> - io:format("Eval: ~p:", [{Mod, Fun}]), - Res = eval(Mod, Fun, Config), - {R, _, _} = Res, - io:format(" ~p\n", [R]), - Res; - - Cases when is_list(Cases) -> - io:format("Expand: ~p ...\n", [{Mod, Fun}]), - Map = fun(Case) when is_atom(Case)-> {Mod, Case}; - (Case) -> Case - end, - do_test(lists:map(Map, Cases), Config); - - {req, _, {conf, Init, Cases, Finish}} -> - case (catch apply(Mod, Init, [Config])) of - Conf when is_list(Conf) -> - io:format("Expand: ~p ...\n", [{Mod, Fun}]), - Map = fun(Case) when is_atom(Case)-> {Mod, Case}; - (Case) -> Case - end, - Res = do_test(lists:map(Map, Cases), Conf), - (catch apply(Mod, Finish, [Conf])), - Res; - - {'EXIT', {skipped, Reason}} -> - io:format(" => skipping: ~p\n", [Reason]), - [{skipped, {Mod, Fun}, Reason}]; - - Error -> - io:format(" => failed: ~p\n", [Error]), - [{failed, {Mod, Fun}, Error}] - end; - - {'EXIT', {undef, _}} -> - io:format("Undefined: ~p\n", [{Mod, Fun}]), - [{nyi, {Mod, Fun}, ok}]; - - Error -> - io:format("Ignoring: ~p: ~p\n", [{Mod, Fun}, Error]), - [{failed, {Mod, Fun}, Error}] - end; -do_test(Mod, Config) when is_atom(Mod) -> - Res = do_test({Mod, all}, Config), - Res; -do_test(Cases, Config) when is_list(Cases) -> - [do_test(Case, Config) || Case <- Cases]; -do_test(Bad, _Config) -> - [{badarg, Bad, ok}]. - -eval(Mod, Fun, Config) -> - TestCase = {?MODULE, Mod, Fun}, - Label = lists:concat(["TEST CASE: ", Fun]), - et:report_event(40, ?MODULE, Mod, Label ++ " started", - [TestCase, Config]), - global:register_name(tftp_test_case_sup, self()), - Flag = process_flag(trap_exit, true), - Config2 = Mod:init_per_testcase(Fun, Config), - Pid = spawn_link(?MODULE, do_eval, [self(), Mod, Fun, Config2]), - R = wait_for_evaluator(Pid, Mod, Fun, Config2, []), - Mod:end_per_testcase(Fun, Config2), - global:unregister_name(tftp_test_case_sup), - process_flag(trap_exit, Flag), - R. - -wait_for_evaluator(Pid, Mod, Fun, Config, Errors) -> - TestCase = {?MODULE, Mod, Fun}, - Label = lists:concat(["TEST CASE: ", Fun]), - receive - {done, Pid, ok} when Errors == [] -> - et:report_event(40, Mod, ?MODULE, Label ++ " ok", - [TestCase, Config]), - {ok, {Mod, Fun}, Errors}; - {done, Pid, {ok, _}} when Errors == [] -> - et:report_event(40, Mod, ?MODULE, Label ++ " ok", - [TestCase, Config]), - {ok, {Mod, Fun}, Errors}; - {done, Pid, Fail} -> - et:report_event(20, Mod, ?MODULE, Label ++ " failed", - [TestCase, Config, {return, Fail}, Errors]), - {failed, {Mod,Fun}, Fail}; - {'EXIT', Pid, {skipped, Reason}} -> - et:report_event(20, Mod, ?MODULE, Label ++ " skipped", - [TestCase, Config, {skipped, Reason}]), - {skipped, {Mod, Fun}, Errors}; - {'EXIT', Pid, Reason} -> - et:report_event(20, Mod, ?MODULE, Label ++ " crashed", - [TestCase, Config, {'EXIT', Reason}]), - {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors]}; - {fail, Pid, Reason} -> - wait_for_evaluator(Pid, Mod, Fun, Config, Errors ++ [Reason]) - end. - -do_eval(ReplyTo, Mod, Fun, Config) -> - case (catch apply(Mod, Fun, [Config])) of - {'EXIT', {skipped, Reason}} -> - ReplyTo ! {'EXIT', self(), {skipped, Reason}}; - Other -> - ReplyTo ! {done, self(), Other} - end, - unlink(ReplyTo), - exit(shutdown). - -display_result([]) -> - io:format("OK\n", []); -display_result(Res) when is_list(Res) -> - Ok = [MF || {ok, MF, _} <- Res], - Nyi = [MF || {nyi, MF, _} <- Res], - Skipped = [{MF, Reason} || {skipped, MF, Reason} <- Res], - Failed = [{MF, Reason} || {failed, MF, Reason} <- Res], - Crashed = [{MF, Reason} || {crashed, MF, Reason} <- Res], - display_summary(Ok, Nyi, Skipped, Failed, Crashed), - display_skipped(Skipped), - display_failed(Failed), - display_crashed(Crashed). - -display_summary(Ok, Nyi, Skipped, Failed, Crashed) -> - io:format("\nTest case summary:\n", []), - display_summary(Ok, "successful"), - display_summary(Nyi, "not yet implemented"), - display_summary(Skipped, "skipped"), - display_summary(Failed, "failed"), - display_summary(Crashed, "crashed"), - io:format("\n", []). - -display_summary(Res, Info) -> - io:format(" ~w test cases ~s\n", [length(Res), Info]). - -display_skipped([]) -> - ok; -display_skipped(Skipped) -> - io:format("Skipped test cases:\n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end, - lists:foreach(F, Skipped), - io:format("\n", []). - - -display_failed([]) -> - ok; -display_failed(Failed) -> - io:format("Failed test cases:\n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end, - lists:foreach(F, Failed), - io:format("\n", []). - -display_crashed([]) -> - ok; -display_crashed(Crashed) -> - io:format("Crashed test cases:\n", []), - F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end, - lists:foreach(F, Crashed), - io:format("\n", []). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% generic callback -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --record(generic_state, {state, prepare, open, read, write, abort}). - -prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) -> - State = lookup_option(state, mandatory, Initial), - Prepare = lookup_option(prepare, mandatory, Initial), - Open = lookup_option(open, mandatory, Initial), - Read = lookup_option(read, mandatory, Initial), - Write = lookup_option(write, mandatory, Initial), - Abort = lookup_option(abort, mandatory, Initial), - case Prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of - {ok, AcceptedOptions, NewState} -> - {ok, - AcceptedOptions, - #generic_state{state = NewState, - prepare = Prepare, - open = Open, - read = Read, - write = Write, - abort = Abort}}; - Other -> - Other - end. - -open(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) -> - case prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) of - {ok, SuggestedOptions2, GenericState} -> - open(Peer, Access, LocalFilename, Mode, SuggestedOptions2, GenericState); - Other -> - Other - end; -open(Peer, Access, LocalFilename, Mode, SuggestedOptions, #generic_state{state = State, open = Open} = GenericState) -> - case Open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of - {ok, SuggestedOptions2, NewState} -> - {ok, SuggestedOptions2, GenericState#generic_state{state = NewState}}; - Other -> - Other - end. - -read(#generic_state{state = State, read = Read} = GenericState) -> - case Read(State) of - {more, DataBlock, NewState} -> - {more, DataBlock, GenericState#generic_state{state = NewState}}; - Other -> - Other - end. - -write(DataBlock, #generic_state{state = State, write = Write} = GenericState) -> - case Write(DataBlock, State) of - {more, NewState} -> - {more, GenericState#generic_state{state = NewState}}; - Other -> - Other - end. - -abort(Code, Text, #generic_state{state = State, abort = Abort}) -> - Abort(Code, Text, State). - -lookup_option(Key, Default, Options) -> - case lists:keysearch(Key, 1, Options) of - {value, {_, Val}} -> - Val; - false -> - Default - end. - diff --git a/lib/inets/test/tftp_test_lib.hrl b/lib/inets/test/tftp_test_lib.hrl deleted file mode 100644 index e7a5a37d2c..0000000000 --- a/lib/inets/test/tftp_test_lib.hrl +++ /dev/null @@ -1,44 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2016. All Rights Reserved. -%% -%% 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 -%% -%% 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% -%% - --record('REASON', {mod, line, desc}). - --define(LOG(Format, Args), - tftp_test_lib:log(Format, Args, ?MODULE, ?LINE)). - --define(ERROR(Reason), - tftp_test_lib:error(Reason, ?MODULE, ?LINE)). - --define(VERIFY(Expected, Expr), - fun() -> - AcTuAlReS = (catch (Expr)), - case AcTuAlReS of - Expected -> ?LOG("Ok, ~p\n", [AcTuAlReS]); - _ -> ?ERROR(AcTuAlReS) - end, - AcTuAlReS - end()). - --define(IGNORE(Expr), - fun() -> - AcTuAlReS = (catch (Expr)), - ?LOG("Ok, ~p\n", [AcTuAlReS]), - AcTuAlReS - end()). |