1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2007-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: megaco sequence generator for the megaco test suite 24%%---------------------------------------------------------------------- 25 26-module(megaco_test_megaco_generator). 27 28-behaviour(megaco_test_generator). 29 30-compile({no_auto_import,[error/1]}). 31 32%% API 33-export([ 34 start_link/1, start_link/2, 35 stop/1, 36 exec/2, exec/3 37 ]). 38 39%% genarator behaviour callback exports 40-export([ 41 init/1, 42 handle_parse/2, 43 handle_exec/2, 44 terminate/2 45 ]). 46 47%% Megaco callback api 48-export([ 49 handle_connect/3, handle_connect/4, 50 handle_disconnect/4, 51 handle_syntax_error/4, handle_syntax_error/5, 52 handle_message_error/4, handle_message_error/5, 53 handle_trans_request/4, handle_trans_request/5, 54 handle_trans_long_request/4, handle_trans_long_request/5, 55 handle_trans_reply/5, handle_trans_reply/6, 56 handle_trans_ack/5, handle_trans_ack/6, 57 handle_trans_request_abort/5, handle_trans_request_abort/6, 58 handle_unexpected_trans/4, handle_unexpected_trans/5 59 ]). 60 61 62%%---------------------------------------------------------------------- 63 64-include_lib("megaco/include/megaco.hrl"). 65 66 67%%---------------------------------------------------------------------- 68 69-define(DELIVER_MOD, megaco_test_deliver). 70 71 72%%---------------------------------------------------------------------- 73 74-record(state, 75 { 76 mid, 77 recv_handle, 78 port, 79 send_handle, 80 conn_handle, 81 82 transport_sup, 83 ctrl_pid, 84 85 result = [] % Accumulated results from verification 86 }). 87 88 89%%---------------------------------------------------------------------- 90%% API 91%%---------------------------------------------------------------------- 92 93start_link(Name) -> 94 megaco_test_generator:start_link(?MODULE, [], Name). 95 96start_link(Name, Node) -> 97 megaco_test_generator:start_link(?MODULE, [], Name, Node). 98 99stop(Server) -> 100 megaco_test_generator:stop(Server). 101 102exec(Server, Instructions) when is_list(Instructions) -> 103 megaco_test_generator:exec(Server, Instructions). 104 105exec(Server, Instructions, Timeout) when is_list(Instructions) -> 106 megaco_test_generator:exec(Server, Instructions, Timeout). 107 108 109%%---------------------------------------------------------------------- 110%% generator callback functions 111%%---------------------------------------------------------------------- 112 113init([]) -> 114 random_init(), 115 {ok, #state{}}. 116 117 118%% ----- instruction parser ----- 119 120handle_parse({debug, Debug} = Instruction, State) 121 when is_boolean(Debug) -> 122 {ok, Instruction, State}; 123 124handle_parse({expect_nothing, To} = Instruction, State) 125 when is_integer(To) andalso (To > 0) -> 126 {ok, Instruction, State}; 127 128handle_parse({megaco_trace, Level} = Instruction, State) 129 when (Level =:= disable) orelse 130 (Level =:= max) orelse 131 (Level =:= min) orelse 132 is_integer(Level) -> 133 {ok, Instruction, State}; 134 135handle_parse({sleep, To} = Instruction, State) 136 when is_integer(To) andalso (To > 0) -> 137 {ok, Instruction, State}; 138 139handle_parse(megaco_start = Instruction, State) -> 140 {ok, Instruction, State}; 141 142handle_parse(megaco_stop = Instruction, State) -> 143 {ok, Instruction, State}; 144 145handle_parse({megaco_start_user, _Mid, _RecvInfo, Conf} = Instruction, State) 146 when is_list(Conf) -> 147 {ok, Instruction, State}; 148 149handle_parse(megaco_stop_user = Instruction, State) -> 150 {ok, Instruction, State}; 151 152handle_parse(megaco_info = Instruction, State) -> 153 {ok, Instruction, State}; 154 155handle_parse(megaco_system_info, State) -> 156 Verify = fun(_) -> ok end, 157 Instruction = {megaco_system_info, internal_system_info_tag, Verify}, 158 {ok, Instruction, State}; 159 160handle_parse({megaco_system_info, Tag}, State) 161 when is_atom(Tag) -> 162 Verify = fun(_) -> ok end, 163 Instruction = {megaco_system_info, Tag, Verify}, 164 {ok, Instruction, State}; 165 166handle_parse({megaco_system_info, Tag, Verify} = Instruction, State) 167 when is_atom(Tag) andalso is_function(Verify) -> 168 {ok, Instruction, State}; 169 170handle_parse({megaco_user_info, Tag} = Instruction, State) 171 when is_atom(Tag) -> 172 {ok, Instruction, State}; 173 174handle_parse({megaco_update_user_info, Tag, _Val} = Instruction, State) 175 when is_atom(Tag) -> 176 {ok, Instruction, State}; 177 178handle_parse({megaco_conn_info, Tag} = Instruction, State) 179 when is_atom(Tag) -> 180 {ok, Instruction, State}; 181 182handle_parse({megaco_update_conn_info, Tag, _Val} = Instruction, State) 183 when is_atom(Tag) -> 184 {ok, Instruction, State}; 185 186handle_parse(start_transport = Instruction, State) -> 187 {ok, Instruction, State}; 188 189handle_parse(listen = _Instruction, State) -> 190 MeybeRetry = make_connect_retry_fun2(), 191 Instruction = {listen, [], MeybeRetry}, 192 {ok, Instruction, State}; 193 194handle_parse({listen, Opts} = _Instruction, State) 195 when is_list(Opts) -> 196 MeybeRetry = make_connect_retry_fun2(), 197 Instruction = {listen, Opts, MeybeRetry}, 198 {ok, Instruction, State}; 199 200handle_parse({listen, Opts, MeybeRetry} = Instruction, State) 201 when is_list(Opts) andalso is_function(MeybeRetry) -> 202 {ok, Instruction, State}; 203 204handle_parse(connect = _Instruction, State) -> 205 case inet:gethostname() of 206 {ok, LocalHost} -> 207 MeybeRetry = make_connect_retry_fun2(), 208 Instruction = {connect, LocalHost, [], MeybeRetry}, 209 {ok, Instruction, State}; 210 Error -> 211 Error 212 end; 213 214handle_parse({connect, Opts} = _Instruction, State) 215 when is_list(Opts) -> 216 verify_connect_opts(Opts), 217 case inet:gethostname() of 218 {ok, LocalHost} -> 219 MeybeRetry = make_connect_retry_fun2(), 220 Instruction = {connect, LocalHost, Opts, MeybeRetry}, 221 {ok, Instruction, State}; 222 Error -> 223 Error 224 end; 225 226handle_parse({connect, Host} = _Instruction, State) 227 when is_atom(Host) -> 228 MeybeRetry = make_connect_retry_fun2(), 229 Instruction = {connect, Host, [], MeybeRetry}, 230 {ok, Instruction, State}; 231 232handle_parse({connect, Host, Opts} = _Instruction, State) 233 when (is_atom(Host) orelse is_list(Host)) andalso is_list(Opts) -> 234 verify_connect_opts(Opts), 235 MeybeRetry = make_connect_retry_fun2(), 236 Instruction = {connect, Host, Opts, MeybeRetry}, 237 {ok, Instruction, State}; 238 239handle_parse({connect, Host, Opts, MeybeRetry} = Instruction, State) 240 when (is_atom(Host) orelse is_list(Host)) andalso 241 is_list(Opts) andalso 242 is_function(MeybeRetry) -> 243 verify_connect_opts(Opts), 244 {ok, Instruction, State}; 245 246handle_parse(disconnect = Instruction, State) -> 247 {ok, Instruction, State}; 248 249handle_parse(megaco_connect = Instruction, State) -> 250 {ok, Instruction, State}; 251 252handle_parse({megaco_connect, _} = Instruction, State) -> 253 {ok, Instruction, State}; 254 255handle_parse(megaco_disconnect = Instruction, State) -> 256 {ok, Instruction, State}; 257 258handle_parse({megaco_disconnect, _Reason} = Instruction, State) -> 259 {ok, Instruction, State}; 260 261handle_parse({megaco_call, ARs, Opts} = Instruction, State) 262 when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) -> 263 {ok, Instruction, State}; 264 265handle_parse({megaco_call, _Mid, ARs, Opts} = Instruction, State) 266 when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) -> 267 {ok, Instruction, State}; 268 269handle_parse({megaco_cast, ARs, Opts} = Instruction, State) 270 when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) -> 271 {ok, Instruction, State}; 272 273handle_parse({megaco_cast, _Mid, ARs, Opts} = Instruction, State) 274 when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) -> 275 {ok, Instruction, State}; 276 277handle_parse({megaco_cancel, _Reason} = Instruction, State) -> 278 {ok, Instruction, State}; 279 280handle_parse({megaco_callback, Tag, TimeoutOrVerify} = Instruction, State) 281 when (is_atom(Tag) andalso 282 ((is_integer(TimeoutOrVerify) andalso 283 (TimeoutOrVerify > 0)) orelse 284 is_function(TimeoutOrVerify))) -> 285 {ok, Instruction, State}; 286 287handle_parse({megaco_callback, Tag, Verify, Timeout} = Instruction, State) 288 when (is_atom(Tag) andalso 289 is_function(Verify) andalso 290 (is_integer(Timeout) andalso (Timeout > 0))) -> 291 {ok, Instruction, State}; 292 293handle_parse({megaco_callback, Tag, {VMod, VFunc, VArgs}} = _Instruction, 294 State) 295 when (is_atom(Tag) andalso 296 (is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs))) -> 297 Verify = fun(X) -> 298 io:format("[megaco_callback ~w] calling ~w:~w with" 299 "~n X: ~p" 300 "~n VArgs: ~w" 301 "~n", [Tag, VMod, VFunc, X, VArgs]), 302 (catch apply(VMod, VFunc, [X|VArgs])) 303 end, 304 Instruction = {megaco_callback, Tag, Verify}, 305 {ok, Instruction, State}; 306 307handle_parse({megaco_callback, Verifiers0} = _Instruction, State) 308 when is_list(Verifiers0) -> 309 Verifiers = [make_verifier(Verifier) || Verifier <- Verifiers0], 310 Instruction = {megaco_callback, Verifiers}, 311 {ok, Instruction, State}; 312 313handle_parse({trigger, Trigger} = Instruction, State) 314 when is_function(Trigger) -> 315 {ok, Instruction, State}; 316handle_parse({trigger, Desc, Trigger} = Instruction, State) 317 when is_list(Desc) andalso is_function(Trigger) -> 318 {ok, Instruction, State}; 319 320handle_parse(Instruction, _State) -> 321 error({invalid_instruction, Instruction}). 322 323 324make_verifier({Tag, No, VerifyFunc} = Verify) 325 when is_atom(Tag) andalso is_integer(No) andalso is_function(VerifyFunc) -> 326 Verify; 327make_verifier({Tag, No, {VMod, VFunc, VArgs}}) 328 when is_atom(Tag) andalso is_integer(No) andalso 329 (is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs)) -> 330 VerifyFunc = fun(X) -> 331 io:format("[megaco_callback ~w] calling ~w:~w with" 332 "~n X: ~p" 333 "~n VArgs: ~w" 334 "~n", [Tag, VMod, VFunc, X, VArgs]), 335 (catch apply(VMod, VFunc, [X|VArgs])) 336 end, 337 Verify = {Tag, No, VerifyFunc}, 338 Verify; 339make_verifier(BadVerifier) -> 340 error({bad_verifier, BadVerifier}). 341 342 343verify_connect_opts([]) -> 344 ok; 345verify_connect_opts([{Key, _}|Opts]) when is_atom(Key) -> 346 verify_connect_opts(Opts); 347verify_connect_opts([H|_]) -> 348 error({bad_opts_list, H}). 349 350%% make_connect_retry_fun1() -> 351%% fun(Error, _) -> 352%% {false, Error} 353%% end. 354 355make_connect_retry_fun2() -> 356 fun(Error, noError) -> 357 Timeout = 250, 358 sleep(random(Timeout) + 100), 359 {true, {3, Timeout*2, Error}}; 360 (_Error, {0, _Timeout, OriginalError}) -> 361 {false, OriginalError}; 362 (_Error, {N, Timeout, OriginalError}) -> 363 sleep(random(Timeout) + 100), 364 {true, {N-1, Timeout*2, OriginalError}} 365 end. 366 367 368%% ----- instruction exececutor ----- 369 370handle_exec({debug, Debug}, State) -> 371 p("debug: ~p", [Debug]), 372 put(debug, Debug), 373 {ok, State}; 374 375handle_exec({expect_nothing, To}, State) -> 376 p("expect nothing: ~p", [To]), 377 receive 378 Any -> 379 e("received unexpected: " 380 "~n ~p", [Any]), 381 error({expect_nothing, Any}) 382 after To -> 383 p("go nothing (~p) as expected", [To]), 384 {ok, State} 385 end; 386 387handle_exec({megaco_trace, disable}, State) -> 388 p("megaco trace: disable"), 389 megaco:disable_trace(), 390 {ok, State}; 391handle_exec({megaco_trace, Level}, State) -> 392 p("megaco trace: enable [~w]", [Level]), 393 megaco:enable_trace(Level, io), 394 {ok, State}; 395 396handle_exec(megaco_start, State) -> 397 p("start megaco"), 398 ok = megaco:start(), 399 {ok, State}; 400 401handle_exec(megaco_stop, State) -> 402 p("stop megaco"), 403 ok = megaco:stop(), 404 {ok, State}; 405 406handle_exec({megaco_start_user, Mid, RecvInfo, Conf}, State) -> 407 p("start megaco user: ~p", [Mid]), 408 409 d("megaco_start_user -> start user"), 410 ok = megaco:start_user(Mid, Conf), 411 412 d("megaco_start_user -> update user info: user_mod"), 413 ok = megaco:update_user_info(Mid, user_mod, ?MODULE), 414 415 d("megaco_start_user -> update user info: user_args"), 416 ok = megaco:update_user_info(Mid, user_args, [self()]), 417 418 Port = get_config(port, RecvInfo), 419 EM = get_config(encoding_module, RecvInfo), 420 EC = get_config(encoding_config, RecvInfo), 421 TM = get_config(transport_module, RecvInfo), 422 RH0 = megaco:user_info(Mid, receive_handle), 423 424 RH1 = RH0#megaco_receive_handle{send_mod = TM, 425 encoding_mod = EM, 426 encoding_config = EC}, 427 428 State1 = State#state{mid = Mid, recv_handle = RH1, port = Port}, 429 {ok, State1}; 430 431handle_exec(megaco_stop_user, #state{mid = Mid} = State) 432 when Mid =/= undefined -> 433 p("stop megaco user: ~p", [Mid]), 434 megaco_cleanup(State), 435 ok = megaco:stop_user(Mid), 436 {ok, State#state{mid = undefined}}; 437 438handle_exec(start_transport, 439 #state{recv_handle = #megaco_receive_handle{send_mod = TM}} = State) -> 440 p("start transport ~p", [TM]), 441 try TM:start_transport() of 442 {ok, Sup} -> 443 d("transport started: Sup: ~p", [Sup]), 444 {ok, State#state{transport_sup = Sup}}; 445 {error, Reason} -> 446 e("failed starting transport (~w): " 447 "~n ~p", [TM, Reason]), 448 error({failed_starting_transport, TM, Reason}); 449 Crap -> 450 e("failed starting transport (~w): " 451 "~n ~p", [TM, Crap]), 452 error({failed_starting_transport, TM, Crap}) 453 catch 454 C:E:S -> 455 e("failed starting transport (~w) - catched: " 456 "~n C: ~p" 457 "~n E: ~p" 458 "~n S: ~p", [TM, C, E, S]), 459 error({failed_starting_transport, TM, {E, E, S}}) 460 end; 461 462handle_exec({listen, Opts0, MaybeRetry}, 463 #state{recv_handle = RH, port = Port, transport_sup = Pid} = State) 464 when RH#megaco_receive_handle.send_mod =:= megaco_tcp -> 465 p("listen(tcp)"), 466 Opts = [{module, ?DELIVER_MOD}, 467 {port, Port}, 468 {receive_handle, RH}, 469 {tcp_options, [{nodelay, true}]} | Opts0], 470 try handle_exec_listen_tcp(Pid, Opts, MaybeRetry) of 471 ok -> 472 p("listen(tcp) -> ok"), 473 {ok, State}; 474 Else -> 475 e("failed tcp listen: " 476 "~n Else: ~p", [Else]), 477 error({tcp_listen_failed, Opts0, Else}) 478 catch 479 C:E:S -> 480 e("failed starting transport (~w) - catched: " 481 "~n C: ~p" 482 "~n E: ~p" 483 "~n S: ~p", [C, E, S]), 484 error({tc_listen_failed, Opts0, {E, E, S}}) 485 end; 486handle_exec({listen, Opts0, _MaybeRetry}, 487 #state{recv_handle = RH, port = Port, transport_sup = Pid} = State) 488 when RH#megaco_receive_handle.send_mod =:= megaco_udp -> 489 p("listen(udp) - open"), 490 Opts = [{module, ?DELIVER_MOD}, {port, Port}, {receive_handle, RH}|Opts0], 491 try megaco_udp:open(Pid, Opts) of 492 {ok, _SH, _CtrlPid} -> 493 p("listen(udp) -> ok"), 494 {ok, State}; 495 Else -> 496 e("[listen] failed udp open: " 497 "~n Else: ~p", [Else]), 498 error({udp_open, Opts0, Else}) 499 catch 500 C:E:S -> 501 e("[listen] failed udp open - catched: " 502 "~n C: ~p" 503 "~n E: ~p" 504 "~n S: ~p", [C, E, S]), 505 error({udp_open, Opts0, {C, E, S}}) 506 end; 507handle_exec({listen, Opts0, _MaybeRetry}, 508 #state{recv_handle = RH, port = Port, transport_sup = Pid} = State) 509 when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport -> 510 p("listen(generic)"), 511 Opts = [{module, ?DELIVER_MOD}, {port, Port}, {receive_handle, RH}|Opts0], 512 try megaco_test_generic_transport:listen(Pid, Opts) of 513 {ok, _SH, _CtrlPid} -> 514 p("listen(generic) -> ok"), 515 {ok, State}; 516 Else -> 517 e("[listen] failed generic: " 518 "~n Else: ~p", [Else]), 519 error({generic_listen, Opts0, Else}) 520 catch 521 C:E:S -> 522 e("[listen] failed generic - catched: " 523 "~n C: ~p" 524 "~n E: ~p" 525 "~n S: ~p", [C, E, S]), 526 error({generic_listen, Opts0, {C, E, S}}) 527 end; 528 529handle_exec({connect, Host, Opts0, MaybeRetry}, 530 #state{transport_sup = Sup, 531 recv_handle = RH, 532 port = Port} = State) 533 when RH#megaco_receive_handle.send_mod =:= megaco_tcp -> 534 p("connect(tcp) to ~p:~p", [Host, Port]), 535 PrelMid = preliminary_mid, 536 Opts = [{host, Host}, 537 {port, Port}, 538 {receive_handle, RH}, 539 {tcp_options, [{nodelay, true}]} | Opts0], 540 try handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry) of 541 {ok, SH, ControlPid} -> 542 p("connected(tcp): ~p, ~p", [SH, ControlPid]), 543 megaco_connector_start(RH, PrelMid, SH, ControlPid), 544 {ok, State#state{send_handle = SH, 545 ctrl_pid = ControlPid}}; 546 Error -> 547 e("tcp connect failed: " 548 "~n Error: ~p", [Error]), 549 error({tcp_connect_failed, Host, Opts0, Error}) 550 catch 551 C:E:S -> 552 e("tcp connect failed - catched: " 553 "~n C: ~p" 554 "~n E: ~p" 555 "~n S: ~p", [C, E, S]), 556 error({tcp_connect_failed, Host, Opts0, {C, E, S}}) 557 end; 558 559handle_exec({connect, Host, Opts0, _MaybeRetry}, 560 #state{transport_sup = Sup, 561 recv_handle = RH, 562 port = Port} = State) 563 when RH#megaco_receive_handle.send_mod =:= megaco_udp -> 564 p("connect(udp) to ~p", [Host]), 565 PrelMid = preliminary_mid, 566 Opts = [{port, 0}, {receive_handle, RH}|Opts0], 567 d("udp open", []), 568 try megaco_udp:open(Sup, Opts) of 569 {ok, Handle, ControlPid} -> 570 d("opened(udp): ~p, ~p", [Handle, ControlPid]), 571 SH = megaco_udp:create_send_handle(Handle, Host, Port), 572 megaco_connector_start(RH, PrelMid, SH, ControlPid), 573 {ok, State#state{send_handle = SH, 574 ctrl_pid = ControlPid}}; 575 Error -> 576 e("udp connect (open) failed: " 577 "~n Error: ~p", [Error]), 578 error({udp_connect_failed, Host, Opts0, Error}) 579 catch 580 C:E:S -> 581 e("udp connect (open) failed - catched: " 582 "~n C: ~p" 583 "~n E: ~p" 584 "~n S: ~p", [C, E, S]), 585 error({tcp_connect_failed, Host, Opts0, {C, E, S}}) 586 end; 587 588handle_exec({connect, Host, Opts0, _MaybeRetry}, 589 #state{transport_sup = Sup, 590 recv_handle = RH, 591 port = Port} = State) 592 when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport -> 593 p("connect(generic) to ~p", [Host]), 594 PrelMid = preliminary_mid, 595 Opts = [{host, Host}, {port, Port}, {receive_handle, RH}|Opts0], 596 try megaco_test_generic_transport:connect(Sup, Opts) of 597 {ok, SH, ControlPid} -> 598 d("connected(generic): ~p, ~p", [SH, ControlPid]), 599 megaco_connector_start(RH, PrelMid, SH, ControlPid), 600 {ok, State#state{send_handle = SH, 601 ctrl_pid = ControlPid}}; 602 Error -> 603 e("generic connect failed: " 604 "~n Error: ~p", [Error]), 605 error({generic_connect_failed, Host, Opts0, Error}) 606 catch 607 C:E:S -> 608 e("generic connect failed - catched: " 609 "~n C: ~p" 610 "~n E: ~p" 611 "~n S: ~p", [C, E, S]), 612 error({generic_connect_failed, Host, Opts0, {C, E, S}}) 613 end; 614 615handle_exec(megaco_connect, State) -> 616 p("expect megaco_connect"), 617 receive 618 {megaco_connect_result, {ok, CH}} -> 619 p("received successful megaco_connect: ~p", [CH]), 620 {ok, State#state{conn_handle = CH}}; 621 {megaco_connect_result, Error} -> 622 p("received failed megaco_connect: ~p", [Error]), 623 #state{result = AccRes} = State, 624 {ok, State#state{result = [Error|AccRes]}} 625 end; 626 627handle_exec({megaco_connect, Mid}, 628 #state{recv_handle = RH, 629 send_handle = SH, 630 ctrl_pid = ControlPid} = State) -> 631 p("megaco connect: ~p", [Mid]), 632 megaco_connector_start(RH, Mid, SH, ControlPid), 633 {ok, State}; 634 635handle_exec({megaco_user_info, Tag}, #state{mid = Mid, result = AccRes} = State) 636 when Mid /= undefined -> 637 p("megaco user-info: ~w", [Tag]), 638 Val = (catch megaco:user_info(Mid, Tag)), 639 d("megaco_user_info: ~p", [Val]), 640 {ok, State#state{result = [Val|AccRes]}}; 641 642handle_exec({megaco_update_user_info, Tag, Val}, #state{mid = Mid} = State) 643 when Mid /= undefined -> 644 p("update megaco user-info: ~w -> ~p", [Tag, Val]), 645 ok = megaco:update_user_info(Mid, Tag, Val), 646 {ok, State}; 647 648handle_exec({megaco_conn_info, Tag}, 649 #state{conn_handle = CH, result = Res} = State) 650 when CH /= undefined -> 651 p("megaco conn-info: ~w", [Tag]), 652 Val = (catch megaco:conn_info(CH, Tag)), 653 d("megaco_conn_info: ~p", [Val]), 654 {ok, State#state{result = [Val|Res]}}; 655 656handle_exec({megaco_update_conn_info, Tag, Val}, 657 #state{conn_handle = CH} = State) 658 when CH /= undefined -> 659 p("update megaco conn-info: ~w -> ~p", [Tag, Val]), 660 try megaco:update_conn_info(CH, Tag, Val) of 661 ok -> 662 {ok, State}; 663 Error -> 664 e("failed updating connection info: " 665 "~n Tag: ~p" 666 "~n Val: ~p" 667 "~n CH: ~p" 668 "~n Error: ~p", [Tag, Val, CH, Error]), 669 error({failed_updating_conn_info, Tag, Val, Error}) 670 catch 671 C:E:S -> 672 e("failed updating connection info: " 673 "~n Tag: ~p" 674 "~n Val: ~p" 675 "~n CH: ~p" 676 "~n C: ~p" 677 "~n E: ~p" 678 "~n S: ~p", [Tag, Val, CH, C, E, S]), 679 error({failed_updating_conn_info, Tag, Val, {C, E, S}}) 680 end; 681 682handle_exec(megaco_info, #state{result = AccRes} = State) -> 683 p("megaco info", []), 684 Val = (catch megaco:info()), 685 d("megaco_info: ~p", [Val]), 686 {ok, State#state{result = [Val|AccRes]}}; 687 688handle_exec({megaco_system_info, Tag, Verify}, 689 #state{result = AccRes} = State) -> 690 p("megaco system-info: ~w", [Tag]), 691 Val = (catch megaco:system_info(Tag)), 692 d("megaco system-info: ~p", [Val]), 693 try Verify(Val) of 694 ok -> 695 {ok, State#state{result = [Val|AccRes]}}; 696 Error -> 697 e("verification failed: " 698 "~n Error: ~p", [Error]), 699 {error, State#state{result = [Error|AccRes]}} 700 catch 701 C:E:S -> 702 e("verification failed - catched: " 703 "~n C: ~p" 704 "~n E: ~p" 705 "~n S: ~p", [C, E, S]), 706 {error, State#state{result = [{catched, {C, E, S}}|AccRes]}} 707 end; 708 709%% This is either a MG or a MGC which is only connected to one MG 710handle_exec({megaco_call, ARs, Opts}, #state{conn_handle = CH} = State) 711 when CH /= undefined -> 712 p("megaco_call: " 713 "~n CH: ~p" 714 "~n ARs: ~p" 715 "~n Opts: ~p", [CH, ARs, Opts]), 716 {_PV, UserReply} = megaco:call(CH, ARs, Opts), 717 d("megaco_call -> UserReply: ~n~p", [UserReply]), 718 {ok, State}; 719 720handle_exec({megaco_call, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) -> 721 p("megaco_call: ~p", [RemoteMid]), 722 %% First we have to find the CH for this Mid 723 Conns = megaco:user_info(Mid, connections), 724 {value, {_, CH}} = 725 lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns), 726 p("megaco_call: " 727 "~n CH: ~p" 728 "~n ARs: ~p" 729 "~n Opts: ~p", [CH, ARs, Opts]), 730 {_PV, UserReply} = megaco:call(CH, ARs, Opts), 731 d("megaco_call -> UserReply: ~n~p", [UserReply]), 732 {ok, State}; 733 734%% This is either a MG or a MGC which is only connected to one MG 735handle_exec({megaco_cast, ARs, Opts}, #state{conn_handle = CH, 736 result = AccRes} = State) 737 when CH =/= undefined -> 738 p("megaco_cast: " 739 "~n CH: ~p" 740 "~n ARs: ~p", [CH, ARs]), 741 try megaco:cast(CH, ARs, Opts) of 742 ok -> 743 p("megaco cast ok"), 744 {ok, State}; 745 Error -> 746 e("failed sending (cast) message: " 747 "~n Error: ~p", [Error]), 748 {error, State#state{result = [Error|AccRes]}} 749 catch 750 C:E:S -> 751 e("failed sending (cast) message - catched: " 752 "~n C: ~p" 753 "~n E: ~p" 754 "~n S: ~p", [C, E, S]), 755 {error, State#state{result = [{catched, {C, E, S}}|AccRes]}} 756 end; 757 758handle_exec({megaco_cast, RemoteMid, ARs, Opts}, 759 #state{mid = Mid, 760 result = AccRes} = State) -> 761 p("megaco_cast with ~p", [RemoteMid]), 762 %% First we have to find the CH for this Mid 763 Conns = megaco:user_info(Mid, connections), 764 {value, {_, CH}} = 765 lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns), 766 p("megaco_cast: " 767 "~n CH: ~p" 768 "~n ARs: ~p" 769 "~n Opts: ~p", [CH, ARs, Opts]), 770 case megaco:cast(CH, ARs, Opts) of 771 ok -> 772 {ok, State}; 773 Error -> 774 e("failed sending (cast) message: " 775 "~n ~p", [Error]), 776 {error, State#state{result = [Error|AccRes]}} 777 end; 778 779%% Nothing shall happen for atleast Timeout time 780handle_exec({megaco_callback, nocall, Timeout}, State) -> 781 p("expect no megaco_callback for ~w", [Timeout]), 782 receive 783 {handle_megaco_callback, Type, Msg, Pid} -> 784 e("received unexpected megaco callback: ~n~p", [Msg]), 785 #state{result = AccRes} = State, 786 Err = {unexpected_callback, Type, Msg, Pid}, 787 {error, State#state{result = [Err|AccRes]}} 788 after Timeout -> 789 p("got no callback (~p) as expected", [Timeout]), 790 {ok, State} 791 end; 792 793handle_exec({megaco_callback, Tag, Verify}, State) when is_function(Verify) -> 794 p("expect megaco_callback ~w", [Tag]), 795 receive 796 {handle_megaco_callback, Type, Msg, Pid} -> 797 d("received megaco callback:" 798 "~n ~p", [Msg]), 799 try Verify(Msg) of 800 {VRes, Res, Reply} -> 801 d("megaco_callback [~w] ~w", [Tag, VRes]), 802 handle_megaco_callback_reply(Pid, Type, Reply), 803 validate(VRes, Tag, Res, State); 804 {VRes, Delay, Res, Reply} -> 805 d("megaco_callback [~w] ~w, ~w", [Tag,Delay,VRes]), 806 handle_megaco_callback_reply(Pid, Type, Delay, Reply), 807 validate(VRes, Tag, Res, State) 808 catch 809 C:E:S -> 810 e("megaco callback - verification failed - catched: " 811 "~n C: ~p" 812 "~n E: ~p" 813 "~n S: ~p", [C, E, S]), 814 error({megaco_callback_verification_failed, Tag, {C, E, S}}) 815 end 816 end; 817 818handle_exec({megaco_callback, Tag, {VMod, VFunc, VArgs}}, State) 819 when is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs) -> 820 p("expect megaco_callback ~w", [Tag]), 821 receive 822 {handle_megaco_callback, Type, Msg, Pid} -> 823 d("received megaco callback: ~n~p" 824 "~n VMod: ~w" 825 "~n VFunc: ~w" 826 "~n VArgs: ~p", [Msg, VMod, VFunc, VArgs]), 827 try apply(VMod, VFunc, [Msg|VArgs]) of 828 {VRes, Res, Reply} -> 829 d("megaco_callback [~w] ~w",[Tag, VRes]), 830 handle_megaco_callback_reply(Pid, Type, Reply), 831 validate(VRes, Tag, Res, State); 832 {VRes, Delay, Res, Reply} -> 833 d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]), 834 handle_megaco_callback_reply(Pid, Type, Delay, Reply), 835 validate(VRes, Tag, Res, State) 836 catch 837 C:E:S -> 838 e("megaco callback - verification failed - catched: " 839 "~n C: ~p" 840 "~n E: ~p" 841 "~n S: ~p", [C, E, S]), 842 error({megaco_callback_verification_failed, Tag, {C, E, S}}) 843 end 844 end; 845 846handle_exec({megaco_callback, Tag, Verify, Timeout}, 847 #state{result = AccRes} = State) 848 when (is_function(Verify) andalso 849 (is_integer(Timeout) andalso (Timeout > 0))) -> 850 p("expect megaco_callback ~w (with ~w)", [Tag, Timeout]), 851 receive 852 {handle_megaco_callback, Type, Msg, Pid} -> 853 d("received megaco callback: ~n~p", [Msg]), 854 try Verify(Msg) of 855 {VRes, Res, Reply} -> 856 d("megaco_callback [~w] ~w",[Tag,VRes]), 857 handle_megaco_callback_reply(Pid, Type, Reply), 858 validate(VRes, Tag, Res, State); 859 {VRes, Delay, Res, Reply} -> 860 d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]), 861 handle_megaco_callback_reply(Pid, Type, Delay, Reply), 862 validate(VRes, Tag, Res, State) 863 catch 864 C:E:S -> 865 e("megaco callback - verification failed - catched: " 866 "~n C: ~p" 867 "~n E: ~p" 868 "~n S: ~p", [C, E, S]), 869 error({megaco_callback_verification_failed, Tag, {C, E, S}}) 870 end 871 after Timeout -> 872 e("megaco_callback ~w timeout", [Tag]), 873 Err = {callback_timeout, Tag, Timeout}, 874 {error, State#state{result = [Err|AccRes]}} 875 end; 876 877handle_exec({megaco_callback, Verifiers}, State) -> 878 p("expect megaco_callback(s)"), 879 megaco_callback_verify(Verifiers, State); 880 881handle_exec({megaco_cancel, Reason}, #state{conn_handle = CH} = State) -> 882 p("megaco_cancel: ~w", [Reason]), 883 case megaco:cancel(CH, Reason) of 884 ok -> 885 {ok, State}; 886 Error -> 887 e("failed cancel: ~n~p", [Error]), 888 #state{result = AccRes} = State, 889 {error, State#state{result = [Error|AccRes]}} 890 end; 891 892handle_exec({trigger, Trigger}, State) when is_function(Trigger) -> 893 p("trigger"), 894 (catch Trigger()), 895 {ok, State}; 896handle_exec({trigger, Desc, Trigger}, State) when is_function(Trigger) -> 897 p("trigger: ~s", [Desc]), 898 (catch Trigger()), 899 {ok, State}; 900 901handle_exec({sleep, To}, State) -> 902 p("sleep ~p", [To]), 903 megaco_test_generator:sleep(To), 904 {ok, State}; 905 906handle_exec(BadInstruction, _State) -> 907 error({invalid_instruction, BadInstruction}). 908 909 910%% --- cleanup --- 911 912megaco_cleanup(#state{mid = Mid}) -> 913 Close = fun(CH) -> do_megaco_cleanup(CH) end, 914 Conns = 915 case (catch megaco:user_info(Mid, connections)) of 916 Connections when is_list(Connections) -> 917 Connections; 918 _ -> 919 [] 920 end, 921 lists:foreach(Close, Conns). 922 923do_megaco_cleanup(CH) -> 924 case (catch do_megaco_cleanup2(CH)) of 925 ok -> 926 ok; 927 {'EXIT', {no_such_connection, _}} -> 928 ok; 929 {'EXIT', Reason} -> 930 exit(Reason) 931 end. 932 933do_megaco_cleanup2(CH) -> 934 d("do_megaco_cleanup2 -> entry with" 935 "~n CH: ~p", [CH]), 936 Reason = {stopped_by_user,self()}, 937 Pid = megaco:conn_info(CH, control_pid), 938 SendMod = megaco:conn_info(CH, send_mod), 939 SendHandle = megaco:conn_info(CH, send_handle), 940 d("do_megaco_cleanup2 -> disconnect"), 941 megaco:disconnect(CH, Reason), 942 d("do_megaco_cleanup2 -> disconnected, now cancel"), 943 megaco:cancel(CH, Reason), 944 d("do_megaco_cleanup2 -> canceled, now close"), 945 case SendMod of 946 megaco_tcp -> (catch megaco_tcp:close(SendHandle)); 947 megaco_udp -> (catch megaco_udp:close(SendHandle)); 948 SendMod -> exit(Pid, Reason) 949 end, 950 ok. 951 952 953%% --- connector --- 954 955megaco_connector_start(RH, PrelMid, SH, ControlPid) -> 956 Self = self(), 957 Fun = fun() -> megaco_connect(RH, PrelMid, SH, ControlPid, Self) end, 958 erlang:spawn_opt(Fun, [link]). 959 960megaco_connect(RH, PrelMid, SH, ControlPid, Parent) -> 961 Result = megaco:connect(RH, PrelMid, SH, ControlPid), 962 Parent ! {megaco_connect_result, Result}, 963 exit(normal). 964 965 966%% --- megaco callback verify --- 967 968%% This is used when a number of callback's is expected, but where 969%% the specific order is unknown. 970megaco_callback_verify([], State) -> 971 d("megaco_callback_verify -> done"), 972 {ok, State}; 973megaco_callback_verify(Verifiers0, State0) -> 974 d("megaco_callback_verify -> entry when" 975 "~n length(Verifiers0): ~w", [length(Verifiers0)]), 976 receive 977 {handle_megaco_callback, Type, Msg, Pid} -> 978 d("megaco_callback_verify -> received megaco callback: ~w" 979 "~n Msg: ~p", [Type, Msg]), 980 case megaco_callback_verify(Verifiers0, Type, Msg, Pid, State0) of 981 {ok, Verifiers, State} -> 982 megaco_callback_verify(Verifiers, State); 983 Error -> 984 Error 985 end 986 end. 987 988megaco_callback_verify(Verifiers0, Type, Msg, Pid, State0) -> 989 d("megaco_callback_verify -> entry"), 990 Tag = element(1, Msg), 991 d("megaco_callback_verify -> Tag: ~w", [Tag]), 992 case lists:keysearch(Tag, 1, Verifiers0) of 993 {value, {Tag, N, Verify}} when (N > 0) andalso is_function(Verify) -> 994 d("megaco_callback_verify -> N: ~w",[N]), 995 case Verify(Msg) of 996 {VRes, Res, Reply} -> 997 d("megaco_callback_verify -> VRes: ~w",[VRes]), 998 handle_megaco_callback_reply(Pid, Type, Reply), 999 case validate(VRes, Tag, Res, State0) of 1000 {error, _} = EState -> 1001 e("megaco_callback_verify -> (1) error", []), 1002 throw(EState); 1003 {ok, State} when N > 1 -> 1004 d("megaco_callback_verify -> (1) validated"), 1005 Rec = {Tag, N-1, Verify}, 1006 Verifiers = 1007 lists:keyreplace(Tag, 1, Verifiers0, Rec), 1008 {ok, Verifiers, State}; 1009 {ok, State} -> 1010 d("megaco_callback_verify -> (2) validated"), 1011 Verifiers = lists:keydelete(Tag, 1, Verifiers0), 1012 {ok, Verifiers, State} 1013 end; 1014 {VRes, Delay, Res, Reply} -> 1015 d("megaco_callback_verify -> Delay: ~w, VRes: ~w", 1016 [Delay,VRes]), 1017 handle_megaco_callback_reply(Pid, Type, Delay, Reply), 1018 case validate(VRes, Tag, Res, State0) of 1019 {error, _} = EState -> 1020 e("megaco_callback_verify -> (2) error", []), 1021 throw(EState); 1022 {ok, State} when N > 1 -> 1023 d("megaco_callback_verify -> (3) validated"), 1024 Rec = {Tag, N-1, Verify}, 1025 Verifiers = 1026 lists:keyreplace(Tag, 1, Verifiers0, Rec), 1027 {ok, Verifiers, State}; 1028 {ok, State} -> 1029 d("megaco_callback_verify -> (4) validated"), 1030 Verifiers = lists:keydelete(Tag, 1, Verifiers0), 1031 {ok, Verifiers, State} 1032 end 1033 end; 1034 false -> 1035 e("megaco_callback_verify -> no such tag ~w~n~p", 1036 [Tag, Verifiers0]), 1037 #state{result = Res} = State0, 1038 State = State0#state{result = [{Type, error, Msg}|Res]}, 1039 error(State) 1040 end. 1041 1042 1043%% --- validate verify result --- 1044 1045validate(ok, handle_connect = Tag, CH, #state{result = Acc} = S) -> 1046 {ok, S#state{conn_handle = CH, result = [{Tag, ok, CH}|Acc]}}; 1047validate(ok, Tag, Res, #state{result = Acc} = S) -> 1048 {ok, S#state{result = [{Tag, ok, Res}|Acc]}}; 1049validate(error, Tag, Res, #state{result = Acc} = S) -> 1050 {error, S#state{result = [{Tag, error, Res}|Acc]}}. 1051 1052 1053%% ----- termination ----- 1054 1055terminate(normal, #state{result = Result} = _State) -> 1056 d("terminate -> entry when normal with" 1057 "~n Result: ~p", [Result]), 1058 %% megaco_cleanup(State), 1059 {ok, Result}; 1060 1061terminate(Reason, #state{result = Result} = State) -> 1062 d("terminate -> entry with" 1063 "~n Reason: ~p" 1064 "~n Result: ~p", [Reason, Result]), 1065 megaco_cleanup(State), 1066 {error, {Reason, Result}}. 1067 1068 1069%%---------------------------------------------------------------------- 1070 1071handle_exec_listen_tcp(Sup, Opts, MaybeRetry) -> 1072 handle_exec_listen_tcp(Sup, Opts, MaybeRetry, noError). 1073 1074handle_exec_listen_tcp(Sup, Opts, MaybeRetry, Error0) -> 1075 case (catch megaco_tcp:listen(Sup, Opts)) of 1076 ok -> 1077 ok; 1078 Error1 -> 1079 case (catch MaybeRetry(Error1, Error0)) of 1080 {true, Error2} -> 1081 handle_exec_listen_tcp(Sup, Opts, MaybeRetry, Error2); 1082 {false, Error3} -> 1083 {error, Error3} 1084 end 1085 end. 1086 1087 1088handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry) 1089 when is_function(MaybeRetry) -> 1090 handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry, noError). 1091 1092handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry, Error0) -> 1093 case (catch megaco_tcp:connect(Sup, Opts)) of 1094 {ok, SH, ControlPid} -> 1095 d("tcp connected: ~p, ~p", [SH, ControlPid]), 1096 {ok, SH, ControlPid}; 1097 Error1 -> 1098 case (catch MaybeRetry(Error1, Error0)) of 1099 {true, Error2} -> 1100 handle_exec_connect_tcp(Host, Opts, Sup, 1101 MaybeRetry, Error2); 1102 {false, Error3} -> 1103 {error, Error3} 1104 end 1105 end. 1106 1107 1108 1109%%---------------------------------------------------------------------- 1110%% megaco_user callback functions 1111%%---------------------------------------------------------------------- 1112 1113handle_connect(CH, PV, P) -> 1114 Req = {handle_connect, CH, PV}, 1115 handle_megaco_callback_call(P, Req). 1116 1117handle_connect(CH, PV, Extra, P) -> 1118 Req = {handle_connect, CH, PV, Extra}, 1119 handle_megaco_callback_call(P, Req). 1120 1121handle_disconnect(CH, PV, R, P) -> 1122 Msg = {handle_disconnect, CH, PV, R}, 1123 Reply = ok, 1124 handle_megaco_callback_cast(P, Msg, Reply). 1125 1126handle_syntax_error(RH, PV, ED, P) -> 1127 Req = {handle_syntax_error, RH, PV, ED}, 1128 handle_megaco_callback_call(P, Req). 1129 1130handle_syntax_error(RH, PV, ED, Extra, P) -> 1131 Req = {handle_syntax_error, RH, PV, ED, Extra}, 1132 handle_megaco_callback_call(P, Req). 1133 1134handle_message_error(CH, PV, ED, P) -> 1135 Msg = {handle_message_error, CH, PV, ED}, 1136 Reply = ok, 1137 handle_megaco_callback_cast(P, Msg, Reply). 1138 1139handle_message_error(CH, PV, ED, Extra, P) -> 1140 Msg = {handle_message_error, CH, PV, ED, Extra}, 1141 Reply = ok, 1142 handle_megaco_callback_cast(P, Msg, Reply). 1143 1144handle_trans_request(CH, PV, AR, P) -> 1145 Req = {handle_trans_request, CH, PV, AR}, 1146 handle_megaco_callback_call(P, Req). 1147 1148handle_trans_request(CH, PV, AR, Extra, P) -> 1149 Req = {handle_trans_request, CH, PV, AR, Extra}, 1150 handle_megaco_callback_call(P, Req). 1151 1152handle_trans_long_request(CH, PV, RD, P) -> 1153 Req = {handle_trans_long_request, CH, PV, RD}, 1154 handle_megaco_callback_call(P, Req). 1155 1156handle_trans_long_request(CH, PV, RD, Extra, P) -> 1157 Req = {handle_trans_long_request, CH, PV, RD, Extra}, 1158 handle_megaco_callback_call(P, Req). 1159 1160handle_trans_reply(CH, PV, AR, RD, P) -> 1161 Msg = {handle_trans_reply, CH, PV, AR, RD}, 1162 Reply = ok, 1163 handle_megaco_callback_cast(P, Msg, Reply). 1164 1165handle_trans_reply(CH, PV, AR, RD, Extra, P) -> 1166 Msg = {handle_trans_reply, CH, PV, AR, RD, Extra}, 1167 Reply = ok, 1168 handle_megaco_callback_cast(P, Msg, Reply). 1169 1170handle_trans_ack(CH, PV, AS, AD, P) -> 1171 Msg = {handle_trans_ack, CH, PV, AS, AD}, 1172 Reply = ok, 1173 handle_megaco_callback_cast(P, Msg, Reply). 1174 1175handle_trans_ack(CH, PV, AS, AD, Extra, P) -> 1176 Msg = {handle_trans_ack, CH, PV, AS, AD, Extra}, 1177 Reply = ok, 1178 handle_megaco_callback_cast(P, Msg, Reply). 1179 1180handle_unexpected_trans(CH, PV, T, P) -> 1181 Msg = {handle_unexpected_trans, CH, PV, T}, 1182 Reply = ok, 1183 handle_megaco_callback_cast(P, Msg, Reply). 1184 1185handle_unexpected_trans(CH, PV, T, Extra, P) -> 1186 Msg = {handle_unexpected_trans, CH, PV, T, Extra}, 1187 Reply = ok, 1188 handle_megaco_callback_cast(P, Msg, Reply). 1189 1190handle_trans_request_abort(RH, PV, TransNo, Pid, P) -> 1191 Msg = {handle_trans_request_abort, RH, PV, TransNo, Pid}, 1192 Reply = ok, 1193 handle_megaco_callback_cast(P, Msg, Reply). 1194 1195handle_trans_request_abort(RH, PV, TransNo, Pid, Extra, P) -> 1196 Msg = {handle_trans_request_abort, RH, PV, TransNo, Pid, Extra}, 1197 Reply = ok, 1198 handle_megaco_callback_cast(P, Msg, Reply). 1199 1200handle_megaco_callback_cast(P, Msg, Reply) -> 1201 d("handle_megaco_callback_cast -> entry with Msg: ~n~p", [Msg]), 1202 P ! {handle_megaco_callback, cast, Msg, self()}, 1203 Reply. 1204 1205handle_megaco_callback_call(P, Msg) -> 1206 d("handle_megaco_callback_call -> entry with" 1207 "~n P: ~p" 1208 "~n Msg: ~p", [P, Msg]), 1209 P ! {handle_megaco_callback, call, Msg, self()}, 1210 receive 1211 {handle_megaco_callback_reply, Reply} -> 1212 d("handle_megaco_callback_call -> received reply: ~n~p", [Reply]), 1213 Reply; 1214 {handle_megaco_callback_reply, Delay, Reply} when is_integer(Delay) -> 1215 d("handle_megaco_callback_call -> " 1216 "received reply [~w]: " 1217 "~n ~p", [Delay, Reply]), 1218 sleep(Delay), 1219 d("handle_megaco_callback_call -> deliver reply after delay [~w]", 1220 [Delay]), 1221 Reply; 1222 {'EXIT', Pid, Reason} when (Pid =:= P) -> 1223 d("handle_megaco_callback_call -> " 1224 "received unexpected EXIT signal (from ~p): " 1225 "~n Reason: ~p", [Pid, Reason]), 1226 exit({unexpected_EXIT_signal, Pid, Reason}); 1227 {'EXIT', SomePid, SomeReason} -> 1228 d("handle_megaco_callback_call -> " 1229 "received unexpected EXIT signal from unknown process: " 1230 "~n Pid: ~p" 1231 "~n Reason: ~p", [SomePid, SomeReason]), 1232 exit({unexpected_EXIT_signal, SomePid, SomeReason}) 1233 end. 1234 1235 1236handle_megaco_callback_reply(P, call, Reply) -> 1237 P ! {handle_megaco_callback_reply, Reply}; 1238handle_megaco_callback_reply(_, _, _) -> 1239 ok. 1240 1241handle_megaco_callback_reply(P, call, Delay, Reply) -> 1242 P ! {handle_megaco_callback_reply, Delay, Reply}; 1243handle_megaco_callback_reply(_, _, _, _) -> 1244 ok. 1245 1246 1247%%---------------------------------------------------------------------- 1248%% internal utility functions 1249%%---------------------------------------------------------------------- 1250 1251random_init() -> 1252 ok. 1253 1254random(N) -> 1255 rand:uniform(N). 1256 1257 1258get_config(Key, Opts) -> 1259 {value, {Key, Val}} = lists:keysearch(Key, 1, Opts), 1260 Val. 1261 1262sleep(X) -> megaco_test_generator:sleep(X). 1263 1264d(F) -> megaco_test_generator:debug(F). 1265d(F, A) -> megaco_test_generator:debug(F, A). 1266 1267e(F, A) -> megaco_test_generator:error(F, A). 1268 1269p(F ) -> p("", F, []). 1270p(F, A) -> p("", F, A). 1271p(P, F, A) -> megaco_test_generator:print(P, F, A). 1272 1273error(Reason) -> 1274 throw({error, Reason}). 1275 1276