1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2021 All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%%----------------------------------------------------------------------
23%% Purpose:
24%%----------------------------------------------------------------------
25-module(megaco_udp_SUITE).
26
27%%----------------------------------------------------------------------
28%% Include files
29%%----------------------------------------------------------------------
30-include_lib("common_test/include/ct.hrl").
31-include_lib("megaco/src/udp/megaco_udp.hrl").
32-include("megaco_test_lib.hrl").
33
34
35%%----------------------------------------------------------------------
36%% External exports
37%%----------------------------------------------------------------------
38-export([
39	 suite/0, all/0, groups/0,
40         init_per_suite/1, end_per_suite/1,
41         init_per_group/2, end_per_group/2,
42         init_per_testcase/2, end_per_testcase/2,
43
44	 start_normal/1,
45	 start_invalid_opt/1,
46         start_and_stop/1,
47	 sendreceive/1,
48         block_unblock/1,
49	 socket_failure/1
50
51         ]).
52
53
54%%----------------------------------------------------------------------
55%% Internal exports
56%%----------------------------------------------------------------------
57-export([
58	 receive_message/4,
59	 process_received_message/4
60        ]).
61
62
63%%----------------------------------------------------------------------
64%% Macros
65%%----------------------------------------------------------------------
66
67-define(CH,             megaco_test_command_handler).
68-define(TEST_VERBOSITY, debug).
69
70
71%%----------------------------------------------------------------------
72%% Records
73%%----------------------------------------------------------------------
74
75
76%%======================================================================
77%% Common Test interface functions
78%%======================================================================
79
80suite() ->
81    [{ct_hooks, [ts_install_cth]}].
82
83all() ->
84    %% This is a temporary messure to ensure that we can
85    %% test the socket backend without effecting *all*
86    %% applications on *all* machines.
87    %% This flag is set only for *one* host.
88    case ?TEST_INET_BACKENDS() of
89        true ->
90            [
91             {group, inet_backend_default},
92             {group, inet_backend_inet},
93             {group, inet_backend_socket}
94            ];
95        _ ->
96            [
97             {group, inet_backend_default}
98            ]
99    end.
100
101groups() ->
102    [
103     {inet_backend_default,          [], inet_backend_default_cases()},
104     {inet_backend_inet,             [], inet_backend_inet_cases()},
105     {inet_backend_socket,           [], inet_backend_socket_cases()},
106
107     {all,                           [], all_cases()},
108     {start,                         [], start_cases()},
109     {sending,                       [], sending_cases()},
110     {error,                         [], error_cases()}
111    ].
112
113inet_backend_default_cases() ->
114    [{all, [], all_cases()}].
115
116inet_backend_inet_cases() ->
117    [{all, [], all_cases()}].
118
119inet_backend_socket_cases() ->
120    [{all, [], all_cases()}].
121
122all_cases() ->
123    [
124     {group, start},
125     {group, sending},
126     {group, error}
127    ].
128
129start_cases() ->
130    [
131     start_normal,
132     start_invalid_opt,
133     start_and_stop
134    ].
135
136sending_cases() ->
137    [
138     sendreceive,
139     block_unblock
140    ].
141
142error_cases() ->
143    [
144     socket_failure
145    ].
146
147
148
149%%
150%% -----
151%%
152
153init_per_suite(suite) ->
154    [];
155init_per_suite(doc) ->
156    [];
157init_per_suite(Config0) when is_list(Config0) ->
158
159    ?ANNOUNCE_SUITE_INIT(),
160
161    p("init_per_suite -> entry with"
162      "~n      Config: ~p"
163      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
164
165    case ?LIB:init_per_suite(Config0) of
166        {skip, _} = SKIP ->
167            SKIP;
168
169        Config1 when is_list(Config1) ->
170
171            %% We need a (local) monitor on this node also
172            megaco_test_sys_monitor:start(),
173
174            p("init_per_suite -> end when"
175              "~n      Config: ~p"
176              "~n      Nodes:  ~p", [Config1, erlang:nodes()]),
177
178            Config1
179    end.
180
181end_per_suite(suite) -> [];
182end_per_suite(doc) -> [];
183end_per_suite(Config0) when is_list(Config0) ->
184
185    p("end_per_suite -> entry with"
186      "~n      Config: ~p"
187      "~n      Nodes:  ~p", [Config0, erlang:nodes()]),
188
189    megaco_test_sys_monitor:stop(),
190    Config1 = ?LIB:end_per_suite(Config0),
191
192    p("end_per_suite -> end when"
193      "~n      Nodes:  ~p", [erlang:nodes()]),
194
195    Config1.
196
197
198%%
199%% -----
200%%
201
202init_per_group(inet_backend_default = Group, Config) ->
203    ?ANNOUNCE_GROUP_INIT(Group),
204    [{socket_create_opts, []} | Config];
205init_per_group(inet_backend_inet = Group, Config) ->
206    ?ANNOUNCE_GROUP_INIT(Group),
207    case ?EXPLICIT_INET_BACKEND() of
208        true ->
209            %% The environment trumps us,
210            %% so only the default group should be run!
211            {skip, "explicit inet backend"};
212        false ->
213            [{socket_create_opts, [{inet_backend, inet}]} | Config]
214    end;
215init_per_group(inet_backend_socket = Group, Config) ->
216    ?ANNOUNCE_GROUP_INIT(Group),
217    case ?EXPLICIT_INET_BACKEND() of
218        true ->
219            %% The environment trumps us,
220            %% so only the default group should be run!
221            {skip, "explicit inet backend"};
222        false ->
223            [{socket_create_opts, [{inet_backend, socket}]} | Config]
224    end;
225init_per_group(Group, Config) ->
226    ?ANNOUNCE_GROUP_INIT(Group),
227    Config.
228
229end_per_group(_Group, Config) ->
230    Config.
231
232
233
234%%
235%% -----
236%%
237
238init_per_testcase(Case, Config) ->
239
240    p("init_per_testcase -> entry with"
241      "~n   Config: ~p"
242      "~n   Nodes:  ~p", [Config, erlang:nodes()]),
243
244    megaco_test_global_sys_monitor:reset_events(),
245
246    megaco_test_lib:init_per_testcase(Case, Config).
247
248end_per_testcase(Case, Config) ->
249
250    p("end_per_testcase -> entry with"
251      "~n   Config: ~p"
252      "~n   Nodes:  ~p", [Config, erlang:nodes()]),
253
254    p("system events during test: "
255      "~n   ~p", [megaco_test_global_sys_monitor:events()]),
256
257    megaco_test_lib:end_per_testcase(Case, Config).
258
259
260
261%% =================================================
262%%
263%% ------------------ start ------------------------
264%%
265%% =================================================
266
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268
269start_normal(suite) ->
270    [];
271start_normal(Config) when is_list(Config) ->
272    ?ACQUIRE_NODES(1, Config),
273    Opts = [{port, 0}, {receive_handle, apa}],
274    {ok, Pid} = start_case(Config, Opts, ok),
275    megaco_udp:stop_transport(Pid),
276    ok.
277
278
279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280
281start_invalid_opt(suite) ->
282    [];
283start_invalid_opt(Config) when is_list(Config) ->
284    ?ACQUIRE_NODES(1, Config),
285    Opts = [{port, 0}, {receivehandle, apa}],
286    start_case(Config, Opts, error).
287
288
289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290
291start_and_stop(suite) ->
292    [];
293start_and_stop(doc) ->
294    ["This test case sets up a connection and then cloises it. "
295     "No data is sent. "];
296start_and_stop(Config) when is_list(Config) ->
297    Factor = ?config(megaco_factor, Config),
298    ct:timetrap(Factor * ?SECS(45)),
299    Pre = fun() ->
300		  p("create nodes"),
301		  ServerNode = make_node_name(server),
302		  ClientNode = make_node_name(client),
303		  Nodes = [ServerNode, ClientNode],
304		  ok = ?START_NODES(Nodes),
305		  Nodes
306	  end,
307    Case = fun(X) -> do_start_and_stop(Config, Factor, X) end,
308    Post = fun(Nodes) ->
309                   p("stop nodes"),
310                   ?STOP_NODES(lists:reverse(Nodes))
311           end,
312    try_tc(start_and_stop, Pre, Case, Post).
313
314do_start_and_stop(Config, Factor, [ServerNode, ClientNode]) ->
315    %% Create command sequences
316    TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end,
317    TO     = TOCalc(?SECS(5)),
318    p("create command sequences"),
319    ServerPort = 2944,
320    ServerCmds = start_and_stop_server_commands(Config, ServerPort),
321    {ok, ServerHost} = inet:gethostname(),
322    ClientCmds = start_and_stop_client_commands(Config, TO, ServerPort, ServerHost),
323
324    %% Start the test procs used in the test-case, one for each node
325    p("start command handlers"),
326    Server = server_start_command_handler(ServerNode, ServerCmds),
327    p("server command handler started: ~p", [Server]),
328    Client = client_start_command_handler(ClientNode, ClientCmds),
329    p("client command handler started: ~p", [Client]),
330
331    ok     =
332        receive
333            {operational, Server} ->
334                p("received listening message from server [~p] => "
335                  "send continue to client [~p]~n", [Server, Client]),
336                Client ! {continue, self()},
337                ok;
338	    {'EXIT', Server, {skip, Reason}} ->
339		?SKIP(Reason);
340	    {'EXIT', Client, {skip, Reason}} ->
341		?SKIP(Reason)
342        after TO ->
343                {error, server_timeout}
344        end,
345
346    ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))),
347    p("done"),
348    ok.
349
350
351start_and_stop_server_commands(Config, Port) ->
352    Opts = [{port, Port}],
353    Self = self(),
354    [
355     #{id   => 1,
356       desc => "Command sequence init",
357       cmd  => fun(State) ->
358		       {ok, State#{parent => Self}}
359	       end},
360
361     #{id   => 2,
362       desc => "Start transport",
363       cmd  => fun(State) ->
364		       server_start_transport(State)
365	       end},
366
367     #{id   => 3,
368       desc => "Open",
369       cmd  => fun(State) ->
370                       server_open(Config, State, Opts)
371	      end},
372
373     #{id   => 4,
374       desc => "Notify operational",
375       cmd  => fun(State) ->
376		      server_notify_operational(State)
377	      end},
378
379     #{id   => 5,
380       desc => "Await nothing",
381       cmd  => fun(State) ->
382		      server_await_nothing(State, 5000)
383	      end},
384
385     #{id   => 6,
386       desc => "Close",
387       cmd  => fun(State) ->
388		      server_close(State)
389	      end},
390
391     #{id   => 7,
392       desc => "Stop",
393       cmd  => fun(State) ->
394		      server_stop_transport(State)
395	      end}
396
397    ].
398
399start_and_stop_client_commands(Config, TO, ServerPort, _ServerHost) ->
400    Opts = [{port, ServerPort}],
401    Self = self(),
402    [
403     #{id   => 1,
404       desc => "Command sequence init",
405       cmd  => fun(State) ->
406		       {ok, State#{parent => Self}}
407	       end},
408
409     #{id   => 2,
410       desc => "Start transport",
411       cmd  => fun(State) ->
412		       client_start_transport(State)
413	       end},
414
415     #{id   => 3,
416       desc => "Open",
417       cmd  => fun(State) ->
418		       client_open(Config, State, Opts)
419	       end},
420
421     #{id   => 4,
422       desc => "Await continue",
423       cmd  => fun(State) ->
424		       client_await_continue_signal(State, TO)
425	       end},
426
427     #{id   => 5,
428       desc => "Await nothing",
429       cmd  => fun(State) ->
430		       client_await_nothing(State, 5000)
431	       end},
432
433     #{id   => 6,
434       desc => "Close",
435       cmd  => fun(State) ->
436		       client_close(State)
437	       end},
438
439     #{id   => 7,
440       desc => "Stop transport",
441       cmd  => fun(State) ->
442		       client_stop_transport(State)
443	       end}
444    ].
445
446
447
448%% =================================================
449%%
450%% ------------------ sending ------------------------
451%%
452%% =================================================
453
454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455
456sendreceive(suite) ->
457    [];
458sendreceive(doc) ->
459    ["Test send and receive with the UDP transport. "];
460sendreceive(Config) when is_list(Config) ->
461    Factor = ?config(megaco_factor, Config),
462    ct:timetrap(Factor * ?SECS(30)),
463    Pre = fun() ->
464		  p("create nodes"),
465		  ServerNode = make_node_name(server),
466		  ClientNode = make_node_name(client),
467		  Nodes = [ServerNode, ClientNode],
468		  ok = ?START_NODES(Nodes),
469		  Nodes
470	  end,
471    Case = fun(X) -> do_sendreceive(Config, Factor, X) end,
472    Post = fun(Nodes) ->
473                   p("stop nodes"),
474                   ?STOP_NODES(lists:reverse(Nodes))
475           end,
476    try_tc(sendreceive, Pre, Case, Post).
477
478do_sendreceive(Config, Factor, [ServerNode, ClientNode]) ->
479    %% Create command sequences
480    p("create command sequences"),
481    TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end,
482    TO     = TOCalc(?SECS(5)),
483    ServerPort = 2944,
484    ServerCmds = sendreceive_server_commands(Config, TO, ServerPort),
485    {ok, ServerHost} = inet:gethostname(),
486    ClientCmds = sendreceive_client_commands(Config, TO, ServerPort, ServerHost),
487
488    %% Start the test procs used in the test-case, one for each node
489    p("start command handlers"),
490    Server = server_start_command_handler(ServerNode, ServerCmds),
491    p("server command handler started: ~p", [Server]),
492    Client = client_start_command_handler(ClientNode, ClientCmds),
493    p("client command handler started: ~p", [Client]),
494
495    ok =
496        receive
497            {operational, Server} ->
498                p("received operational message from server [~p] => "
499                  "send continue to client [~p]~n", [Server, Client]),
500                Client ! {continue, self()},
501                ok;
502	    {'EXIT', Server, {skip, Reason}} ->
503		?SKIP(Reason);
504	    {'EXIT', Client, {skip, Reason}} ->
505		?SKIP(Reason)
506	after TO ->
507                {error, server_timeout}
508        end,
509
510    ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))),
511    p("done"),
512    ok.
513
514
515sendreceive_server_commands(Config, TO, Port) ->
516    Opts = [{port, Port}],
517    Self = self(),
518    [
519     #{id   => 1,
520       desc => "Command sequence init",
521       cmd  => fun(State) ->
522		       {ok, State#{parent => Self}}
523	       end},
524
525     #{id   => 2,
526       desc => "Start transport",
527       cmd  => fun(State) ->
528		       server_start_transport(State)
529	       end},
530
531     #{id   => 3,
532       desc => "Open",
533       cmd  => fun(State) ->
534		       server_open(Config, State, Opts)
535	       end},
536
537     #{id   => 4,
538       desc => "Notify operational",
539       cmd  => fun(State) ->
540		       server_notify_operational(State)
541	       end},
542
543     #{id   => 5,
544       desc => "Await initial message (ping)",
545       cmd  => fun(State) ->
546		       server_await_initial_message(State, "ping", TO)
547	       end},
548
549     #{id   => 6,
550       desc => "Send reply (pong) to initial message",
551       cmd  => fun(State) ->
552		       server_send_message(State, "pong")
553	       end},
554
555     #{id   => 7,
556       desc => "Await nothing before sending a message (hejsan)",
557       cmd  => fun(State) ->
558		       server_await_nothing(State, TO div 5)
559	       end},
560
561     #{id   => 8,
562       desc => "Send message (hejsan)",
563       cmd  => fun(State) ->
564		       server_send_message(State, "hejsan")
565	       end},
566
567     #{id   => 9,
568       desc => "Await reply (hoppsan) to message",
569       cmd  => fun(State) ->
570		       server_await_message(State, "hoppsan", TO div 5)
571	       end},
572
573     #{id   => 10,
574       desc => "Await nothing before closing",
575       cmd  => fun(State) ->
576		       server_await_nothing(State, TO div 5)
577	       end},
578
579     #{id   => 11,
580       desc => "Close",
581       cmd  => fun(State) ->
582		       server_close(State)
583	       end},
584
585     #{id   => 12,
586       desc => "Await nothing before stopping transport",
587       cmd  => fun(State) ->
588		       server_await_nothing(State, TO div 5)
589	       end},
590
591     #{id   => 13,
592       desc => "Stop",
593       cmd  => fun(State) ->
594		       server_stop_transport(State)
595	       end}
596    ].
597
598sendreceive_client_commands(Config, TO, ServerPort, ServerHost) ->
599    OwnPort = ServerPort+1,
600    Opts    = [{port, OwnPort}],
601    Self    = self(),
602    [
603     #{id   => 1,
604       desc => "Command sequence init",
605       cmd  => fun(State) ->
606		       {ok, State#{parent => Self}}
607	       end},
608
609     #{id   => 2,
610       desc => "Start transport",
611       cmd  => fun(State) ->
612		       client_start_transport(State)
613	       end},
614
615     #{id   => 3,
616       desc => "Open",
617       cmd  => fun(State) ->
618		       client_open(Config, State, Opts)
619	       end},
620
621     #{id   => 4,
622       desc => "Await continue",
623       cmd  => fun(State) ->
624		       client_await_continue_signal(State, TO)
625	       end},
626
627     #{id   => 5,
628       desc => "Connect",
629       cmd  => fun(State) ->
630		       client_connect(State, ServerHost, ServerPort)
631	       end},
632
633     #{id   => 6,
634       desc => "Send initial message (ping)",
635       cmd  => fun(State) ->
636		       client_send_message(State, "ping")
637	       end},
638
639     #{id   => 7,
640       desc => "Await reply (pong) to initial message",
641       cmd  => fun(State) ->
642		       client_await_message(State, "pong", TO div 5)
643	       end},
644
645     #{id   => 8,
646       desc => "Await message (hejsan)",
647       cmd  => fun(State) ->
648		       client_await_message(State, "hejsan", TO)
649	       end},
650
651     #{id   => 9,
652       desc => "Send reply (hoppsan) to message",
653       cmd  => fun(State) ->
654		       client_send_message(State, "hoppsan")
655	       end},
656
657     #{id   => 10,
658       desc => "Await nothing before closing",
659       cmd  => fun(State) ->
660		       client_await_nothing(State, TO div 5)
661	       end},
662
663     #{id   => 11,
664       desc => "Close",
665       cmd  => fun(State) ->
666		       client_close(State)
667	       end},
668
669     #{id   => 12,
670       desc => "Await nothing before stopping transport",
671       cmd  => fun(State) ->
672		       client_await_nothing(State, TO div 5)
673	       end},
674
675     #{id   => 13,
676       desc => "Stop transport",
677       cmd  => fun(State) ->
678		       client_stop_transport(State)
679	       end}
680    ].
681
682
683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
684
685block_unblock(suite) ->
686    [];
687block_unblock(doc) ->
688    ["Test the block/unblock functions of the UDP transport. "];
689block_unblock(Config) when is_list(Config) ->
690    Factor = ?config(megaco_factor, Config),
691    ct:timetrap(Factor * ?MINS(1)),
692    Pre = fun() ->
693		  p("create nodes"),
694		  ServerNode = make_node_name(server),
695		  ClientNode = make_node_name(client),
696		  Nodes = [ServerNode, ClientNode],
697		  ok = ?START_NODES(Nodes),
698		  Nodes
699	  end,
700    Case = fun(X) -> do_block_unblock(Config, Factor, X) end,
701    Post = fun(Nodes) ->
702                   p("stop nodes"),
703                   ?STOP_NODES(lists:reverse(Nodes))
704           end,
705    try_tc(block_unblock, Pre, Case, Post).
706
707do_block_unblock(Config, Factor, [ServerNode, ClientNode]) ->
708    %% Create command sequences
709    p("create command sequences"),
710    TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end,
711    TO     = TOCalc(?SECS(5)),
712    ServerPort = 2944,
713    p("generated command sequences with timeout: ~w msec", [TO]),
714    ServerCmds = block_unblock_server_commands(Config, TO, ServerPort),
715    {ok, ServerHost} = inet:gethostname(),
716    ClientCmds = block_unblock_client_commands(Config, TO, ServerPort, ServerHost),
717
718    %% Start the test procs used in the test-case, one for each node
719    p("start command handlers"),
720    Server = server_start_command_handler(ServerNode, ServerCmds),
721    p("server command handler started: ~p", [Server]),
722    Client = client_start_command_handler(ClientNode, ClientCmds),
723    p("client command handler started: ~p", [Client]),
724
725    %% Wait for the server to become ready for operation
726    %% and then tell the client to continue
727    ok =
728        receive
729            {operational, Server} ->
730                p("received operational message from server [~p] => "
731                  "send continue to client [~p]~n", [Server, Client]),
732                Client ! {continue, self()},
733                ok;
734	    {'EXIT', Server, {skip, Reason1}} ->
735		?SKIP(Reason1);
736	    {'EXIT', Client, {skip, Reason2}} ->
737		?SKIP(Reason2)
738        after TO ->
739                {error, server_timeout}
740        end,
741
742    %% Wait for the client to become blocked
743    %% and then tell the server to continue
744    ok =
745	receive
746	    {blocked, Client} ->
747		p("received blocked message from client [~p] => "
748		  "send continue to server [~p]~n", [Client, Server]),
749		Server ! {continue, self()},
750		ok;
751	    {'EXIT', Server, {skip, Reason3}} ->
752		?SKIP(Reason3);
753	    {'EXIT', Client, {skip, Reason4}} ->
754		?SKIP(Reason4)
755	after TO ->
756		{error, timeout}
757	end,
758
759    ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))),
760    p("done"),
761    ok.
762
763
764block_unblock_server_commands(Config, TO, Port) ->
765    Opts = [{port, Port}],
766    Self = self(),
767    [
768     #{id   => 1,
769       desc => "Command sequence init",
770       cmd  => fun(State) ->
771		       {ok, State#{parent => Self}}
772	       end},
773
774     #{id   => 2,
775       desc => "Start transport",
776       cmd  => fun(State) ->
777		       server_start_transport(State)
778	       end},
779
780     #{id   => 3,
781       desc => "Open",
782       cmd  => fun(State) ->
783		       server_open(Config, State, Opts)
784	       end},
785
786     #{id   => 4,
787       desc => "Notify operational",
788       cmd  => fun(State) ->
789		       server_notify_operational(State)
790	       end},
791
792     #{id   => 5,
793       desc => "Await initial message (ping)",
794       cmd  => fun(State) ->
795		       server_await_initial_message(State, "ping", TO)
796	       end},
797
798     #{id   => 6,
799       desc => "Send reply (pong) to initial message",
800       cmd  => fun(State) ->
801		       server_send_message(State, "pong")
802	       end},
803
804     #{id   => 7,
805       desc => "Await continue - and nothing else",
806       cmd  => fun(State) ->
807		       server_await_continue_signal(State, TO)
808	       end},
809
810     #{id   => 8,
811       desc => "Send message (hejsan) (client is blocked)",
812       cmd  => fun(State) ->
813		       server_send_message(State, "hejsan")
814	       end},
815
816     #{id   => 9,
817       desc => "Await reply (hoppsan) to message",
818       cmd  => fun(State) ->
819		       server_await_message(State, "hoppsan", TO)
820	       end},
821
822     #{id   => 10,
823       desc => "Await nothing before closing",
824       cmd  => fun(State) ->
825		       server_await_nothing(State, TO div 5)
826	       end},
827
828     #{id   => 11,
829       desc => "Close",
830       cmd  => fun(State) ->
831		       server_close(State)
832	       end},
833
834     #{id   => 12,
835       desc => "Await nothing before stopping transport",
836       cmd  => fun(State) ->
837		       server_await_nothing(State, TO div 5)
838	       end},
839
840     #{id   => 13,
841       desc => "Stop",
842       cmd  => fun(State) ->
843		       server_stop_transport(State)
844	       end}
845
846    ].
847
848block_unblock_client_commands(Config, TO, ServerPort, ServerHost) ->
849    OwnPort = ServerPort+1,
850    Opts    = [{port, OwnPort}],
851    Self    = self(),
852    [
853     #{id   => 1,
854       desc => "Command sequence init",
855       cmd  => fun(State) ->
856		       {ok, State#{parent => Self}}
857	       end},
858
859     #{id   => 2,
860       desc => "Start transport",
861       cmd  => fun(State) ->
862		       client_start_transport(State)
863	       end},
864
865     #{id   => 3,
866       desc => "Open",
867       cmd  => fun(State) ->
868		       client_open(Config, State, Opts)
869	       end},
870
871     #{id   => 4,
872       desc => "Await continue",
873       cmd  => fun(State) ->
874		       client_await_continue_signal(State, TO)
875	       end},
876
877     #{id   => 5,
878       desc => "[pseudo] Connect",
879       cmd  => fun(State) ->
880		       client_connect(State, ServerHost, ServerPort)
881	       end},
882
883     #{id   => 6,
884       desc => "Send initial message (ping)",
885       cmd  => fun(State) ->
886		       client_send_message(State, "ping")
887	       end},
888
889     #{id   => 7,
890       desc => "Await reply (pong) to initial message",
891       cmd  => fun(State) ->
892		       client_await_message(State, "pong", TO div 5)
893	       end},
894
895     #{id   => 8,
896       desc => "Pre-Block info",
897       cmd  => fun(#{socket := Socket} = State) ->
898                       p("Socket Info: "
899                         "~n      Port Info: ~p", [inet:info(Socket)]),
900		       {ok, State}
901	       end},
902
903     #{id   => 9,
904       desc => "Block",
905       cmd  => fun(State) ->
906		       client_block(State)
907	       end},
908
909     #{id   => 10,
910       desc => "Post-Block info",
911       cmd  => fun(#{socket := Socket} = State) ->
912                       Active =
913                           case inet:getopts(Socket, [active]) of
914                               {ok, [{active, Act}]} ->
915                                   Act;
916                               _ ->
917                                   undefined
918                           end,
919                       p("Socket Info: "
920                         "~n      Active:    ~p"
921                         "~n      Port Info: ~p",
922                         [Active, inet:info(Socket)]),
923		       {ok, State}
924	       end},
925
926     #{id   => 11,
927       desc => "Notify blocked",
928       cmd  => fun(State) ->
929		       client_notify_blocked(State)
930	       end},
931
932     #{id   => 12,
933       desc => "Await nothing before unblocking",
934       cmd  => fun(#{socket := Socket} = State) ->
935                       Fail =
936                           fun(_) ->
937                                   Active =
938                                       case inet:getopts(Socket, [active]) of
939                                           {ok, [{active, Act}]} ->
940                                               Act;
941                                           _ ->
942                                               undefined
943                                       end,
944                                   p("Socket Info: "
945                                     "~n      Active:    ~p"
946                                     "~n      Port Info: ~p",
947                                     [Active, inet:info(Socket)]),
948                                   ok
949                           end,
950		       client_await_nothing(State, Fail, TO div 2)
951	       end},
952
953     #{id   => 13,
954       desc => "Pre-Unblock info",
955       cmd  => fun(#{socket := Socket} = State) ->
956                       Active =
957                           case inet:getopts(Socket, [active]) of
958                               {ok, [{active, Act}]} ->
959                                   Act;
960                               _ ->
961                                   undefined
962                           end,
963                       p("Socket Info: "
964                         "~n      Active:    ~p"
965                         "~n      Port Info: ~p",
966                         [Active, inet:info(Socket)]),
967		       {ok, State}
968	       end},
969
970     #{id   => 14,
971       desc => "Unblock",
972       cmd  => fun(State) ->
973		       client_unblock(State)
974	       end},
975
976     #{id   => 15,
977       desc => "Post-Unblock info",
978       cmd  => fun(#{socket := Socket} = State) ->
979                       Active =
980                           case inet:getopts(Socket, [active]) of
981                               {ok, [{active, Act}]} ->
982                                   Act;
983                               _ ->
984                                   undefined
985                           end,
986                       p("Socket Info: "
987                         "~n      Active:    ~p"
988                         "~n      Port Info: ~p",
989                         [Active, inet:info(Socket)]),
990		       {ok, State}
991	       end},
992
993     #{id   => 16,
994       desc => "Await message (hejsan)",
995       cmd  => fun(State) ->
996		       client_await_message(State, "hejsan", TO)
997	       end},
998
999     #{id   => 17,
1000       desc => "Send reply (hoppsan) to message",
1001       cmd  => fun(State) ->
1002		       client_send_message(State, "hoppsan")
1003	       end},
1004
1005     #{id   => 18,
1006       desc => "Await nothing before closing",
1007       cmd  => fun(State) ->
1008		       client_await_nothing(State, TO)
1009	       end},
1010
1011     #{id   => 19,
1012       desc => "Close",
1013       cmd  => fun(State) ->
1014		       client_close(State)
1015	       end},
1016
1017     #{id   => 20,
1018       desc => "Await nothing before stopping transport",
1019       cmd  => fun(State) ->
1020		       client_await_nothing(State, TO)
1021	       end},
1022
1023     #{id   => 21,
1024       desc => "Stop transport",
1025       cmd  => fun(State) ->
1026		       client_stop_transport(State)
1027	       end}
1028    ].
1029
1030
1031%% =================================================
1032%%
1033%% ------------------ errors ------------------------
1034%%
1035%% =================================================
1036
1037socket_failure(suite) ->
1038    [];
1039socket_failure(Config) when is_list(Config) ->
1040    ?ACQUIRE_NODES(1, Config),
1041    failing_socket().
1042
1043
1044%%======================================================================
1045%% Test functions
1046%%======================================================================
1047
1048start_case(Config, Opts, Expect) ->
1049    case (catch megaco_udp:start_transport()) of
1050	{ok, Pid} ->
1051	    case (catch ?OPEN(Config, Pid, Opts)) of
1052		{ok, _Handle, _CtrlPid} when Expect =:= ok ->
1053		    {ok, Pid};
1054		{ok, Handle, CtrlPid} ->
1055		    megaco_udp:stop_transport(Pid),
1056		    ?ERROR({unexpected_start_sucesss, Handle, CtrlPid});
1057		{error, _Reason} when Expect =:= error ->
1058		    megaco_udp:stop_transport(Pid),
1059		    ok;
1060		{error, Reason} ->
1061		    megaco_udp:stop_transport(Pid),
1062		    ?ERROR({unexpected_start_failure, Reason});
1063		Error ->
1064		    ?ERROR({unexpected_result, Error})
1065	    end;
1066	{error, Reason} ->
1067	    ?ERROR({failed_starting_transport, Reason})
1068    end.
1069
1070
1071failing_socket() ->
1072    ?SKIP(not_yet_implemented).
1073
1074
1075
1076%%----------------------------------------------------------------------
1077%% Message Callback functions
1078%%----------------------------------------------------------------------
1079
1080receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
1081  when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
1082    Msg = binary_to_list(BinMsg),
1083    ReceiveHandle ! {receive_message, {ControlPid, SendHandle, Msg}},
1084    ok.
1085
1086process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
1087  when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
1088    Msg = binary_to_list(BinMsg),
1089    ReceiveHandle ! {process_received_message, {ControlPid, SendHandle, Msg}},
1090    ok.
1091
1092
1093%%======================================================================
1094%% Internal functions
1095%%======================================================================
1096
1097%% -------  Server command handler and utility functions ----------
1098
1099server_start_command_handler(Node, Commands) ->
1100    start_command_handler(Node, Commands, #{}, "server").
1101
1102server_start_transport(State) when is_map(State) ->
1103    case (catch megaco_udp:start_transport()) of
1104	{ok, Ref} ->
1105            p("Transport started: ~p", [Ref]),
1106	    {ok, State#{transport_ref => Ref}};
1107	Error ->
1108	    Error
1109    end.
1110
1111server_open(Config, #{transport_ref := Ref} = State, Options)
1112  when is_list(Options) ->
1113    Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
1114    try ?OPEN(Config, Ref, Opts) of
1115	{ok, Socket, ControlPid} ->
1116            p("opened: "
1117              "~n      Socket:     ~p"
1118              "~n      ControlPid: ~p", [Socket, ControlPid]),
1119	    {ok, State#{handle      => {socket, Socket},  % Temporary
1120			control_pid => ControlPid}};
1121	{error, {could_not_open_udp_port, eaddrinuse}} ->
1122	    {skip, {server, eaddrinuse}};
1123	{error, _} = ERROR ->
1124	    ERROR
1125    catch
1126        C:E:S ->
1127            {error, {catched, C, E, S}}
1128    end.
1129
1130server_notify_operational(#{parent := Parent} = State) ->
1131    Parent ! {operational, self()},
1132    {ok, State}.
1133
1134server_await_continue_signal(#{parent := Parent} = State, Timeout) ->
1135    receive
1136	{continue, Parent} ->
1137            p("received expected continue signal"),
1138	    {ok, State};
1139        Any ->
1140            p("received UNEXPECTED message: "
1141              "~n   ~p", [Any]),
1142            {error, {unexpected, Any}}
1143    after Timeout ->
1144	    {error, timeout}
1145    end.
1146
1147server_await_initial_message(State, InitialMessage, Timeout)
1148  when is_map(State) ->
1149    receive
1150	{receive_message, {ControlPid, Handle, InitialMessage}} ->
1151	    p("received expected event with: "
1152	      "~n   ControlPid: ~p"
1153	      "~n   Handle:     ~p", [ControlPid, Handle]),
1154	    NewState = State#{handle => Handle},
1155	    {ok, NewState};
1156
1157	Any ->
1158	    p("received unexpected event: ~p", [Any]),
1159	    {error, {unexpected_event, Any}}
1160
1161    after Timeout ->
1162	    {error, timeout}
1163    end.
1164
1165server_send_message(#{handle := Handle} = State, Message) ->
1166    Bin = if
1167	      is_list(Message) ->
1168		  list_to_binary(Message);
1169	      true ->
1170		  Message
1171	  end,
1172    megaco_udp:send_message(Handle, Bin),
1173    {ok, State}.
1174
1175server_await_nothing(State, Timeout)
1176  when is_map(State) ->
1177    receive
1178	Any ->
1179	    p("received unexpected event: ~p", [Any]),
1180	    {error, {unexpected_event, Any}}
1181
1182    after Timeout ->
1183	    {ok, State}
1184    end.
1185
1186server_await_message(State, ExpectMessage, Timeout)
1187  when is_map(State) ->
1188    receive
1189	{receive_message, {_, _, ExpectMessage}} ->
1190	    p("received expected message [~p]", [ExpectMessage]),
1191	    {ok, State};
1192
1193	Any ->
1194	    p("received unexpected event: ~p", [Any]),
1195	    {error, {unexpected_event, Any}}
1196
1197    after Timeout ->
1198	    {error, timeout}
1199    end.
1200
1201server_close(#{handle := {socket, Socket}} = State) ->
1202    megaco_udp:close(Socket),
1203    {ok, State#{handle => undefined, control_pid => undefined}};
1204server_close(#{handle := Handle} = State)
1205  when (Handle =/= undefined) ->
1206    megaco_udp:close(Handle),
1207    {ok, State#{handle => undefined, control_pid => undefined}}.
1208
1209server_stop_transport(#{transport_ref := Ref} = State)
1210  when (Ref =/= undefined) ->
1211    megaco_udp:stop_transport(Ref),
1212    {ok, State#{transport_ref => undefined}}.
1213
1214
1215%% -------  Client command handler and utility functions ----------
1216
1217client_start_command_handler(Node, Commands) ->
1218    start_command_handler(Node, Commands, #{}, "client").
1219
1220client_start_transport(State) when is_map(State) ->
1221    case (catch megaco_udp:start_transport()) of
1222	{ok, Ref} ->
1223	    {ok, State#{transport_ref => Ref}};
1224	Error ->
1225	    Error
1226    end.
1227
1228client_open(Config, #{transport_ref := Ref} = State, Options)
1229  when is_list(Options) ->
1230    Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
1231    try ?OPEN(Config, Ref, Opts) of
1232	{ok, Socket, ControlPid} ->
1233	    {ok, State#{handle      => {socket, Socket},
1234                        socket      => Socket,
1235			control_pid => ControlPid}};
1236	{error, {could_not_open_udp_port, eaddrinuse}} ->
1237	    {skip, {client, eaddrinuse}};
1238	{error, _} = ERROR ->
1239	    ERROR
1240    catch
1241        C:E:S ->
1242            {error, {catched, C, E, S}}
1243    end.
1244
1245client_await_continue_signal(#{parent := Parent} = State, Timeout) ->
1246    receive
1247	{continue, Parent} ->
1248	    {ok, State}
1249    after Timeout ->
1250	    {error, timeout}
1251    end.
1252
1253client_notify_blocked(#{parent := Parent} = State) ->
1254    Parent ! {blocked, self()},
1255    {ok, State}.
1256
1257client_await_nothing(State, Timeout) ->
1258    client_await_nothing(State, fun(_) -> ok end, Timeout).
1259
1260client_await_nothing(State, Fail, Timeout)
1261  when is_map(State) andalso is_function(Fail, 1) ->
1262    receive
1263	Any ->
1264	    p("received unexpected event: ~p", [Any]),
1265            (catch Fail(Any)),
1266	    {error, {unexpected_event, Any}}
1267    after Timeout ->
1268	    {ok, State}
1269    end.
1270
1271client_connect(#{handle := {socket, Socket}} = State, Host, Port) ->
1272    Handle = megaco_udp:create_send_handle(Socket, Host, Port),
1273    {ok, State#{handle => Handle}}.
1274
1275client_send_message(#{handle := Handle} = State, Message) ->
1276    Bin = if
1277	      is_list(Message) ->
1278		  list_to_binary(Message);
1279	      true ->
1280		  Message
1281	  end,
1282    megaco_udp:send_message(Handle, Bin),
1283    {ok, State}.
1284
1285client_await_message(State, ExpectMessage, Timeout)
1286  when is_map(State) ->
1287    receive
1288	{receive_message, {_, _, ExpectMessage}} ->
1289	    {ok, State};
1290
1291	Any ->
1292	    p("received unexpected event: ~p", [Any]),
1293	    {error, {unexpected_event, Any}}
1294
1295    after Timeout ->
1296	    {error, timeout}
1297    end.
1298
1299client_block(#{handle := Handle} = State)
1300  when (Handle =/= undefined) ->
1301    ok = megaco_udp:block(Handle),
1302    {ok, State}.
1303
1304client_unblock(#{handle := Handle} = State)
1305  when (Handle =/= undefined) ->
1306    ok = megaco_udp:unblock(Handle),
1307    {ok, State}.
1308
1309client_close(#{handle := {socket, Socket}} = State) ->
1310    megaco_udp:close(Socket),
1311    {ok, State#{handle => undefined, control_pid => undefined}};
1312client_close(#{handle := Handle} = State)
1313  when (Handle =/= undefined) ->
1314    megaco_udp:close(Handle),
1315    {ok, State#{handle => undefined, control_pid => undefined}}.
1316
1317client_stop_transport(#{transport_ref := Ref} = State)
1318  when (Ref =/= undefined) ->
1319    megaco_udp:stop_transport(Ref),
1320    {ok, State#{transport_ref => undefined}}.
1321
1322
1323%% -------- Command handler interface ---------
1324
1325start_command_handler(Node, Commands, State, ShortName) ->
1326    ?CH:start(Node, Commands, State, ShortName).
1327
1328
1329await_command_handler_completion(Pids, Timeout) ->
1330    ?CH:await_completion(Pids, Timeout).
1331
1332
1333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334
1335try_tc(TCName, Pre, Case, Post) ->
1336    try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
1337
1338try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
1339    ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
1340
1341
1342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343
1344%% ------- Misc functions --------
1345
1346make_node_name(Name) ->
1347    case string:tokens(atom_to_list(node()), [$@]) of
1348        [_,Host] ->
1349            list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
1350        _ ->
1351            exit("Test node must be started with '-sname'")
1352    end.
1353
1354
1355to_calc(1 = _Factor, BaseTO) when is_integer(BaseTO) andalso (BaseTO > 0) ->
1356    BaseTO;
1357to_calc(Factor, BaseTO) when is_integer(Factor) andalso (Factor > 0) andalso
1358                             is_integer(BaseTO) andalso (BaseTO > 0) ->
1359    trunc( ((Factor + 1) / 2) * BaseTO ).
1360
1361
1362p(F) ->
1363    p(F, []).
1364
1365p(F, A) ->
1366    p(get(sname), F, A).
1367
1368p(S, F, A) when is_list(S) ->
1369    io:format("*** [~s] ~p ~s ***"
1370	      "~n   " ++ F ++ "~n",
1371	      [?FTS(), self(), S | A]);
1372p(_S, F, A) ->
1373    io:format("*** [~s] ~p *** "
1374	      "~n   " ++ F ++ "~n",
1375	      [?FTS(), self() | A]).
1376
1377
1378%% ms() ->
1379%%     erlang:monotonic_time(milli_seconds).
1380
1381
1382