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