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