1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2003-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: Implements an "MGC" used by the test suite 24%%---------------------------------------------------------------------- 25-module(megaco_test_mgc). 26 27-export([start/4, start/5, stop/1, 28 get_stats/2, reset_stats/1, 29 user_info/1, user_info/2, conn_info/1, conn_info/2, 30 update_user_info/3, update_conn_info/3, 31 request_ignore/1, 32 request_discard/1, request_discard/2, 33 request_pending/1, request_pending/2, request_pending_ignore/1, 34 request_handle/1, request_handle/2, 35 request_handle_pending/1, request_handle_pending/2, 36 request_handle_sloppy/1, request_handle_sloppy/2, 37 ack_info/2, abort_info/2, req_info/2, 38 disconnect/2, 39 verbosity/2]). 40-export([mgc/3]). 41 42%% Megaco callback api 43-export([ 44 handle_connect/3, 45 handle_disconnect/4, 46 handle_syntax_error/4, 47 handle_message_error/4, 48 handle_trans_request/4, 49 handle_trans_long_request/4, 50 handle_trans_reply/5, 51 handle_trans_ack/5, 52 handle_unexpected_trans/4, 53 handle_trans_request_abort/5 54 ]). 55 56-include("megaco_test_lib.hrl"). 57-include_lib("megaco/include/megaco.hrl"). 58-include_lib("megaco/include/megaco_message_v1.hrl"). 59 60-define(NO_ERROR, 'no error'). 61 62-define(A4444, ["11111111", "00000000", "00000000"]). 63-define(A4445, ["11111111", "00000000", "11111111"]). 64-define(A5555, ["11111111", "11111111", "00000000"]). 65-define(A5556, ["11111111", "11111111", "11111111"]). 66 67-define(valid_actions, 68 [ignore, pending, pending_ignore, discard_ack, handle_ack, handle_pending_ack, handle_sloppy_ack]). 69 70-record(mgc, {parent = undefined, 71 inet_backend = default, 72 tcp_sup = undefined, 73 udp_sup = undefined, 74 req_action = discard_ack, 75 req_timeout = 0, 76 mid = undefined, 77 ack_info = undefined, 78 abort_info = undefined, 79 req_info = undefined, 80 mg = [], 81 dsi_timer, 82 evs = []}). 83 84-define(EVS_MAX, 10). 85 86 87%%% ------------------------------------------------------------------ 88 89start(Node, Mid, ET, Verbosity) -> 90 %% Conf = [{megaco_trace, io}], 91 %% Conf = [{megaco_trace, "megaco-mgc.trace"}], 92 Conf = [{megaco_trace, false}], 93 start(Node, Mid, ET, Conf, Verbosity). 94 95start(Node, Mid, ET, Conf, Verbosity) -> 96 d("start mgc[~p]: ~p" 97 "~n ET: ~p" 98 "~n Conf: ~p", [Node, Mid, ET, Conf]), 99 RI = {receive_info, mk_recv_info(ET)}, 100 Config = [{local_mid, Mid}, RI] ++ Conf, 101 Self = self(), 102 true = erlang:monitor_node(Node, true), 103 MGC = fun() -> mgc(Self, Verbosity, Config) end, 104 {Pid, MRef} = spawn_monitor(Node, MGC), 105 NodePing = net_adm:ping(Node), 106 ProcInfo = (catch proc_info(Pid)), 107 i("start mgc[~p] -> ~p" 108 "~n self(): ~p" 109 "~n node(): ~p" 110 "~n Node ping: ~p" 111 "~n Loader: ~p" 112 "~n Monitor ref: ~p" 113 "~n Process info: ~p", 114 [Node, Pid, 115 Self, node(), NodePing, Pid, MRef, ProcInfo]), 116 await_started(Node, Pid, MRef). 117 118proc_info(Pid) -> 119 rpc:call(node(Pid), erlang, process_info, [Pid]). 120 121mk_recv_info(ET) -> 122 mk_recv_info(ET, []). 123 124mk_recv_info([], Acc) -> 125 Acc; 126mk_recv_info([{Encoding, Transport}|ET], Acc) 127 when is_atom(Encoding) andalso is_atom(Transport) -> 128 {EMod, Port} = select_encoding(Encoding), 129 TMod = select_transport(Transport), 130 RI = [{encoding_module, EMod}, 131 {encoding_config, []}, 132 {transport_module, TMod}, 133 {port, Port}], 134 mk_recv_info(ET, [RI|Acc]); 135mk_recv_info([{Encoding, Transport, TO}|ET], Acc) 136 when is_atom(Encoding) andalso is_atom(Transport) andalso is_list(TO) -> 137 {EMod, Port} = select_encoding(Encoding), 138 TMod = select_transport(Transport), 139 RI = [{encoding_module, EMod}, 140 {encoding_config, []}, 141 {transport_module, TMod}, 142 {port, Port}, 143 {transport_opts, TO}], 144 mk_recv_info(ET, [RI|Acc]); 145mk_recv_info([{Encoding, EC, Transport}|ET], Acc) 146 when is_atom(Encoding) andalso is_list(EC) andalso is_atom(Transport) -> 147 {EMod, Port} = select_encoding(Encoding), 148 TMod = select_transport(Transport), 149 RI = [{encoding_module, EMod}, 150 {encoding_config, EC}, 151 {transport_module, TMod}, 152 {port, Port}], 153 mk_recv_info(ET, [RI|Acc]); 154mk_recv_info([ET|_], _) -> 155 throw({error, {invalid_encoding_transport, ET}}). 156 157select_encoding(text) -> 158 {megaco_pretty_text_encoder, 2944}; 159select_encoding(pretty_text) -> 160 {megaco_pretty_text_encoder, 2944}; 161select_encoding(compact_text) -> 162 {megaco_compact_text_encoder, 2944}; 163select_encoding(binary) -> 164 {megaco_ber_encoder, 2945}; 165select_encoding(erl_dist) -> 166 {megaco_erl_dist_encoder, 2946}; 167select_encoding(Encoding) -> 168 throw({error, {invalid_encoding, Encoding}}). 169 170select_transport(tcp) -> 171 megaco_tcp; 172select_transport(udp) -> 173 megaco_udp; 174select_transport(Transport) -> 175 throw({error, {invalid_transport, Transport}}). 176 177 178await_started(Node, Pid, MRef) -> 179 receive 180 {started, Pid} -> 181 i("await_started ~p: ok", [Pid]), 182 true = erlang:monitor_node(Node, false), 183 erlang:demonitor(MRef), 184 {ok, Pid}; 185 186 {nodedown, Node} -> 187 i("await_started ~p - received node down", [Pid]), 188 exit({node_down, Node}); 189 190 {'DOWN', MRef, process, Pid, 191 {failed_starting_tcp_listen, 192 {could_not_start_listener, {gen_tcp_listen, eaddrinuse}}}} -> 193 e("await_started ~p: address already in use", [Pid]), 194 true = erlang:monitor_node(Node, false), 195 ?SKIP(eaddrinuse); 196 197 {'DOWN', MRef, process, Pid, Reason} -> 198 e("await_started ~p: received exit signal: ~p", [Pid, Reason]), 199 true = erlang:monitor_node(Node, false), 200 exit({failed_starting, Pid, Reason}) 201 202 after 10000 -> 203 NodePing = net_adm:ping(Node), 204 ProcInfo = (catch proc_info(Pid)), 205 FlushQ = megaco_test_lib:flush(), 206 e("await_started ~p - timeout: " 207 "~n net_adm:ping(~p): ~p" 208 "~n Process info: ~p" 209 "~n Messages in my queue: ~p", 210 [Pid, Node, NodePing, ProcInfo, FlushQ]), 211 true = erlang:monitor_node(Node, false), 212 exit({error, timeout}) 213 end. 214 215 216stop(Pid) -> 217 server_request(Pid, stop, stopped). 218 219get_stats(Pid, No) -> 220 server_request(Pid, {statistics, No}, {statistics_reply, No}). 221 222reset_stats(Pid) -> 223 server_request(Pid, reset_stats, reset_stats_ack). 224 225user_info(Pid) -> 226 server_request(Pid, {user_info, all}, user_info_ack). 227 228user_info(Pid, Tag) -> 229 server_request(Pid, {user_info, Tag}, user_info_ack). 230 231conn_info(Pid) -> 232 server_request(Pid, {conn_info, all}, conn_info_ack). 233 234conn_info(Pid, Tag) -> 235 server_request(Pid, {conn_info, Tag}, conn_info_ack). 236 237update_user_info(Pid, Tag, Val) -> 238 server_request(Pid, {update_user_info, Tag, Val}, update_user_info_ack). 239 240update_conn_info(Pid, Tag, Val) -> 241 server_request(Pid, {update_conn_info, Tag, Val}, update_conn_info_ack). 242 243disconnect(Pid, Reason) -> 244 server_request(Pid, {disconnect, Reason}, disconnected). 245 246ack_info(Pid, InfoPid) -> 247 Pid ! {ack_info, InfoPid, self()}. 248 249abort_info(Pid, InfoPid) -> 250 Pid ! {abort_info, InfoPid, self()}. 251 252req_info(Pid, InfoPid) -> 253 Pid ! {req_info, InfoPid, self()}. 254 255verbosity(Pid, V) -> 256 Pid ! {verbosity, V, self()}. 257 258request_ignore(Pid) -> 259 request_action(Pid, {ignore, infinity}). 260 261request_pending_ignore(Pid) -> 262 request_action(Pid, {pending_ignore, infinity}). 263 264request_discard(Pid) -> 265 request_discard(Pid,0). 266 267request_discard(Pid, To) -> 268 request_action(Pid, {discard_ack, To}). 269 270request_pending(Pid) -> 271 request_pending(Pid, 5000). 272 273request_pending(Pid, To) -> 274 request_action(Pid, {pending, To}). 275 276request_handle(Pid) -> 277 request_handle(Pid, 0). 278 279request_handle(Pid, To) -> 280 request_action(Pid, {handle_ack, To}). 281 282request_handle_pending(Pid) -> 283 request_handle_pending(Pid, 0). 284 285request_handle_pending(Pid, To) -> 286 request_action(Pid, {handle_pending_ack, To}). 287 288request_handle_sloppy(Pid) -> 289 request_handle_sloppy(Pid, 0). 290 291request_handle_sloppy(Pid, To) -> 292 request_action(Pid, {handle_sloppy_ack, To}). 293 294request_action(Pid, Action) -> 295 server_request(Pid, request_action, Action, request_action_ack). 296 297 298server_request(Pid, Req, ReplyTag) -> 299 Pid ! {Req, self()}, 300 receive 301 {ReplyTag, Reply, Pid} -> 302 Reply; 303 {'EXIT', Pid, Reason} -> 304 exit({failed, Req, Pid, Reason}) 305 after 10000 -> 306 exit({timeout, Req, Pid}) 307 end. 308 309server_request(Pid, Req, ReqData, ReplyTag) -> 310 Pid ! {Req, ReqData, self()}, 311 receive 312 {ReplyTag, Reply, Pid} -> 313 Reply; 314 {'EXIT', Pid, Reason} -> 315 exit({failed, Req, Pid, Reason}) 316 after 10000 -> 317 exit({timeout, Req, Pid}) 318 end. 319 320 321server_reply(Pid, ReplyTag, Reply) -> 322 Pid ! {ReplyTag, Reply, self()}. 323 324 325%%% ------------------------------------------------------------------ 326 327 328mgc(Parent, Verbosity, Config) -> 329 process_flag(trap_exit, true), 330 put(verbosity, Verbosity), 331 put(sname, "MGC"), 332 i("mgc -> starting"), 333 case (catch init(Config)) of 334 {error, Reason} -> 335 exit(Reason); 336 {IB, Mid, TcpSup, UdpSup, DSITimer} -> 337 notify_started(Parent), 338 S = #mgc{parent = Parent, 339 tcp_sup = TcpSup, 340 udp_sup = UdpSup, 341 mid = Mid, 342 dsi_timer = DSITimer, 343 inet_backend = IB}, 344 i("mgc -> started"), 345 display_system_info("at start "), 346 loop(evs(S, started)) 347 end. 348 349init(Config) -> 350 d("init -> entry"), 351 random_init(), 352 353 IB = get_conf(inet_backend, Config, default), 354 Mid = get_conf(local_mid, Config), 355 RI = get_conf(receive_info, Config), 356 357 d("init -> " 358 "~n Inet Backend: ~p" 359 "~n Mid: ~p" 360 "~n RI: ~p", [IB, Mid, RI]), 361 DSITimer = 362 case get_conf(display_system_info, Config, undefined) of 363 Time when is_integer(Time) -> 364 d("init -> creating display system info timer"), 365 create_timer(Time, display_system_info); 366 _ -> 367 undefined 368 end, 369 Conf0 = lists:keydelete(display_system_info, 1, Config), 370 Conf1 = lists:keydelete(inet_backend, 1, Conf0), 371 372 d("init -> start megaco"), 373 application:start(megaco), 374 375 d("init -> possibly enable megaco trace"), 376 case lists:keysearch(megaco_trace, 1, Config) of 377 {value, {megaco_trace, true}} -> 378 megaco:enable_trace(max, io); 379 {value, {megaco_trace, io}} -> 380 megaco:enable_trace(max, io); 381 {value, {megaco_trace, File}} when is_list(File) -> 382 megaco:enable_trace(max, File); 383 _ -> 384 ok 385 end, 386 Conf2 = lists:keydelete(megaco_trace, 1, Conf1), 387 388 d("init -> start megaco user"), 389 Conf3 = lists:keydelete(local_mid, 1, Conf2), 390 Conf4 = lists:keydelete(receive_info, 1, Conf3), 391 ok = megaco:start_user(Mid, Conf4), 392 393 d("init -> update user info (user_mod)"), 394 ok = megaco:update_user_info(Mid, user_mod, ?MODULE), 395 396 d("init -> update user info (user_args)"), 397 ok = megaco:update_user_info(Mid, user_args, [self()]), 398 399 d("init -> get user info (receive_handle)"), 400 RH = megaco:user_info(Mid,receive_handle), 401 d("init -> parse receive info"), 402 Transports = parse_receive_info(RI, RH), 403 404 d("init -> start transports"), 405 {Tcp, Udp} = start_transports(IB, Transports), 406 {IB, Mid, Tcp, Udp, DSITimer}. 407 408loop(S) -> 409 d("loop -> await request"), 410 receive 411 {display_system_info, Time} -> 412 display_system_info(S#mgc.mid), 413 NewTimer = create_timer(Time, display_system_info), 414 loop(evs(S#mgc{dsi_timer = NewTimer}, {dsi, Time})); 415 416 {stop, Parent} when S#mgc.parent =:= Parent -> 417 i("loop -> stopping"), 418 display_system_info(S#mgc.mid, "at finish "), 419 cancel_timer(S#mgc.dsi_timer), 420 Mid = S#mgc.mid, 421 (catch close_conns(Mid)), 422 megaco:stop_user(Mid), 423 application:stop(megaco), 424 i("loop -> stopped"), 425 server_reply(Parent, stopped, ok), 426 done(evs(S, stop), normal); 427 428 {{disconnect, Reason}, Parent} when S#mgc.parent == Parent -> 429 i("loop -> disconnecting"), 430 Mid = S#mgc.mid, 431 [Conn|_] = megaco:user_info(Mid, connections), 432 Res = megaco:disconnect(Conn, {self(), Reason}), 433 server_reply(Parent, disconnected, Res), 434 loop(evs(S, {disconnect, Reason})); 435 436 {{update_user_info, Tag, Val}, Parent} when S#mgc.parent == Parent -> 437 i("loop -> got update_user_info: ~w -> ~p", [Tag, Val]), 438 Res = (catch megaco:update_user_info(S#mgc.mid, Tag, Val)), 439 d("loop -> Res: ~p", [Res]), 440 server_reply(Parent, update_user_info_ack, Res), 441 loop(evs(S, {uui, {Tag, Val}})); 442 443 {{user_info, Tag}, Parent} when S#mgc.parent == Parent -> 444 i("loop -> got user_info request for ~w", [Tag]), 445 Res = (catch megaco:user_info(S#mgc.mid, Tag)), 446 d("loop -> Res: ~p", [Res]), 447 server_reply(Parent, user_info_ack, Res), 448 loop(evs(S, {ui, Tag})); 449 450 {{update_conn_info, Tag, Val}, Parent} when S#mgc.parent == Parent -> 451 i("loop -> got update_conn_info: ~w -> ~p", [Tag, Val]), 452 Conns = megaco:user_info(S#mgc.mid, connections), 453 Fun = fun(CH) -> 454 (catch megaco:update_conn_info(CH, Tag, Val)) 455 end, 456 Res = lists:map(Fun, Conns), 457 d("loop -> Res: ~p", [Res]), 458 server_reply(Parent, update_conn_info_ack, Res), 459 loop(evs(S, {uci, {Tag, Val}})); 460 461 {{conn_info, Tag}, Parent} when S#mgc.parent =:= Parent -> 462 i("loop -> got conn_info request for ~w", [Tag]), 463 Conns = megaco:user_info(S#mgc.mid, connections), 464 Fun = fun(CH) -> 465 {CH, (catch megaco:conn_info(CH, Tag))} 466 end, 467 Res = lists:map(Fun, Conns), 468 d("loop -> Res: ~p", [Res]), 469 server_reply(Parent, conn_info_ack, Res), 470 loop(evs(S, {ci, Tag})); 471 472 473 %% 474 {request_action, {Action, To}, Parent} when S#mgc.parent == Parent -> 475 i("loop -> got new request_action: ~p:~w", [Action,To]), 476 {Reply, S1} = 477 case lists:member(Action, ?valid_actions) of 478 true when To >= 0; To == infinity -> 479 {{ok, S#mgc.req_action}, 480 S#mgc{req_action = Action, req_timeout = To}}; 481 true -> 482 {{error, {invalid_action_timeout, To}}, S}; 483 false -> 484 {{error, {invalid_action, Action}}, S} 485 end, 486 server_reply(Parent, request_action_ack, Reply), 487 loop(evs(S1, {req_act, {Action, To}})); 488 489 490 %% Reset stats 491 {reset_stats, Parent} when S#mgc.parent == Parent -> 492 i("loop -> got request to reset stats counters"), 493 do_reset_stats(S#mgc.mid), 494 server_reply(Parent, reset_stats_ack, ok), 495 loop(evs(S, rst_stats)); 496 497 498 %% Give me statistics 499 {{statistics, 1}, Parent} when S#mgc.parent == Parent -> 500 i("loop(stats1) -> got request for statistics 1"), 501 {ok, Gen} = megaco:get_stats(), 502 i("loop(stats1) -> gen stats: " 503 "~n ~p", [Gen]), 504 GetTrans = 505 fun(CH) -> 506 i("loop(stats1):GetTrans -> " 507 "get stats for connection ~p", [CH]), 508 Reason = {statistics, CH}, 509 Pid = megaco:conn_info(CH, control_pid), 510 i("loop(stats1):GetTrans -> control pid: ~p", [Pid]), 511 SendMod = megaco:conn_info(CH, send_mod), 512 i("loop(stats1):GetTrans -> " 513 "send module: ~p", [SendMod]), 514 SendHandle = megaco:conn_info(CH, send_handle), 515 i("loop(stats1):GetTrans -> " 516 "send handle: ~p", [SendHandle]), 517 {ok, Stats} = 518 case SendMod of 519 megaco_tcp -> megaco_tcp:get_stats(SendHandle); 520 megaco_udp -> megaco_udp:get_stats(SendHandle); 521 SendMod -> exit(Pid, Reason) 522 end, 523 i("loop(stats1):GetTrans -> stats: " 524 "~n ~p", [Stats]), 525 {SendHandle, Stats} 526 end, 527 Mid = S#mgc.mid, 528 Trans = lists:map(GetTrans, megaco:user_info(Mid, connections)), 529 Reply = {ok, [{gen, Gen}, {trans, Trans}]}, 530 i("loop(stats1) -> send reply"), 531 server_reply(Parent, {statistics_reply, 1}, Reply), 532 i("loop(stats1) -> done"), 533 loop(evs(S, {stats, 1})); 534 535 536 {{statistics, 2}, Parent} when S#mgc.parent == Parent -> 537 i("loop(stats2) -> got request for statistics 2"), 538 {ok, Gen} = megaco:get_stats(), 539 #mgc{tcp_sup = TcpSup, udp_sup = UdpSup} = S, 540 TcpStats = get_trans_stats(TcpSup, megaco_tcp), 541 UdpStats = get_trans_stats(UdpSup, megaco_udp), 542 Reply = {ok, [{gen, Gen}, {trans, [TcpStats, UdpStats]}]}, 543 i("loop(stats2) -> send reply"), 544 server_reply(Parent, {statistics_reply, 2}, Reply), 545 i("loop(stats2) -> done"), 546 loop(evs(S, {stats, 2})); 547 548 549 %% Megaco callback messages 550 {request, Request, From} -> 551 d("loop(request) -> received megaco request from ~p:" 552 "~n ~p", [From, Request]), 553 {Reply, S1} = handle_megaco_request(Request, S), 554 d("loop(request) -> send reply: ~n~p", [Reply]), 555 reply(From, Reply), 556 d("loop(request) -> done"), 557 loop(evs(S1, {req, Request})); 558 559 560 {ack_info, To, Parent} when S#mgc.parent == Parent -> 561 i("loop -> received request to inform about received ack's "), 562 loop(evs(S#mgc{ack_info = To}, {acki, To})); 563 564 565 {abort_info, To, Parent} when S#mgc.parent == Parent -> 566 i("loop -> received request to inform about received aborts "), 567 loop(evs(S#mgc{abort_info = To}, {abi, To})); 568 569 570 {req_info, To, Parent} when S#mgc.parent == Parent -> 571 i("loop -> received request to inform about received req's "), 572 loop(evs(S#mgc{req_info = To}, {reqi, To})); 573 574 575 {verbosity, V, Parent} when S#mgc.parent == Parent -> 576 i("loop -> received new verbosity: ~p", [V]), 577 put(verbosity,V), 578 loop(evs(S, {verb, V})); 579 580 581 {'EXIT', Pid, Reason} when S#mgc.tcp_sup =:= Pid -> 582 error_msg("MGC received unexpected exit " 583 "from TCP transport supervisor (~p):" 584 "~n ~p", [Pid, Reason]), 585 i("loop -> [tcp] exiting"), 586 display_system_info(S#mgc.mid, "at bad finish (tcp) "), 587 cancel_timer(S#mgc.dsi_timer), 588 Mid = S#mgc.mid, 589 (catch close_conns(Mid)), 590 megaco:stop_user(Mid), 591 application:stop(megaco), 592 i("loop -> stopped"), 593 StopReason = {error, {tcp_terminated, Pid, Reason}}, 594 server_reply(S#mgc.parent, stopped, StopReason), 595 done(evs(S, {tcp_sup_exit, Reason}), StopReason); 596 597 598 {'EXIT', Pid, Reason} when S#mgc.udp_sup =:= Pid -> 599 error_msg("MGC received unexpected exit " 600 "from UDP transport supervisor (~p):" 601 "~n ~p", [Pid, Reason]), 602 i("loop -> [udp] exiting"), 603 display_system_info(S#mgc.mid, "at bad finish (udp) "), 604 cancel_timer(S#mgc.dsi_timer), 605 Mid = S#mgc.mid, 606 (catch close_conns(Mid)), 607 megaco:stop_user(Mid), 608 application:stop(megaco), 609 i("loop -> stopped"), 610 StopReason = {error, {udp_terminated, Pid, Reason}}, 611 server_reply(S#mgc.parent, stopped, StopReason), 612 done(evs(S, {udp_sup_exit, Reason}), StopReason); 613 614 615 Invalid -> 616 i("loop -> received invalid request: ~p", [Invalid]), 617 loop(evs(S, {invalid, Invalid})) 618 end. 619 620 621evs(#mgc{evs = EVS} = S, Ev) when (length(EVS) < ?EVS_MAX) -> 622 echo_evs(S#mgc{evs = [{?FTS(), Ev}|EVS]}); 623evs(#mgc{evs = EVS} = S, Ev) -> 624 echo_evs(S#mgc{evs = [{?FTS(), Ev}|lists:droplast(EVS)]}). 625 626echo_evs(#mgc{evs = EVS} = S) -> 627 i("Events: " 628 "~n ~p", [EVS]), 629 S. 630 631done(#mgc{evs = EVS}, Reason) -> 632 info_msg("Exiting with latest event(s): " 633 "~n ~p" 634 "~n", [EVS]), 635 exit(Reason). 636 637 638do_reset_stats(Mid) -> 639 megaco:reset_stats(), 640 do_reset_trans_stats(megaco:user_info(Mid, connections), []). 641 642do_reset_trans_stats([], _Reset) -> 643 ok; 644do_reset_trans_stats([CH|CHs], Reset) -> 645 SendMod = megaco:conn_info(CH, send_mod), 646 case lists:member(SendMod, Reset) of 647 true -> 648 do_reset_trans_stats(CHs, Reset); 649 false -> 650 SendMod:reset_stats(), 651 do_reset_trans_stats(CHs, [SendMod|Reset]) 652 end. 653 654 655close_conns(Mid) -> 656 Reason = {self(), ignore}, 657 Disco = fun(CH) -> 658 (catch do_close_conn(CH, Reason)) 659 end, 660 lists:map(Disco, megaco:user_info(Mid, connections)). 661 662do_close_conn(CH, Reason) -> 663 d("close connection to ~p", [CH#megaco_conn_handle.remote_mid]), 664 Pid = megaco:conn_info(CH, control_pid), 665 SendMod = megaco:conn_info(CH, send_mod), 666 SendHandle = megaco:conn_info(CH, send_handle), 667 megaco:disconnect(CH, Reason), 668 case SendMod of 669 megaco_tcp -> megaco_tcp:close(SendHandle); 670 megaco_udp -> megaco_udp:close(SendHandle); 671 SendMod -> exit(Pid, Reason) 672 end. 673 674get_trans_stats(P, SendMod) when is_pid(P) -> 675 case (catch SendMod:get_stats()) of 676 {ok, Stats} -> 677 {SendMod, Stats}; 678 Else -> 679 {SendMod, Else} 680 end; 681get_trans_stats(_P, SendMod) -> 682 {SendMod, undefined}. 683 684parse_receive_info([], _RH) -> 685 throw({error, no_receive_info}); 686parse_receive_info(RI, RH) -> 687 parse_receive_info(RI, RH, []). 688 689parse_receive_info([], _RH, Transports) -> 690 d("parse_receive_info -> done when" 691 "~n Transports: ~p", [Transports]), 692 Transports; 693parse_receive_info([RI|RIs], RH, Transports) -> 694 d("parse_receive_info -> parse receive info"), 695 case (catch parse_receive_info1(RI, RH)) of 696 {error, Reason} -> 697 e("failed parsing receive info: ~p~n~p", [RI, Reason]), 698 exit({failed_parsing_recv_info, RI, Reason}); 699 RH1 -> 700 parse_receive_info(RIs, RH, [RH1|Transports]) 701 end. 702 703parse_receive_info1(RI, RH) -> 704 d("parse_receive_info1 -> get encoding module"), 705 EM = get_encoding_module(RI), 706 d("parse_receive_info1 -> get encoding config"), 707 EC = get_encoding_config(RI, EM), 708 d("parse_receive_info1 -> get transport module"), 709 TM = get_transport_module(RI), 710 d("parse_receive_info1 -> get transport port"), 711 TP = get_transport_port(RI), 712 d("parse_receive_info1 -> get transport opts"), 713 TO = get_transport_opts(RI), 714 RH1 = RH#megaco_receive_handle{send_mod = TM, 715 encoding_mod = EM, 716 encoding_config = EC}, 717 d("parse_receive_info1 -> " 718 "~n Transport Opts: ~p" 719 "~n Port: ~p" 720 "~n Receive handle: ~p", [TO, TP, RH1]), 721 {TO, TP, RH1}. 722 723 724 725%% -------------------------------------------------------- 726%% On some platforms there seem to take some time before 727%% a port is released by the OS (after having been used, 728%% as is often the case in the test suites). 729%% So, starting the transports is done in two steps. 730%% First) Start the actual transport(s) 731%% Second) Create the listener (tcp) or open the 732%% send/receive port (udp). 733%% The second step *may* need to be repeated! 734%% -------------------------------------------------------- 735start_transports(_, []) -> 736 throw({error, no_transport}); 737start_transports(IB, Transports) when is_list(Transports) -> 738 {Tcp, Udp} = start_transports1(Transports, undefined, undefined), 739 ok = start_transports2(IB, Transports, Tcp, Udp), 740 {Tcp, Udp}. 741 742start_transports1([], Tcp, Udp) -> 743 {Tcp, Udp}; 744start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp) 745 when ((RH#megaco_receive_handle.send_mod =:= megaco_tcp) andalso 746 (not is_pid(Tcp))) -> 747 d("try start tcp transport service"), 748 case megaco_tcp:start_transport() of 749 {ok, Sup} -> 750 d("tcp transport service started: ~p", [Sup]), 751 start_transports1(Transports, Sup, Udp); 752 Else -> 753 e("Failed starting TCP transport service:" 754 "~n ~p", [Else]), 755 throw({error, {failed_starting_tcp_transport, Else}}) 756 end; 757start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp) 758 when ((RH#megaco_receive_handle.send_mod =:= megaco_udp) andalso 759 (not is_pid(Udp))) -> 760 d("try start udp transport servuice"), 761 case megaco_udp:start_transport() of 762 {ok, Sup} -> 763 d("udp transport started: ~p", [Sup]), 764 start_transports1(Transports, Tcp, Sup); 765 Else -> 766 e("Failed starting UDP transport service:" 767 "~n ~p", [Else]), 768 throw({error, {failed_starting_udp_transport, Else}}) 769 end; 770start_transports1([_|Transports], Tcp, Udp) -> 771 start_transports1(Transports, Tcp, Udp). 772 773start_transports2(_, [], _, _) -> 774 ok; 775start_transports2(IB, [{TO, Port, RH}|Transports], Tcp, Udp) 776 when RH#megaco_receive_handle.send_mod =:= megaco_tcp -> 777 start_tcp(IB, TO, RH, Port, Tcp), 778 start_transports2(IB, Transports, Tcp, Udp); 779start_transports2(IB, [{TO, Port, RH}|Transports], Tcp, Udp) 780 when RH#megaco_receive_handle.send_mod =:= megaco_udp -> 781 start_udp(IB, TO, RH, Port, Udp), 782 start_transports2(IB, Transports, Tcp, Udp). 783 784start_tcp(IB, TO, RH, Port, Sup) -> 785 d("start tcp transport"), 786 start_tcp(IB, TO, RH, Port, Sup, 250). 787 788start_tcp(IB, TO, RH, Port, Sup, Timeout) 789 when is_pid(Sup) andalso is_integer(Timeout) andalso (Timeout > 0) -> 790 d("tcp listen on ~p", [Port]), 791 Opts = [{inet_backend, IB}, 792 {port, Port}, 793 {receive_handle, RH}, 794 {tcp_options, [{nodelay, true}]}] ++ TO, 795 try_start_tcp(Sup, Opts, Timeout, ?NO_ERROR). 796 797try_start_tcp(Sup, Opts, Timeout, Error0) when (Timeout < 5000) -> 798 Sleep = random(Timeout) + 100, 799 d("try create tcp listen socket (~p,~p)", [Timeout, Sleep]), 800 case megaco_tcp:listen(Sup, Opts) of 801 ok -> 802 d("listen socket created", []), 803 Sup; 804 Error1 when Error0 =:= ?NO_ERROR -> % Keep the first error 805 d("failed creating listen socket [1]: ~p", [Error1]), 806 sleep(Sleep), 807 try_start_tcp(Sup, Opts, Timeout*2, Error1); 808 Error2 -> 809 d("failed creating listen socket [2]: ~p", [Error2]), 810 sleep(Sleep), 811 try_start_tcp(Sup, Opts, Timeout*2, Error0) 812 end; 813try_start_tcp(Sup, _Opts, _Timeout, Error) -> 814 megaco_tcp:stop_transport(Sup), 815 case Error of 816 {error, Reason} -> 817 throw({error, {failed_starting_tcp_listen, Reason}}); 818 _ -> 819 throw({error, {failed_starting_tcp_listen, Error}}) 820 end. 821 822 823start_udp(IB, TO, RH, Port, Sup) -> 824 d("start udp transport"), 825 start_udp(IB, TO, RH, Port, Sup, 250). 826 827start_udp(IB, TO, RH, Port, Sup, Timeout) -> 828 d("udp open ~p", [Port]), 829 Opts = [{inet_backend, IB}, 830 {port, Port}, 831 {receive_handle, RH}] ++ TO, 832 try_start_udp(Sup, Opts, Timeout, ?NO_ERROR). 833 834try_start_udp(Sup, Opts, Timeout, Error0) when (Timeout < 5000) -> 835 d("try open udp socket (~p)", [Timeout]), 836 case megaco_udp:open(Sup, Opts) of 837 {ok, _SendHandle, _ControlPid} -> 838 d("port opened", []), 839 Sup; 840 Error1 when Error0 =:= ?NO_ERROR -> % Keep the first error 841 d("failed open port [1]: ~p", [Error1]), 842 sleep(Timeout), 843 try_start_udp(Sup, Opts, Timeout*2, Error1); 844 Error2 -> 845 d("failed open port [2]: ~p", [Error2]), 846 sleep(Timeout), 847 try_start_udp(Sup, Opts, Timeout*2, Error0) 848 end; 849try_start_udp(Sup, _Opts, _Timeout, Error) -> 850 megaco_udp:stop_transport(Sup), 851 throw({error, {failed_starting_udp_open, Error}}). 852 853 854%% ----------------------- 855%% Handle megaco callbacks 856%% 857 858handle_megaco_request({handle_connect, CH, _PV}, #mgc{mg = MGs} = S) -> 859 case lists:member(CH, MGs) of 860 true -> 861 i("MG already connected: ~n ~p", [CH]), 862 {error, S}; 863 false -> 864 {ok, S#mgc{mg = [CH|MGs]}} 865 end; 866 867handle_megaco_request({handle_disconnect, CH, _PV, R}, S) -> 868 d("handle_megaco_request(handle_disconnect) -> entry with" 869 "~n CH: ~p" 870 "~n R: ~p", [CH, R]), 871 CancelRes = (catch megaco:cancel(CH, R)), % Cancel the outstanding messages 872 d("handle_megaco_request(handle_disconnect) -> megaco cancel result: ~p", [CancelRes]), 873 MGs = lists:delete(CH, S#mgc.mg), 874 d("handle_megaco_request(handle_disconnect) -> MGs: ~p", [MGs]), 875 {ok, S#mgc{mg = MGs}}; 876 877handle_megaco_request({handle_syntax_error, _RH, _PV, _ED}, S) -> 878 {reply, S}; 879 880handle_megaco_request({handle_message_error, _CH, _PV, _ED}, S) -> 881 {no_reply, S}; 882 883handle_megaco_request({handle_trans_request, CH, PV, ARs}, 884 #mgc{req_info = P} = S) when is_pid(P) -> 885 d("handle_megaco_request(handle_trans_request,~p) -> entry", [P]), 886 P ! {req_received, self(), ARs}, 887 do_handle_trans_request(CH, PV, ARs, S); 888handle_megaco_request({handle_trans_request, CH, PV, ARs}, S) -> 889 d("handle_megaco_request(handle_trans_request) -> entry"), 890 do_handle_trans_request(CH, PV, ARs, S); 891 892handle_megaco_request({handle_trans_long_request, CH, PV, RD}, S) -> 893 d("handle_megaco_request(handle_long_trans_request) -> entry"), 894 Reply0 = handle_act_requests(CH, PV, RD, discard_ack), 895 Reply = 896 case S of 897 #mgc{req_action = ignore, req_timeout = To} -> 898 d("handle_megaco_request(handle_long_trans_request) -> " 899 "~n To: ~p", [To]), 900 {delay_reply, To, Reply0}; 901 _ -> 902 d("handle_megaco_request(handle_long_trans_request) -> " 903 "~n S: ~p", [S]), 904 Reply0 905 end, 906 {Reply, S}; 907 908handle_megaco_request({handle_trans_reply, _CH, _PV, _AR, _RD}, S) -> 909 {ok, S}; 910 911handle_megaco_request({handle_trans_ack, CH, PV, AS, AD}, 912 #mgc{ack_info = P} = S) when is_pid(P) -> 913 d("handle_megaco_request(handle_trans_ack,~p) -> entry when" 914 "~n CH: ~p" 915 "~n PV: ~p" 916 "~n AS: ~p" 917 "~n AD: ~p", [P, CH, PV, AS, AD]), 918 P ! {ack_received, self(), AS}, 919 {ok, S}; 920 921handle_megaco_request({handle_trans_ack, CH, PV, AS, AD}, S) -> 922 d("handle_megaco_request(handle_trans_ack) -> entry with" 923 "~n Conn Handle: ~p" 924 "~n Prot Version: ~p" 925 "~n Ack Status: ~p" 926 "~n Ack Data: ~p", [CH, PV, AS, AD]), 927 {ok, S}; 928 929handle_megaco_request({handle_unexpected_trans, CH, PV, TR}, S) -> 930 d("handle_megaco_request(handle_unexpected_trans) -> entry with" 931 "~n CH: ~p" 932 "~n PV: ~p" 933 "~n TR: ~p", [CH, PV, TR]), 934 {ok, S}; 935 936handle_megaco_request({handle_trans_request_abort, CH, PV, TI, Handler}, S) -> 937 d("handle_megaco_request(handle_trans_request_abort) -> entry with" 938 "~n CH: ~p" 939 "~n PV: ~p" 940 "~n TI: ~p" 941 "~n Handler: ~p", [CH, PV, TI, Handler]), 942 Reply = 943 case S#mgc.abort_info of 944 P when is_pid(P) -> 945 P ! {abort_received, self(), TI}, 946 ok; 947 _ -> 948 ok 949 end, 950 {Reply, S}. 951 952 953do_handle_trans_request(CH, PV, ARs, 954 #mgc{req_action = Action, req_timeout = To} = S) -> 955 d("do_handle_megaco_request(handle_trans_request) -> entry with" 956 "~n Action: ~p" 957 "~n To: ~p", [Action, To]), 958 case handle_act_requests(CH, PV, ARs, Action) of 959 {pending_ignore, ActReqs} -> 960 {{pending, ActReqs}, S#mgc{req_action = ignore}}; 961 Reply -> 962 {{delay_reply, To, Reply}, S} 963 end. 964 965 966handle_act_requests(_CH, _PV, _ActReqs, ignore) -> 967 ignore; 968handle_act_requests(_CH, _PV, ActReqs, pending) -> 969 {pending, ActReqs}; 970handle_act_requests(_CH, _PV, ActReqs, pending_ignore) -> 971 {pending_ignore, ActReqs}; 972handle_act_requests(CH, PV, ActReqs, handle_ack) -> 973 Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])), 974 {{handle_ack, ActReqs}, Reply}; 975handle_act_requests(CH, PV, ActReqs, handle_sloppy_ack) -> 976 Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])), 977 {{handle_sloppy_ack, ActReqs}, Reply}; 978handle_act_requests(CH, PV, ActReqs, _) -> 979 Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])), 980 {discard_ack, Reply}. 981 982do_handle_act_requests(_CH, _PV, [], ActReplies) -> 983 lists:reverse(ActReplies); 984do_handle_act_requests(CH, PV, [ActReq|ActReqs], ActReplies) -> 985 ActReply = handle_act_request(CH, PV, ActReq), 986 do_handle_act_requests(CH, PV, ActReqs, [ActReply|ActReplies]). 987 988handle_act_request(CH, PV, ActReq) -> 989 #'ActionRequest'{contextId = CtxId, commandRequests = Cmds} = ActReq, 990 CmdReplies = handle_cmd_requests(CH, PV, CtxId, Cmds), 991 #'ActionReply'{contextId = CtxId, 992 commandReply = CmdReplies}. 993 994handle_cmd_requests(CH, PV, ?megaco_null_context_id, 995 [#'CommandRequest'{command={serviceChangeReq,Req}}]) -> 996 Rep = service_change(CH, PV, Req), 997 [{serviceChangeReply, Rep}]; 998handle_cmd_requests(CH, PV, CtxId, Cmds) -> 999 do_handle_cmd_requests(CH, PV, CtxId, Cmds, []). 1000 1001do_handle_cmd_requests(_CH, _PV, _CtxId, [], CmdReplies) -> 1002 lists:reverse(CmdReplies); 1003do_handle_cmd_requests(CH, PV, CtxId, [Cmd|Cmds], CmdReplies) -> 1004 CmdReply = handle_cmd_request(CH, PV, CtxId, Cmd), 1005 do_handle_cmd_requests(CH, PV, CtxId, Cmds, [CmdReply|CmdReplies]). 1006 1007handle_cmd_request(CH, PV, CtxId, 1008 #'CommandRequest'{command = {Tag,Req}}) -> 1009 case Tag of 1010 notifyReq -> 1011 (catch handle_notify_req(CH,PV,CtxId,Req)); 1012 1013 serviceChangeReq -> 1014 ED = cre_error_descr(?megaco_not_implemented, 1015 "Service change only allowed " 1016 "on null context handled"), 1017 throw(ED); 1018 1019 _ -> 1020 Code = ?megaco_not_implemented, 1021 ED = cre_error_descr(Code,"Unknown command requst received:" 1022 "~n Tag: ~p~n Req: ~p",[Tag,Req]), 1023 throw(ED) 1024 end. 1025 1026handle_notify_req(CH, PV, CtxId, 1027 #'NotifyRequest'{terminationID = [Tid], 1028 observedEventsDescriptor = EvDesc}) -> 1029 handle_event(CH, PV, CtxId, Tid, EvDesc). 1030 1031handle_event(_CH, _PV, _Cid, Tid, EvDesc) -> 1032 d("handle_event -> received" 1033 "~n EvDesc: ~p" 1034 "~n Tid: ~p", [EvDesc, Tid]), 1035 {notifyReply, cre_notifyRep(Tid)}. 1036 1037 1038service_change(CH, _PV, SCR) -> 1039 SCP = SCR#'ServiceChangeRequest'.serviceChangeParms, 1040 #'ServiceChangeParm'{serviceChangeAddress = Address, 1041 serviceChangeProfile = Profile, 1042 serviceChangeReason = [_Reason]} = SCP, 1043 TermId = SCR#'ServiceChangeRequest'.terminationID, 1044 if 1045 TermId == [?megaco_root_termination_id] -> 1046 MyMid = CH#megaco_conn_handle.local_mid, 1047 Res = {serviceChangeResParms, 1048 cre_serviceChangeResParms(MyMid, Address, Profile)}, 1049 cre_serviceChangeReply(TermId, Res); 1050 true -> 1051 Res = {errorDescriptor, 1052 cre_error_descr(?megaco_not_implemented, 1053 "Only handled for root")}, 1054 cre_serviceChangeReply(TermId, Res) 1055 end. 1056 1057 1058 1059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1060 1061cre_serviceChangeReply(TermId, Result) -> 1062 #'ServiceChangeReply'{terminationID = TermId, 1063 serviceChangeResult = Result}. 1064 1065cre_serviceChangeResParms(Mid, Addr, Prof) -> 1066 #'ServiceChangeResParm'{serviceChangeMgcId = Mid, 1067 serviceChangeAddress = Addr, 1068 serviceChangeProfile = Prof}. 1069 1070 1071cre_notifyRep(Tid) -> 1072 #'NotifyReply'{terminationID = [Tid]}. 1073 1074% cre_notifyRep(Tid,Err) -> 1075% #'NotifyReply'{terminationID = [Tid], errorDescriptor = Err}. 1076 1077cre_error_descr(Code,Text) -> 1078 #'ErrorDescriptor'{errorCode = Code, errorText = Text}. 1079 1080cre_error_descr(Code,FormatString,Args) -> 1081 Text = lists:flatten(io_lib:format(FormatString,Args)), 1082 cre_error_descr(Code,Text). 1083 1084 1085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1086 1087notify_started(Parent) -> 1088 Parent ! {started, self()}. 1089 1090 1091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1092 1093%% The megaco user callback interface 1094 1095handle_connect(CH, PV, Pid) -> 1096 case CH#megaco_conn_handle.remote_mid of 1097 preliminary_mid -> 1098 %% Avoids deadlock 1099 ok; 1100 _ -> 1101 Reply = request(Pid, {handle_connect, CH, PV}), 1102 Reply 1103 end. 1104 1105handle_disconnect(_CH, _PV, 1106 {user_disconnect, {Pid, ignore}}, 1107 Pid) -> 1108 ok; 1109handle_disconnect(CH, _PV, 1110 {user_disconnect, {Pid, cancel}}, 1111 Pid) -> 1112 megaco:cancel(CH, disconnected), 1113 ok; 1114handle_disconnect(CH, PV, R, Pid) -> 1115 request(Pid, {handle_disconnect, CH, PV, R}). 1116 1117handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Pid) -> 1118 Req = {handle_syntax_error, ReceiveHandle, ProtocolVersion, 1119 ErrorDescriptor}, 1120 request(Pid, Req). 1121 1122handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) -> 1123 Req = {handle_message_error, ConnHandle, ProtocolVersion, ErrorDescriptor}, 1124 request(Pid, Req). 1125 1126handle_trans_request(CH, PV, AR, Pid) -> 1127 Reply = request(Pid, {handle_trans_request, CH, PV, AR}), 1128 Reply. 1129 1130handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Pid) -> 1131 Req = {handle_trans_long_request, ConnHandle, ProtocolVersion, ReqData}, 1132 request(Pid, Req). 1133 1134handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData, Pid) -> 1135 Req = {handle_trans_reply, ConnHandle, ProtocolVersion, 1136 ActualReply, ReplyData}, 1137 request(Pid, Req). 1138 1139handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Pid) -> 1140 Req = {handle_trans_ack, ConnHandle, ProtocolVersion, AckStatus, AckData}, 1141 request(Pid, Req). 1142 1143handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Pid) -> 1144 Req = {handle_unexpected_trans, ConnHandle, ProtocolVersion, Trans}, 1145 request(Pid, Req). 1146 1147handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId, 1148 Handler, Pid) -> 1149 Req = {handle_trans_request_abort, 1150 ConnHandle, ProtocolVersion, TransId, Handler}, 1151 request(Pid, Req). 1152 1153 1154request(Pid, Request) -> 1155 Pid ! {request, Request, self()}, 1156 receive 1157 {reply, {delay_reply, To, Reply}, Pid} -> 1158 megaco:report_event(ignore, self(), Pid, 1159 "reply: delay_reply", [To, Reply]), 1160 sleep(To), 1161 megaco:report_event(ignore, self(), Pid, 1162 "reply: delay done now return", []), 1163 Reply; 1164 {reply, {exit, To, Reason}, Pid} -> 1165 megaco:report_event(ignore, self(), Pid, 1166 "reply: exit", [To, Reason]), 1167 sleep(To), 1168 megaco:report_event(ignore, self(), Pid, 1169 "reply: sleep done now exit", []), 1170 exit(Reason); 1171 {reply, Reply, Pid} -> 1172 megaco:report_event(ignore, self(), Pid, "reply", [Reply]), 1173 Reply 1174 end. 1175 1176 1177reply(To, Reply) -> 1178 To ! {reply, Reply, self()}. 1179 1180 1181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1182 1183sleep(X) -> 1184 d("sleep -> ~w", [X]), 1185 receive after X -> ok end. 1186 1187 1188info_msg(F,A) -> error_logger:info_msg("MGC: " ++ F ++ "~n",A). 1189error_msg(F,A) -> error_logger:error_msg("MGC: " ++ F ++ "~n",A). 1190 1191 1192get_encoding_module(RI) -> 1193 case (catch get_conf(encoding_module, RI)) of 1194 {error, _} -> 1195 undefined; 1196 Val -> 1197 Val 1198 end. 1199 1200get_encoding_config(RI, EM) -> 1201 case text_codec(EM) of 1202 true -> 1203 case megaco:system_info(text_config) of 1204 [Conf] when is_list(Conf) -> 1205 Conf; 1206 _ -> 1207 [] 1208 end; 1209 1210 false -> 1211 get_conf(encoding_config, RI) 1212 end. 1213 1214text_codec(megaco_compact_text_encoder) -> 1215 true; 1216text_codec(megaco_pretty_text_encoder) -> 1217 true; 1218text_codec(_) -> 1219 false. 1220 1221 1222get_transport_module(RI) -> 1223 get_conf(transport_module, RI). 1224 1225get_transport_port(RI) -> 1226 get_conf(port, RI). 1227 1228get_transport_opts(RI) -> 1229 get_conf(transport_opts, RI, []). 1230 1231 1232get_conf(Key, Config) -> 1233 case lists:keysearch(Key, 1, Config) of 1234 {value, {Key, Val}} -> 1235 Val; 1236 _ -> 1237 exit({error, {not_found, Key, Config}}) 1238 end. 1239 1240get_conf(Key, Config, Default) -> 1241 case lists:keysearch(Key, 1, Config) of 1242 {value, {Key, Val}} -> 1243 Val; 1244 _ -> 1245 Default 1246 end. 1247 1248 1249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1250 1251random_init() -> 1252 ok. 1253 1254random(N) -> 1255 rand:uniform(N). 1256 1257 1258display_system_info(Mid) -> 1259 display_system_info(Mid, ""). 1260 1261display_system_info(Mid, Pre) -> 1262 TimeStr = ?FTS(), 1263 MibStr = lists:flatten(io_lib:format("~p ", [Mid])), 1264 megaco_test_lib:display_system_info(MibStr ++ Pre ++ TimeStr). 1265 1266 1267create_timer(Time, Event) -> 1268 erlang:send_after(Time, self(), {Event, Time}). 1269 1270cancel_timer(undefined) -> 1271 ok; 1272cancel_timer(Ref) -> 1273 erlang:cancel_timer(Ref). 1274 1275 1276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1277 1278e(F, A) -> 1279 print(error, get(verbosity), "ERROR", F, A). 1280 1281i(F) -> 1282 i(F, []). 1283 1284i(F, A) -> 1285 print(info, get(verbosity), "INFO", F, A). 1286 1287 1288d(F) -> 1289 d(F, []). 1290 1291d(F, A) -> 1292 print(debug, get(verbosity), "DBG", F, A). 1293 1294 1295printable(error, _) -> true; 1296printable(_, debug) -> true; 1297printable(info, info) -> true; 1298printable(_,_) -> false. 1299 1300print(Severity, Verbosity, P, F, A) -> 1301 print(printable(Severity,Verbosity), P, F, A). 1302 1303print(true, P, F, A) -> 1304 print(P, F, A); 1305print(_, _, _, _) -> 1306 ok. 1307 1308print(P, F, A) -> 1309 io:format("*** [~s] [~s] ~p ~s ***" 1310 "~n " ++ F ++ "~n~n", 1311 [?FTS(), P, self(), get(sname) | A]). 1312 1313 1314