1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2002-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: Verify the application specifics of the Megaco application 24%%---------------------------------------------------------------------- 25 26-module(megaco_mib_SUITE). 27 28-export([ 29 suite/0, all/0, groups/0, 30 init_per_suite/1, end_per_suite/1, 31 init_per_group/2, end_per_group/2, 32 init_per_testcase/2, end_per_testcase/2, 33 34 plain/1, 35 connect/1, 36 traffic/1, 37 38 mg/3, 39 mgc/3, 40 41 handle_connect/3, 42 handle_disconnect/4, 43 handle_syntax_error/4, 44 handle_message_error/4, 45 handle_trans_request/4, 46 handle_trans_long_request/4, 47 handle_trans_reply/5, 48 handle_trans_ack/5 49 ]). 50 51-include_lib("megaco/include/megaco.hrl"). 52-include_lib("megaco/include/megaco_message_v1.hrl"). 53-include("megaco_test_lib.hrl"). 54 55-define(TEST_VERBOSITY, info). % silence | info | debug 56-define(MGC_VERBOSITY, debug). 57-define(MG_VERBOSITY, debug). 58 59-define(LOAD_COUNTER_START, 100). 60-define(A4444, ["11111111", "00000000", "00000000"]). 61 62-record(mgc, {parent = undefined, 63 tcp_sup = undefined, 64 udp_sup = undefined, 65 mid = undefined, 66 mg = []}). 67-record(mg, {parent = undefined, 68 mid = undefined, 69 conn_handle = undefined, 70 state = initiated, 71 load_counter = 0}). 72 73 74%%====================================================================== 75%% Common Test interface functions 76%%====================================================================== 77 78suite() -> 79 [{ct_hooks, [ts_install_cth]}]. 80 81all() -> 82 [ 83 plain, 84 connect, 85 traffic 86 ]. 87 88groups() -> 89 []. 90 91 92 93%% 94%% ----- 95%% 96 97init_per_suite(suite) -> 98 []; 99init_per_suite(doc) -> 100 []; 101init_per_suite(Config0) when is_list(Config0) -> 102 103 ?ANNOUNCE_SUITE_INIT(), 104 105 p("init_per_suite -> entry with" 106 "~n Config: ~p" 107 "~n Nodes: ~p", [Config0, erlang:nodes()]), 108 109 case ?LIB:init_per_suite(Config0) of 110 {skip, _} = SKIP -> 111 SKIP; 112 113 Config1 when is_list(Config1) -> 114 115 %% We need a (local) monitor on this node also 116 megaco_test_sys_monitor:start(), 117 118 p("init_per_suite -> end when" 119 "~n Config: ~p" 120 "~n Nodes: ~p", [Config1, erlang:nodes()]), 121 122 Config1 123 end. 124 125end_per_suite(suite) -> []; 126end_per_suite(doc) -> []; 127end_per_suite(Config0) when is_list(Config0) -> 128 129 p("end_per_suite -> entry with" 130 "~n Config: ~p" 131 "~n Nodes: ~p", [Config0, erlang:nodes()]), 132 133 megaco_test_sys_monitor:stop(), 134 Config1 = ?LIB:end_per_suite(Config0), 135 136 p("end_per_suite -> end when" 137 "~n Nodes: ~p", [erlang:nodes()]), 138 139 Config1. 140 141 142%% 143%% ----- 144%% 145 146init_per_group(_GroupName, Config) -> 147 Config. 148 149end_per_group(_GroupName, Config) -> 150 Config. 151 152 153 154%% 155%% ----- 156%% 157 158init_per_testcase(Case, Config) -> 159 process_flag(trap_exit, true), 160 161 progress("init_per_testcase -> ~w", [Case]), 162 163 megaco_test_global_sys_monitor:reset_events(), 164 165 case Case of 166 traffic -> 167 Conf0 = lists:keydelete(tc_timeout, 1, Config), 168 Conf = [{tc_timeout, timer:minutes(5)}|Conf0], 169 megaco_test_lib:init_per_testcase(Case, Conf); 170 _ -> 171 megaco_test_lib:init_per_testcase(Case, Config) 172 end. 173 174end_per_testcase(Case, Config) -> 175 process_flag(trap_exit, false), 176 177 progress("end_per_testcase -> ~w", [Case]), 178 179 p("system events during test: " 180 "~n ~p", [megaco_test_global_sys_monitor:events()]), 181 182 megaco_test_lib:end_per_testcase(Case, Config). 183 184 185 186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 187 188plain(suite) -> 189 []; 190plain(doc) -> 191 ["Test case for the basic statistics counter handling. "]; 192plain(Config) when is_list(Config) -> 193 io:format("create test table 1~n", []), 194 Tab1 = megaco_test_cnt1, 195 megaco_stats:init(Tab1), 196 197 io:format("~ncreate test table 2~n", []), 198 Tab2 = megaco_test_cnt2, 199 megaco_stats:init(Tab2, [kalle, hobbe]), 200 201 io:format("~ntable 1 increments~n", []), 202 H1 = #megaco_conn_handle{local_mid = {deviceName, "a"}, 203 remote_mid = {deviceName, "b"}}, 204 H2 = #megaco_conn_handle{local_mid = {deviceName, "a"}, 205 remote_mid = {deviceName, "c"}}, 206 1 = megaco_stats:inc(Tab1, H1, sune), 207 2 = megaco_stats:inc(Tab1, H2, sune, 2), 208 3 = megaco_stats:inc(Tab1, H1, gurka, 3), 209 4 = megaco_stats:inc(Tab1, H2, sune, 2), 210 4 = megaco_stats:inc(Tab1, H1, gurka), 211 212 io:format("~ntable 2 increments~n", []), 213 H3 = #megaco_conn_handle{local_mid = {deviceName, "e"}, 214 remote_mid = {deviceName, "c"}}, 215 H4 = #megaco_conn_handle{local_mid = {deviceName, "e"}, 216 remote_mid = {deviceName, "d"}}, 217 1 = megaco_stats:inc(Tab2, H3, tomat), 218 4 = megaco_stats:inc(Tab2, H3, tomat, 3), 219 5 = megaco_stats:inc(Tab2, H4, paprika, 5), 220 221 io:format("~ntable 2 global increments~n", []), 222 1 = megaco_stats:inc(Tab2, kalle), 223 1 = megaco_stats:inc(Tab2, hobbe), 224 2 = megaco_stats:inc(Tab2, hobbe), 225 2 = megaco_stats:inc(Tab2, kalle), 226 3 = megaco_stats:inc(Tab2, kalle), 227 4 = megaco_stats:inc(Tab2, hobbe, 2), 228 229 io:format("~ntable 1 stats~n", []), 230 {ok, Stats1} = megaco_stats:get_stats(Tab1), 231 io:format("Stats1 = ~p~n", [Stats1]), 232 {value, {H1, H1Stats}} = lists:keysearch(H1, 1, Stats1), 233 Stats1_2 = lists:keydelete(H1, 1, Stats1), 234 {value, {H2, H2Stats}} = lists:keysearch(H2, 1, Stats1_2), 235 Stats1_3 = lists:keydelete(H2, 1, Stats1_2), 236 [] = Stats1_3, 237 io:format("H1Stats = ~p~n", [H1Stats]), 238 io:format("H2Stats = ~p~n", [H2Stats]), 239 240 {value, {sune, 1}} = lists:keysearch(sune, 1, H1Stats), 241 H1Stats_2 = lists:keydelete(sune, 1, H1Stats), 242 {value, {gurka, 4}} = lists:keysearch(gurka, 1, H1Stats_2), 243 H1Stats_3 = lists:keydelete(gurka, 1, H1Stats_2), 244 [] = H1Stats_3, 245 246 {value, {sune, 4}} = lists:keysearch(sune, 1, H2Stats), 247 H2Stats_2 = lists:keydelete(sune, 1, H2Stats), 248 [] = H2Stats_2, 249 250 251 %% -- 252 io:format("~ntable 2 stats~n", []), 253 {ok, Stats2} = megaco_stats:get_stats(Tab2), 254 io:format("Stats2 = ~p~n", [Stats2]), 255 {ok, 3} = megaco_stats:get_stats(Tab2, kalle), 256 {ok, 4} = megaco_stats:get_stats(Tab2, hobbe), 257 258 259 %% -- 260 io:format("~ntable 1 reset stats for ~p~n", [H1]), 261 megaco_stats:reset_stats(Tab1, H1), 262 {ok, Stats1_4} = megaco_stats:get_stats(Tab1), 263 io:format("Stats1_4 = ~p~n", [Stats1_4]), 264 {ok, 0} = megaco_stats:get_stats(Tab1, H1, sune), 265 {ok, 0} = megaco_stats:get_stats(Tab1, H1, gurka), 266 267 268 %% -- 269 io:format("~ntable 2 reset stats for kalle and ~p~n", [H4]), 270 megaco_stats:reset_stats(Tab2, kalle), 271 megaco_stats:reset_stats(Tab2, H4), 272 {ok, Stats2_2} = megaco_stats:get_stats(Tab2), 273 io:format("Stats2_2 = ~p~n", [Stats2_2]), 274 {ok, 0} = megaco_stats:get_stats(Tab2, kalle), 275 {ok, 4} = megaco_stats:get_stats(Tab2, hobbe), 276 {ok, 4} = megaco_stats:get_stats(Tab2, H3, tomat), 277 {ok, 0} = megaco_stats:get_stats(Tab2, H4, paprika), 278 {ok, Stats4_4} = megaco_stats:get_stats(Tab2, H4), 279 io:format("Stats4_4 = ~p~n", [Stats4_4]), 280 281 %% -- 282 io:format("~ntable 2 stats for nonexisting counters~n", []), 283 {error, _} = megaco_stats:get_stats(Tab2, kalla), 284 {error, _} = megaco_stats:get_stats(Tab2, H3, paprika), 285 ok. 286 287 288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289 290connect(suite) -> 291 []; 292connect(doc) -> 293 []; 294connect(Config) when is_list(Config) -> 295 Pre = fun() -> 296 progress("start nodes"), 297 MgcNode = make_node_name(mgc), 298 Mg1Node = make_node_name(mg1), 299 Mg2Node = make_node_name(mg2), 300 d("connect -> Nodes: " 301 "~n MgcNode: ~p" 302 "~n Mg1Node: ~p" 303 "~n Mg2Node: ~p", [MgcNode, Mg1Node, Mg2Node]), 304 Nodes = [MgcNode, Mg1Node, Mg2Node], 305 ok = ?START_NODES(Nodes, true), 306 Nodes 307 end, 308 Case = fun do_connect/1, 309 Post = fun(Nodes) -> 310 progress("stop nodes"), 311 d("stop nodes"), 312 ?STOP_NODES(lists:reverse(Nodes)) 313 end, 314 try_tc(connect, Pre, Case, Post). 315 316do_connect([MgcNode, Mg1Node, Mg2Node]) -> 317 %% Start the MGC and MGs 318 319 ET = [{text, tcp}, {text, udp}, {binary, tcp}, {binary, udp}], 320 progress("start MGC (on ~p)", [MgcNode]), 321 {ok, Mgc} = 322 start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY), 323 324 progress("start MG1 (on ~p) using tcp", [Mg1Node]), 325 {ok, Mg1} = 326 start_mg(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY), 327 328 progress("start MG2 (on ~p) using udp", [Mg2Node]), 329 {ok, Mg2} = 330 start_mg(Mg2Node, {deviceName, "mg2"}, binary, udp, ?MG_VERBOSITY), 331 332 %% Collect the initial statistics (should be zero if anything) 333 progress("collect initial MG1 stats"), 334 {ok, Mg1Stats0} = get_stats(Mg1, 1), 335 d("connect -> stats for Mg1: ~n~p", [Mg1Stats0]), 336 progress("collect initial MG2 stats"), 337 {ok, Mg2Stats0} = get_stats(Mg2, 1), 338 d("connect -> stats for Mg2: ~n~p", [Mg2Stats0]), 339 progress("collect initial MGC stats"), 340 {ok, MgcStats0} = get_stats(Mgc, 1), 341 d("connect -> stats for Mgc: ~n~p", [MgcStats0]), 342 343 %% Ask Mg1 to do a service change 344 progress("perform MG1 service change"), 345 {ok, Res1} = service_change(Mg1), 346 d("connect -> (Mg1) service change result: ~p", [Res1]), 347 348 %% Collect the statistics 349 progress("collect MG1 statistics (after service change)"), 350 {ok, Mg1Stats1} = get_stats(Mg1, 1), 351 d("connect -> stats for Mg1: ~n~p", [Mg1Stats1]), 352 progress("collect MGC statistics (after MG1 service change)"), 353 {ok, MgcStats1} = get_stats(Mgc, 1), 354 d("connect -> stats (1) for Mgc: ~n~p", [MgcStats1]), 355 {ok, MgcStats2} = get_stats(Mgc, 2), 356 d("connect -> stats (2) for Mgc: ~n~p", [MgcStats2]), 357 358 %% Ask Mg2 to do a service change 359 progress("perform MG2 service change"), 360 {ok, Res2} = service_change(Mg2), 361 d("connect -> (Mg2) service change result: ~p", [Res2]), 362 363 %% Collect the statistics 364 progress("collect MG2 statistics (after service change)"), 365 {ok, Mg2Stats1} = get_stats(Mg2, 1), 366 d("connect -> stats for Mg1: ~n~p", [Mg2Stats1]), 367 progress("collect MGC statistics (after MG2 service change)"), 368 {ok, MgcStats3} = get_stats(Mgc, 1), 369 d("connect -> stats (1) for Mgc: ~n~p", [MgcStats3]), 370 {ok, MgcStats4} = get_stats(Mgc, 2), 371 d("connect -> stats (2) for Mgc: ~n~p", [MgcStats4]), 372 373 %% Tell Mg1 to stop 374 progress("stop MG1"), 375 stop(Mg1), 376 377 %% Collect the statistics 378 progress("collect MGC statistics (after MG1 stop)"), 379 {ok, MgcStats5} = get_stats(Mgc, 1), 380 d("connect -> stats (1) for Mgc: ~n~p", [MgcStats5]), 381 {ok, MgcStats6} = get_stats(Mgc, 2), 382 d("connect -> stats (2) for Mgc: ~n~p", [MgcStats6]), 383 384 %% Tell Mg2 to stop 385 progress("stop MG2"), 386 stop(Mg2), 387 388 %% Collect the statistics 389 progress("collect MGC statistics (after MG2 stop)"), 390 {ok, MgcStats7} = get_stats(Mgc, 1), 391 d("connect -> stats (1) for Mgc: ~n~p", [MgcStats7]), 392 {ok, MgcStats8} = get_stats(Mgc, 2), 393 d("connect -> stats (2) for Mgc: ~n~p", [MgcStats8]), 394 395 %% Tell Mgc to stop 396 progress("stop MGC"), 397 stop(Mgc), 398 399 i("connect -> done", []), 400 ok. 401 402 403 404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 405 406traffic(suite) -> 407 []; 408traffic(doc) -> 409 []; 410traffic(Config) when is_list(Config) -> 411 Pre = fun() -> 412 progress("start nodes"), 413 MgcNode = make_node_name(mgc), 414 Mg1Node = make_node_name(mg1), 415 Mg2Node = make_node_name(mg2), 416 Mg3Node = make_node_name(mg3), 417 Mg4Node = make_node_name(mg4), 418 Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node], 419 d("traffic -> Nodes: " 420 "~n MgcNode: ~p" 421 "~n Mg1Node: ~p" 422 "~n Mg2Node: ~p" 423 "~n Mg3Node: ~p" 424 "~n Mg4Node: ~p", 425 [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]), 426 ok = ?START_NODES(Nodes, true), 427 Nodes 428 end, 429 Case = fun do_traffic/1, 430 Post = fun(Nodes) -> 431 progress("stop nodes"), 432 d("stop nodes"), 433 ?STOP_NODES(lists:reverse(Nodes)) 434 end, 435 try_tc(traffic, Pre, Case, Post). 436 437do_traffic([MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]) -> 438 %% Start the MGC and MGs 439 i("start the MGC"), 440 progress("start MGC (on ~p)", [MgcNode]), 441 ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], 442 {ok, Mgc} = 443 start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY), 444 445 i("traffic -> start and connect the MGs"), 446 progress("start and connect MGs"), 447 MgConf0 = [{Mg1Node, "mg1", text, tcp}, 448 {Mg2Node, "mg2", text, udp}, 449 {Mg3Node, "mg3", binary, tcp}, 450 {Mg4Node, "mg4", binary, udp}], 451 MgConf = traffic_connect_mg(MgConf0, []), 452 453 %% Collect and check the MGs statistics 454 i("traffic -> collect and check the MGs stats"), 455 progress("collect and verify MGs (initial) stats"), 456 traffic_verify_mg_stats(MgConf, 1, 1), 457 458 %% Collect and check the MGC statistics 459 i("traffic -> collect and check the MGC (initial) stats"), 460 progress("collect and verify MGC stats"), 461 {ok, MgcStats1} = get_stats(Mgc, 1), 462 d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats1]), 463 traffic_verify_mgc_stats(Mgc, 1, 1), 464 465 466 ?SLEEP(1000), 467 468 469 %% And apply some load 470 i("traffic -> apply traffic load (1)"), 471 progress("apply some load (1)"), 472 ok = traffic_apply_load(MgConf), 473 474 %% Await completion of load part and the collect traffic 475 i("traffic -> await load (1) competion"), 476 progress("await load (1) completion"), 477 ok = traffic_await_load_complete(MgConf), 478 479 480 ?SLEEP(1000), 481 482 483 i("traffic -> collect and check the MGs statistics"), 484 progress("collect and verify MGs (after load 1) stats"), 485 traffic_verify_mg_stats(MgConf, 486 1 + ?LOAD_COUNTER_START, 487 1 + ?LOAD_COUNTER_START), 488 489 i("traffic -> collect and check the MGC statistics"), 490 progress("collect and verify MGC (after load 1) stats"), 491 {ok, MgcStats3} = get_stats(Mgc, 1), 492 d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats3]), 493 traffic_verify_mgc_stats(Mgc, 494 1 + ?LOAD_COUNTER_START, 495 1 + ?LOAD_COUNTER_START), 496 497 498 ?SLEEP(1000), 499 500 501 %% Reset counters 502 i("traffic -> reset the MGs statistics"), 503 progress("reset MGs stats"), 504 traffic_reset_mg_stats(MgConf), 505 i("traffic -> collect and check the MGs statistics"), 506 progress("collect and verify MGs (after reset) stats"), 507 traffic_verify_mg_stats(MgConf, 0, 0), 508 509 i("traffic -> reset the MGC statistics"), 510 progress("reset MGC stats"), 511 traffic_reset_mgc_stats(Mgc), 512 i("traffic -> collect and check the MGC statistics"), 513 progress("collect and verify MGC (after reset) stats"), 514 traffic_verify_mgc_stats(Mgc, 0, 0), 515 516 517 ?SLEEP(1000), 518 519 520 %% And apply some load 521 i("traffic -> apply traffic load (2)"), 522 progress("apply some load (2)"), 523 ok = traffic_apply_load(MgConf), 524 525 %% Await completion of load part and the collect traffic 526 i("traffic -> await load (2) competion"), 527 progress("await load (2) completion"), 528 ok = traffic_await_load_complete(MgConf), 529 530 531 ?SLEEP(1000), 532 533 534 i("traffic -> collect and check the MGs statistics"), 535 progress("collect and verify MGs (after load 2) stats"), 536 traffic_verify_mg_stats(MgConf, 537 ?LOAD_COUNTER_START, 538 ?LOAD_COUNTER_START), 539 540 i("traffic -> collect and check the MGC statistics"), 541 progress("collect and verify MGC (after load 2) stats"), 542 traffic_verify_mgc_stats(Mgc, 543 ?LOAD_COUNTER_START, 544 ?LOAD_COUNTER_START), 545 546 547 ?SLEEP(1000), 548 549 550 %% Tell MGs to stop 551 i("traffic -> stop the MGs"), 552 progress("stop MGs"), 553 traffic_stop_mg(MgConf), 554 555 556 ?SLEEP(1000), 557 558 559 %% Collect the statistics 560 i("traffic -> collect the MGC statistics"), 561 progress("collect and verify MGC (after MGs stop) stats"), 562 {ok, MgcStats7} = get_stats(Mgc, 1), 563 d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats7]), 564 {ok, MgcStats8} = get_stats(Mgc, 2), 565 d("traffic -> stats (2) for Mgc: ~n~p~n", [MgcStats8]), 566 567 %% Tell Mgc to stop 568 i("traffic -> stop the MGC"), 569 progress("stop MGC"), 570 stop(Mgc), 571 572 i("traffic -> done", []), 573 ok. 574 575 576traffic_verify_mgc_stats(Pid, Out, In) 577 when is_pid(Pid) andalso is_integer(Out) andalso is_integer(In) -> 578 d("traffic_verify_mgc_stats -> entry with" 579 "~n Out: ~p" 580 "~n In: ~p", [Out, In]), 581 {ok, Stats} = get_stats(Pid, 2), 582 d("traffic_verify_mgc_stats -> stats (2) for Mgc: ~n~p~n", [Stats]), 583 traffic_verify_mgc_stats(Stats, Out, In); 584 585traffic_verify_mgc_stats(Stats, Out, In) when is_list(Stats) -> 586 d("traffic_verify_mgc_stats -> checking stats"), 587 Gen = traffic_verify_get_stats(gen, Stats), 588 Trans = traffic_verify_get_stats(trans, Stats), 589 traffic_verify_mgc_stats_gen(Gen), 590 traffic_verify_mgc_stats_trans(Trans, Out, In). 591 592traffic_verify_mgc_stats_gen([]) -> 593 d("traffic_verify_mgc_stats_gen -> done"), 594 ok; 595traffic_verify_mgc_stats_gen([{medGwyGatewayNumErrors, 0}|Stats]) -> 596 traffic_verify_mgc_stats_gen(Stats); 597traffic_verify_mgc_stats_gen([{medGwyGatewayNumErrors, Val}|_]) -> 598 exit({global_error_counter, Val, mgc}); 599traffic_verify_mgc_stats_gen([{Handle, Counters}|Stats]) -> 600 N = {mgc, Handle, Handle}, 601 traffic_verify_counter(N, medGwyGatewayNumErrors, Counters, 0), 602 traffic_verify_mgc_stats_gen(Stats). 603 604 605traffic_verify_mgc_stats_trans([], _Out, _In) -> 606 ok; 607traffic_verify_mgc_stats_trans([{Mod, Stats}|MgcStats], Out, In) -> 608 d("traffic_verify_mgc_stats_trans -> entry with" 609 "~n Mod: ~p" 610 "~n Stats: ~p", [Mod, Stats]), 611 traffic_verify_mgc_stats_trans(Mod, Stats, Out, In), 612 traffic_verify_mgc_stats_trans(MgcStats, Out, In). 613 614traffic_verify_mgc_stats_trans(_Mod, [], _Out, _In) -> 615 ok; 616traffic_verify_mgc_stats_trans(Mod, [{Handle,Counters}|Stats], Out, In) -> 617 N = {mgc, Mod, Handle}, 618 traffic_verify_counter(N, medGwyGatewayNumErrors, Counters, 0), 619 traffic_verify_counter(N, medGwyGatewayNumOutMessages, Counters, Out), 620 traffic_verify_counter(N, medGwyGatewayNumInMessages, Counters, In), 621 traffic_verify_mgc_stats_trans(Mod, Stats, Out, In). 622 623 624traffic_verify_mg_stats(MgConf, Out, In) 625 when is_integer(Out) andalso is_integer(In) -> 626 d("traffic_verify_mg_stats -> entry with" 627 "~n Out: ~p" 628 "~n In: ~p", [Out, In]), 629 Stats = traffic_get_mg_stats(MgConf, []), 630 d("traffic_verify_mg_stats -> stats for MGs: ~n~p", [Stats]), 631 traffic_verify_mg_stats1(Stats, Out, In). 632 633traffic_verify_mg_stats1([], _, _) -> 634 ok; 635traffic_verify_mg_stats1([{Name, Stats}|MgStats], Out, In) -> 636 d("traffic_verify_mg_stats1 -> entry with" 637 "~n Name: ~s" 638 "~n Stats: ~p", [Name, Stats]), 639 Gen = traffic_verify_get_stats(gen, Stats), 640 Trans = traffic_verify_get_stats(trans, Stats), 641 traffic_verify_mg_stats_gen(Name, Gen), 642 traffic_verify_mg_stats_trans(Name, Trans, Out, In), 643 traffic_verify_mg_stats1(MgStats, Out, In). 644 645traffic_verify_mg_stats_gen(Mg, []) -> 646 d("traffic_verify_mg_stats_gen -> ~s checked out OK",[Mg]), 647 ok; 648traffic_verify_mg_stats_gen(Mg, [{medGwyGatewayNumErrors, 0}|Stats]) -> 649 traffic_verify_mg_stats_gen(Mg, Stats); 650traffic_verify_mg_stats_gen(Mg, [{medGwyGatewayNumErrors, Val}|_]) -> 651 exit({global_error_counter, Val, Mg}); 652traffic_verify_mg_stats_gen(Mg, [{_Handle, Counters}|Stats]) -> 653 traffic_verify_counter(Mg, medGwyGatewayNumErrors, Counters, 0), 654 traffic_verify_mg_stats_gen(Mg, Stats). 655 656traffic_verify_mg_stats_trans(Mg, Counters, Out, In) -> 657 traffic_verify_counter(Mg, medGwyGatewayNumErrors, Counters, 0), 658 traffic_verify_counter(Mg, medGwyGatewayNumOutMessages, Counters, Out), 659 traffic_verify_counter(Mg, medGwyGatewayNumInMessages, Counters, In). 660 661 662traffic_verify_get_stats(S, Stats) -> 663 case lists:keysearch(S, 1, Stats) of 664 {value, {S, Val}} -> 665 Val; 666 false -> 667 exit({not_found, S, Stats}) 668 end. 669 670traffic_verify_counter(Name, Counter, Counters, Expected) -> 671 case lists:keysearch(Counter, 1, Counters) of 672 {value, {Counter, Expected}} -> 673 i("counter ~w verified for ~p", [Counter, Name]), 674 ok; 675 {value, {Counter, Val}} -> 676 i("counter ~w *not* verified for ~p: " 677 "~n Expected: ~w" 678 "~n Actual: ~w", [Counter, Name, Expected, Val]), 679 exit({illegal_counter_value, Counter, Val, Expected, Name}); 680 false -> 681 i("counter ~w *not* found for ~p", [Counter, Name]), 682 exit({not_found, Counter, Counters, Name, Expected}) 683 end. 684 685 686traffic_connect_mg([], Acc) -> 687 lists:reverse(Acc); 688traffic_connect_mg([{Node, Name, Coding, Trans}|Mg], Acc) -> 689 Pid = traffic_connect_mg(Node, Name, Coding, Trans), 690 traffic_connect_mg(Mg, [{Name, Pid}|Acc]). 691 692traffic_connect_mg(Node, Name, Coding, Trans) -> 693 progress("start (and connect) ~s (on ~p) using ~p", [Name, Node, Trans]), 694 Mid = {deviceName, Name}, 695 {ok, Pid} = start_mg(Node, Mid, Coding, Trans, ?MG_VERBOSITY), 696 697 %% Ask the MGs to do a service change 698 progress("perform ~s service change", [Name]), 699 {ok, Res} = service_change(Pid), 700 d("traffic_connect_mg -> (~s) service change result: ~p", [Name, Res]), 701 Pid. 702 703 704traffic_stop_mg(MGs) -> 705 [stop(Pid) || {_Name, Pid} <- MGs]. 706 707 708traffic_get_mg_stats([], Acc) -> 709 lists:reverse(Acc); 710traffic_get_mg_stats([{Name, Pid}|Mgs], Acc) -> 711 {ok, Stats} = get_stats(Pid, 1), 712 d("traffic_get_mg_stats -> stats for ~s: " 713 "~n ~p" 714 "~n", [Name, Stats]), 715 traffic_get_mg_stats(Mgs, [{Name, Stats}|Acc]). 716 717 718traffic_apply_load([]) -> 719 ok; 720traffic_apply_load([{_,MG}|MGs]) -> 721 MG ! {apply_load, self(), ?LOAD_COUNTER_START}, 722 receive 723 {apply_load_ack, MG} -> 724 traffic_apply_load(MGs); 725 {'EXIT', MG, Reason} -> 726 exit({mg_exit, MG, Reason}) 727 after 10000 -> 728 exit({apply_load_ack_timeout, MG}) 729 end. 730 731 732traffic_reset_mg_stats([]) -> 733 ok; 734traffic_reset_mg_stats([{Name, Pid}|MGs]) -> 735 d("traffic_reset_mg_stats -> resetting ~s", [Name]), 736 traffic_reset_stats(Pid), 737 traffic_reset_mg_stats(MGs). 738 739traffic_reset_mgc_stats(Mgc) -> 740 d("traffic_reset_mgc_stats -> resetting ~p", [Mgc]), 741 traffic_reset_stats(Mgc). 742 743traffic_reset_stats(Pid) -> 744 Pid ! {reset_stats, self()}, 745 receive 746 {reset_stats_ack, Pid} -> 747 ok; 748 {'EXIT', Pid, Reason} -> 749 exit({client_exit, Pid, Reason}) 750 after 10000 -> 751 exit({reset_stats_ack_timeout, Pid}) 752 end. 753 754 755traffic_await_load_complete([]) -> 756 ok; 757traffic_await_load_complete(MGs0) -> 758 receive 759 {load_complete, Pid} -> 760 d("received load_complete from ~p", [Pid]), 761 MGs1 = lists:keydelete(Pid, 2, MGs0), 762 traffic_await_load_complete(lists:delete(Pid, MGs1)); 763 {'EXIT', Pid, Reason} -> 764 i("exit signal from ~p: ~p", [Pid, Reason]), 765 case lists:keymember(Pid, 2, MGs0) of 766 true -> 767 exit({mg_exit, Pid, Reason}); 768 false -> 769 MGs1 = lists:keydelete(Pid, 2, MGs0), 770 traffic_await_load_complete(lists:delete(Pid, MGs1)) 771 end 772 end. 773 774 775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 776 777make_node_name(Name) -> 778 case string:tokens(atom_to_list(node()), [$@]) of 779 [_,Host] -> 780 list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host])); 781 _ -> 782 exit("Test node must be started with '-sname'") 783 end. 784 785 786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 787 788start_mgc(Node, Mid, ET, Verbosity) -> 789 d("start mgc[~p]: ~p", [Node, Mid]), 790 RI = {receive_info, mk_recv_info(ET)}, 791 Config = [{local_mid, Mid}, RI], 792 Pid = spawn_link(Node, ?MODULE, mgc, [self(), Verbosity, Config]), 793 await_started(Pid). 794 795mk_recv_info(ET) -> 796 mk_recv_info(ET, []). 797 798mk_recv_info([], Acc) -> 799 Acc; 800mk_recv_info([{text,tcp}|ET], Acc) -> 801 RI = [{encoding_module, megaco_pretty_text_encoder}, 802 {encoding_config, []}, 803 {transport_module, megaco_tcp}, 804 {port, 2944}], 805 mk_recv_info(ET, [RI|Acc]); 806mk_recv_info([{text,udp}|ET], Acc) -> 807 RI = [{encoding_module, megaco_pretty_text_encoder}, 808 {encoding_config, []}, 809 {transport_module, megaco_udp}, 810 {port, 2944}], 811 mk_recv_info(ET, [RI|Acc]); 812mk_recv_info([{binary,tcp}|ET], Acc) -> 813 RI = [{encoding_module, megaco_ber_encoder}, 814 {encoding_config, []}, 815 {transport_module, megaco_tcp}, 816 {port, 2945}], 817 mk_recv_info(ET, [RI|Acc]); 818mk_recv_info([{binary,udp}|ET], Acc) -> 819 RI = [{encoding_module, megaco_ber_encoder}, 820 {encoding_config, []}, 821 {transport_module, megaco_udp}, 822 {port, 2945}], 823 mk_recv_info(ET, [RI|Acc]); 824mk_recv_info([ET|_], _) -> 825 throw({error, {invaalid_encoding_transport, ET}}). 826 827mgc(Parent, Verbosity, Config) -> 828 process_flag(trap_exit, true), 829 put(verbosity, Verbosity), 830 put(sname, "MGC"), 831 i("mgc -> starting"), 832 {Mid, TcpSup, UdpSup} = mgc_init(Config), 833 notify_started(Parent), 834 S = #mgc{parent = Parent, 835 tcp_sup = TcpSup, udp_sup = UdpSup, mid = Mid}, 836 i("mgc -> started"), 837 mgc_loop(S). 838 839mgc_init(Config) -> 840 d("mgc_init -> entry"), 841 Mid = get_conf(local_mid, Config), 842 RI = get_conf(receive_info, Config), 843 i("mgc_init -> start megaco"), 844 application:start(megaco), 845 d("mgc_init -> start megaco user"), 846 megaco:start_user(Mid, []), 847 d("mgc_init -> update user info (user_mod)"), 848 megaco:update_user_info(Mid, user_mod, ?MODULE), 849 d("mgc_init -> update user info (user_args)"), 850 megaco:update_user_info(Mid, user_args, [self()]), 851 d("mgc_init -> get user info (receive_handle)"), 852 RH = megaco:user_info(Mid,receive_handle), 853 d("mgc_init -> parse receive info"), 854 ListenTo = mgc_parse_receive_info(RI, RH), 855 i("mgc_init -> start transport(s) with:" 856 "~n ListenTo: ~p", [ListenTo]), 857 {Tcp, Udp} = mgc_start_transports(ListenTo), 858 i("mgc_init -> transport(s) started:" 859 "~n Tcp: ~p" 860 "~n Udp: ~p", [Tcp, Udp]), 861 {Mid, Tcp, Udp}. 862 863 864mgc_loop(S) -> 865 d("mgc_loop -> await request"), 866 receive 867 {stop, Parent} when S#mgc.parent == Parent -> 868 i("mgc_loop -> stopping", []), 869 Mid = S#mgc.mid, 870 (catch mgc_close_conns(Mid)), 871 megaco:stop_user(Mid), 872 application:stop(megaco), 873 i("mgc_loop -> stopped", []), 874 Parent ! {stopped, self()}, 875 exit(normal); 876 877 878 879 %% Reset stats 880 {reset_stats, Parent} when S#mgc.parent == Parent -> 881 i("mgc_loop -> got request to reset stats counters"), 882 mgc_reset_stats(S#mgc.mid), 883 Parent ! {reset_stats_ack, self()}, 884 mgc_loop(S); 885 886 887 %% Give me statistics 888 {statistics, 1, Parent} when S#mgc.parent == Parent -> 889 i("mgc_loop -> got request for statistics 1"), 890 {ok, Gen} = megaco:get_stats(), 891 GetTrans = 892 fun(CH) -> 893 Reason = {statistics, CH}, 894 Pid = megaco:conn_info(CH, control_pid), 895 SendMod = megaco:conn_info(CH, send_mod), 896 SendHandle = megaco:conn_info(CH, send_handle), 897 {ok, Stats} = 898 case SendMod of 899 megaco_tcp -> megaco_tcp:get_stats(SendHandle); 900 megaco_udp -> megaco_udp:get_stats(SendHandle); 901 SendMod -> exit(Pid, Reason) 902 end, 903 {SendHandle, Stats} 904 end, 905 Mid = S#mgc.mid, 906 Trans = 907 lists:map(GetTrans, megaco:user_info(Mid, connections)), 908 Parent ! {statistics, 1, [{gen, Gen}, {trans, Trans}], self()}, 909 mgc_loop(S); 910 911 912 {statistics, 2, Parent} when S#mgc.parent == Parent -> 913 i("mgc_loop -> got request for statistics 2"), 914 {ok, Gen} = megaco:get_stats(), 915 #mgc{tcp_sup = TcpSup, udp_sup = UdpSup} = S, 916 TcpStats = get_trans_stats(TcpSup, megaco_tcp), 917 UdpStats = get_trans_stats(UdpSup, megaco_udp), 918 Parent ! {statistics, 2, [{gen, Gen}, {trans, [TcpStats, UdpStats]}], self()}, 919 mgc_loop(S); 920 921 922 %% Megaco callback messages 923 {request, Request, From} -> 924 d("mgc_loop -> received megaco request: ~n~p~n From: ~p", 925 [Request, From]), 926 Reply = mgc_handle_request(Request), 927 d("mgc_loop -> send request reply: ~n~p", [Reply]), 928 From ! {reply, Reply, self()}, 929 mgc_loop(S); 930 931 932 {'EXIT', Pid, Reason} -> 933 error_msg("MGC received unexpected exit signal from ~p:~n~p", 934 [Pid, Reason]), 935 mgc_loop(S); 936 937 938 Invalid -> 939 i("mgc_loop -> received invalid request: ~p", [Invalid]), 940 mgc_loop(S) 941 end. 942 943 944mgc_reset_stats(Mid) -> 945 megaco:reset_stats(), 946 mgc_reset_trans_stats(megaco:user_info(Mid, connections), []). 947 948mgc_reset_trans_stats([], _Reset) -> 949 ok; 950mgc_reset_trans_stats([CH|CHs], Reset) -> 951 SendMod = megaco:conn_info(CH, send_mod), 952 case lists:member(SendMod, Reset) of 953 true -> 954 mgc_reset_trans_stats(CHs, Reset); 955 false -> 956 SendMod:reset_stats(), 957 mgc_reset_trans_stats(CHs, [SendMod|Reset]) 958 end. 959 960 961mgc_close_conns(Mid) -> 962 Reason = {self(), ignore}, 963 Disco = fun(CH) -> 964 (catch mgc_close_conn(CH, Reason)) 965 end, 966 lists:map(Disco, megaco:user_info(Mid, connections)). 967 968mgc_close_conn(CH, Reason) -> 969 d("close connection to ~p", [CH#megaco_conn_handle.remote_mid]), 970 Pid = megaco:conn_info(CH, control_pid), 971 SendMod = megaco:conn_info(CH, send_mod), 972 SendHandle = megaco:conn_info(CH, send_handle), 973 megaco:disconnect(CH, Reason), 974 case SendMod of 975 megaco_tcp -> megaco_tcp:close(SendHandle); 976 megaco_udp -> megaco_udp:close(SendHandle); 977 SendMod -> exit(Pid, Reason) 978 end. 979 980get_trans_stats(P, SendMod) when is_pid(P) -> 981 case (catch SendMod:get_stats()) of 982 {ok, Stats} -> 983 {SendMod, Stats}; 984 Else -> 985 {SendMod, Else} 986 end; 987get_trans_stats(_P, SendMod) -> 988 {SendMod, undefined}. 989 990mgc_parse_receive_info([], _RH) -> 991 throw({error, no_receive_info}); 992mgc_parse_receive_info(RI, RH) -> 993 mgc_parse_receive_info(RI, RH, []). 994 995mgc_parse_receive_info([], _RH, ListenTo) -> 996 ListenTo; 997mgc_parse_receive_info([RI|RIs], RH, ListenTo) -> 998 d("mgc_parse_receive_info -> parse receive info"), 999 RH1 = mgc_parse_receive_info1(RI, RH), 1000 case (catch mgc_parse_receive_info1(RI, RH)) of 1001 {error, Reason} -> 1002 i("failed parsing receive info: ~p~n~p", [RI, Reason]), 1003 exit({failed_parsing_recv_info, RI, Reason}); 1004 RH1 -> 1005 mgc_parse_receive_info(RIs, RH, [RH1|ListenTo]) 1006 end. 1007 1008mgc_parse_receive_info1(RI, RH) -> 1009 d("mgc_parse_receive_info1 -> get encoding module"), 1010 EM = get_encoding_module(RI), 1011 d("mgc_parse_receive_info1 -> get encoding config"), 1012 EC = get_encoding_config(RI, EM), 1013 d("mgc_parse_receive_info1 -> get transport module"), 1014 TM = get_transport_module(RI), 1015 d("mgc_parse_receive_info1 -> get transport port"), 1016 TP = get_transport_port(RI), 1017 RH1 = RH#megaco_receive_handle{send_mod = TM, 1018 encoding_mod = EM, 1019 encoding_config = EC}, 1020 {TP, RH1}. 1021 1022 1023mgc_start_transports([]) -> 1024 throw({error, no_transport}); 1025mgc_start_transports(ListenTo) -> 1026 mgc_start_transports(ListenTo, undefined, undefined). 1027 1028 1029mgc_start_transports([], TcpSup, UdpSup) -> 1030 {TcpSup, UdpSup}; 1031mgc_start_transports([{Port, RH}|ListenTo], TcpSup, UdpSup) 1032 when RH#megaco_receive_handle.send_mod == megaco_tcp -> 1033 TcpSup1 = mgc_start_tcp(RH, Port, TcpSup), 1034 mgc_start_transports(ListenTo, TcpSup1, UdpSup); 1035mgc_start_transports([{Port, RH}|ListenTo], TcpSup, UdpSup) 1036 when RH#megaco_receive_handle.send_mod == megaco_udp -> 1037 UdpSup1 = mgc_start_udp(RH, Port, UdpSup), 1038 mgc_start_transports(ListenTo, TcpSup, UdpSup1); 1039mgc_start_transports([{_Port, RH}|_ListenTo], _TcpSup, _UdpSup) -> 1040 throw({error, {bad_send_mod, RH#megaco_receive_handle.send_mod}}). 1041 1042 1043mgc_start_tcp(RH, Port, undefined) -> 1044 i("start tcp transport"), 1045 case megaco_tcp:start_transport() of 1046 {ok, Sup} -> 1047 mgc_start_tcp(RH, Port, Sup); 1048 Else -> 1049 throw({error, {failed_starting_tcp_transport, Else}}) 1050 end; 1051mgc_start_tcp(RH, Port, Sup) when is_pid(Sup) -> 1052 i("tcp listen on ~p", [Port]), 1053 Opts = [{port, Port}, 1054 {receive_handle, RH}, 1055 {tcp_options, [{nodelay, true}]}], 1056 mgc_tcp_create_listen(Sup, Opts, 3). 1057 1058mgc_tcp_create_listen(Sup, Opts, N) -> 1059 mgc_tcp_create_listen(Sup, Opts, N, 1, undefined). 1060 1061mgc_tcp_create_listen(_Sup, _Opts, N, N, InitialReason) -> 1062 d("failed creating mgc tcp listen socket after ~p tries: ~p", 1063 [N, InitialReason]), 1064 throw({error, {failed_starting_tcp_listen, InitialReason}}); 1065mgc_tcp_create_listen(Sup, Opts, MaxN, N, _InitialReason) 1066 when is_integer(N) andalso is_integer(MaxN) andalso (MaxN > N) -> 1067 d("try create mgc tcp listen socket [~w]", [N]), 1068 case megaco_tcp:listen(Sup, Opts) of 1069 ok -> 1070 Sup; 1071 {error, {could_not_start_listener, {gen_tcp_listen, eaddrinuse} = Reason}} -> 1072 ?SLEEP(N * 200), 1073 mgc_tcp_create_listen(Sup, Opts, MaxN, N + 1, Reason); 1074 {error, Reason} -> 1075 throw({error, {failed_starting_tcp_listen, Reason}}); 1076 Else -> 1077 throw({error, {failed_starting_tcp_listen, Else}}) 1078 end. 1079 1080 1081mgc_start_udp(RH, Port, undefined) -> 1082 i("start udp transport"), 1083 case megaco_udp:start_transport() of 1084 {ok, Sup} -> 1085 mgc_start_udp(RH, Port, Sup); 1086 Else -> 1087 throw({error, {failed_starting_udp_transport, Else}}) 1088 end; 1089mgc_start_udp(RH, Port, Sup) -> 1090 i("open udp ~p", [Port]), 1091 Opts = [{port, Port}, {receive_handle, RH}], 1092 case megaco_udp:open(Sup, Opts) of 1093 {ok, _SendHandle, _ControlPid} -> 1094 Sup; 1095 Else -> 1096 exit({error, {failed_starting_udp_listen, Else}}) 1097 end. 1098 1099 1100 1101%% ----------------------- 1102%% Handle megaco callbacks 1103%% 1104 1105mgc_handle_request({handle_connect, _CH, _PV}) -> 1106 ok; 1107mgc_handle_request({handle_disconnect, CH, _PV, R}) -> 1108 megaco:cancel(CH, R), % Cancel the outstanding messages 1109 ok; 1110mgc_handle_request({handle_syntax_error, _RH, _PV, _ED}) -> 1111 reply; 1112mgc_handle_request({handle_message_error, _CH, _PV, _ED}) -> 1113 no_reply; 1114mgc_handle_request({handle_trans_request, CH, PV, ARs}) -> 1115 ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented, 1116 errorText = "Only single service change on null context handled"}, 1117 case ARs of 1118 [AR] -> 1119 ContextId = AR#'ActionRequest'.contextId, 1120 case AR#'ActionRequest'.commandRequests of 1121 [CR] when ContextId == ?megaco_null_context_id -> 1122 case CR#'CommandRequest'.command of 1123 {serviceChangeReq, Req} -> 1124 Rep = mgc_service_change(CH, PV, Req), 1125 CmdRep = [{serviceChangeReply, Rep}], 1126 {discard_ack, 1127 [#'ActionReply'{contextId = ContextId, 1128 commandReply = CmdRep}]}; 1129 _ -> 1130 {discard_ack, ED} 1131 end; 1132 _ -> 1133 {discard_ack, ED} 1134 end; 1135 _ -> 1136 {discard_ack, ED} 1137 end; 1138mgc_handle_request({handle_trans_long_request, _CH, _PV, _RD}) -> 1139 ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented, 1140 errorText = "Long transaction requests not handled"}, 1141 {discard_ack, ED}; 1142mgc_handle_request({handle_trans_reply, _CH, _PV, _AR, _RD}) -> 1143 ok; 1144mgc_handle_request({handle_trans_ack, _CH, _PV, _AS, _AD}) -> 1145 ok. 1146 1147mgc_service_change(CH, _PV, SCR) -> 1148 SCP = SCR#'ServiceChangeRequest'.serviceChangeParms, 1149 #'ServiceChangeParm'{serviceChangeAddress = Address, 1150 serviceChangeProfile = Profile, 1151 serviceChangeReason = [_Reason]} = SCP, 1152 TermId = SCR#'ServiceChangeRequest'.terminationID, 1153 if 1154 TermId == [?megaco_root_termination_id] -> 1155 MyMid = CH#megaco_conn_handle.local_mid, 1156 Res = {serviceChangeResParms, 1157 #'ServiceChangeResParm'{serviceChangeMgcId = MyMid, 1158 serviceChangeAddress = Address, 1159 serviceChangeProfile = Profile}}, 1160 #'ServiceChangeReply'{terminationID = TermId, 1161 serviceChangeResult = Res}; 1162 true -> 1163 Res = {errorDescriptor, 1164 #'ErrorDescriptor'{errorCode = ?megaco_not_implemented, 1165 errorText = "Only handled for root"}}, 1166 1167 #'ServiceChangeReply'{terminationID = TermId, 1168 serviceChangeResult = Res} 1169 end. 1170 1171 1172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1173 1174start_mg(Node, Mid, Encoding, Transport, Verbosity) -> 1175 d("start mg[~p]: ~p", [Node, Mid]), 1176 RI1 = 1177 case Encoding of 1178 text -> 1179 [{encoding_module, megaco_pretty_text_encoder}, 1180 {encoding_config, []}, 1181 {port,2944}]; 1182 binary -> 1183 [{encoding_module, megaco_ber_encoder}, 1184 {encoding_config, []}, 1185 {port,2945}] 1186 end, 1187 RI2 = 1188 case Transport of 1189 tcp -> 1190 [{transport_module, megaco_tcp}]; 1191 udp -> 1192 [{transport_module, megaco_udp}] 1193 end, 1194 RI = {receive_info, RI1 ++ RI2}, 1195 Config = [{local_mid, Mid}, RI], 1196 Pid = spawn_link(Node, ?MODULE, mg, [self(), Verbosity, Config]), 1197 await_started(Pid). 1198 1199 1200mg(Parent, Verbosity, Config) -> 1201 process_flag(trap_exit, true), 1202 put(verbosity, Verbosity), 1203 put(sname, "MG"), 1204 i("mg -> starting"), 1205 {Mid, ConnHandle} = mg_init(Config), 1206 notify_started(Parent), 1207 S = #mg{parent = Parent, mid = Mid, conn_handle = ConnHandle}, 1208 i("mg -> started"), 1209 mg_loop(S). 1210 1211mg_init(Config) -> 1212 d("mg_init -> entry"), 1213 Mid = get_conf(local_mid, Config), 1214 RI = get_conf(receive_info, Config), 1215 i("mg_init -> start megaco"), 1216 application:start(megaco), 1217 d("mg_init -> start megaco user"), 1218 megaco:start_user(Mid, []), 1219 d("mg_init -> update user info (user_mod)"), 1220 megaco:update_user_info(Mid, user_mod, ?MODULE), 1221 d("mg_init -> update user info (user_args)"), 1222 megaco:update_user_info(Mid, user_args, [self()]), 1223 d("mg_init -> get user info (receive_handle)"), 1224 RH = megaco:user_info(Mid,receive_handle), 1225 d("mg_init -> parse receive info"), 1226 {MgcPort,RH1} = mg_parse_receive_info(RI, RH), 1227 i("mg_init -> start transport(s)"), 1228 ConnHandle = mg_start_transport(MgcPort, RH1), 1229 {Mid, ConnHandle}. 1230 1231mg_loop(#mg{state = State} = S) -> 1232 d("mg_loop(~p) -> await request", [State]), 1233 receive 1234 {stop, Parent} when S#mg.parent == Parent -> 1235 i("mg_loop(~p) -> stopping", [State]), 1236 mg_close_conn(S#mg.conn_handle), 1237 megaco:stop_user(S#mg.mid), 1238 application:stop(megaco), 1239 i("mg_loop(~p) -> stopped", [State]), 1240 Parent ! {stopped, self()}, 1241 exit(normal); 1242 1243 1244 {reset_stats, Parent} when S#mg.parent == Parent -> 1245 i("mg_loop(~p) -> got request to reset stats counters", [State]), 1246 %% mg_reset_stats(S#mgc.conn_handle), 1247 mg_reset_stats(S#mg.conn_handle), 1248 Parent ! {reset_stats_ack, self()}, 1249 mg_loop(S); 1250 1251 1252 1253 %% Give me statistics 1254 {statistics, 1, Parent} when S#mg.parent == Parent -> 1255 i("mg_loop(~p) -> got request for statistics 1", [State]), 1256 {ok, Gen} = megaco:get_stats(), 1257 CH = S#mg.conn_handle, 1258 Reason = {statistics, CH}, 1259 Pid = megaco:conn_info(CH, control_pid), 1260 SendMod = megaco:conn_info(CH, send_mod), 1261 SendHandle = megaco:conn_info(CH, send_handle), 1262 {ok, Trans} = 1263 case SendMod of 1264 megaco_tcp -> megaco_tcp:get_stats(SendHandle); 1265 megaco_udp -> megaco_udp:get_stats(SendHandle); 1266 SendMod -> exit(Pid, Reason) 1267 end, 1268 Parent ! {statistics, 1, [{gen, Gen}, {trans, Trans}], self()}, 1269 mg_loop(S); 1270 1271 1272 %% Do a service change 1273 {service_change, Parent} when S#mg.parent == Parent, 1274 State == initiated -> 1275 i("mg_loop(~p) -> received request to perform service change when:" 1276 "~n Conn Handle: ~p" 1277 "~n Conn Data: ~p", 1278 [State, 1279 S#mg.conn_handle, 1280 megaco:conn_info(S#mg.conn_handle, conn_data)]), 1281 Res = mg_service_change(S#mg.conn_handle), 1282 d("mg_loop(~p) -> service change request send result: ~p", 1283 [State, Res]), 1284 mg_loop(S#mg{state = connecting}); 1285 1286 1287 %% Apply some load 1288 {apply_load, Parent, Times} when S#mg.parent == Parent -> 1289 i("mg_loop(~p) -> received apply_load request", [State]), 1290 apply_load_timer(), 1291 Parent ! {apply_load_ack, self()}, 1292 mg_loop(S#mg{load_counter = Times - 1}); 1293 1294 1295 apply_load_timeout -> 1296 d("mg_loop(~p) -> received apply_load timeout [~p]", 1297 [State, S#mg.load_counter]), 1298 mg_apply_load(S), 1299 mg_loop(S); 1300 1301 1302 %% Megaco callback messages 1303 {request, Request, From} -> 1304 d("mg_loop(~p) -> received megaco request: ~n~p~n From: ~p", 1305 [State, Request, From]), 1306 {Reply, NewS} = mg_handle_request(Request, S), 1307 d("mg_loop(~p) -> send request reply: ~n~p", 1308 [NewS#mg.state, Reply]), 1309 From ! {reply, Reply, self()}, 1310 mg_loop(NewS); 1311 1312 1313 {'EXIT', Pid, Reason} -> 1314 error_msg("MG ~p received unexpected exit signal from ~p:~n~p", 1315 [S#mg.mid, Pid, Reason]), 1316 mg_loop(S); 1317 1318 1319 Invalid -> 1320 i("mg_loop(~p) -> received invalid request: ~p", [State, Invalid]), 1321 mg_loop(S) 1322 1323 end. 1324 1325 1326mg_reset_stats(CH) -> 1327 megaco:reset_stats(), 1328 case (catch megaco:conn_info(CH, send_mod)) of 1329 {error, Reason} -> 1330 error_msg("unexpected result when retrieving send module for " 1331 "own connection ~p: ~p. " 1332 "~nexiting...", [CH, Reason]), 1333 exit({invalid_connection, CH, Reason}); 1334 {'EXIT', Reason} -> 1335 error_msg("exit signal when retrieving send module for " 1336 "own connection ~p: ~p. " 1337 "~nexiting...", [CH, Reason]), 1338 exit({invalid_connection, CH, Reason}); 1339 SendMod when is_atom(SendMod) -> 1340 SendMod:reset_stats() 1341 end. 1342 1343 1344mg_close_conn(CH) -> 1345 Reason = {self(), ignore}, 1346 Pid = megaco:conn_info(CH, control_pid), 1347 SendMod = megaco:conn_info(CH, send_mod), 1348 SendHandle = megaco:conn_info(CH, send_handle), 1349 megaco:disconnect(CH, Reason), 1350 case SendMod of 1351 megaco_tcp -> megaco_tcp:close(SendHandle); 1352 megaco_udp -> megaco_udp:close(SendHandle); 1353 SendMod -> exit(Pid, Reason) 1354 end. 1355 1356 1357mg_parse_receive_info(RI, RH) -> 1358 d("mg_parse_receive_info -> get encoding module"), 1359 EM = get_encoding_module(RI), 1360 d("mg_parse_receive_info -> get encoding config"), 1361 EC = get_encoding_config(RI, EM), 1362 d("mg_parse_receive_info -> get transport module"), 1363 TM = get_transport_module(RI), 1364 d("mg_parse_receive_info -> get transport port"), 1365 TP = get_transport_port(RI), 1366 RH1 = RH#megaco_receive_handle{send_mod = TM, 1367 encoding_mod = EM, 1368 encoding_config = EC}, 1369 {TP, RH1}. 1370 1371 1372mg_start_transport(MgcPort, 1373 #megaco_receive_handle{send_mod = megaco_tcp} = RH) -> 1374 mg_start_tcp(MgcPort,RH); 1375mg_start_transport(MgcPort, 1376 #megaco_receive_handle{send_mod = megaco_udp} = RH) -> 1377 mg_start_udp(MgcPort,RH); 1378mg_start_transport(_, #megaco_receive_handle{send_mod = Mod}) -> 1379 throw({error, {bad_send_mod, Mod}}). 1380 1381 1382mg_start_tcp(MgcPort, RH) -> 1383 i("start tcp transport"), 1384 case megaco_tcp:start_transport() of 1385 {ok, Sup} -> 1386 {ok, LocalHost} = inet:gethostname(), 1387 Opts = [{host, LocalHost}, 1388 {port, MgcPort}, 1389 {receive_handle, RH}, 1390 {tcp_options, [{nodelay, true}]}], 1391 i("tcp transport started: attempt (tcp) connect to MGC at:" 1392 "~n ~p", [LocalHost]), 1393 case megaco_tcp:connect(Sup, Opts) of 1394 {ok, SendHandle, ControlPid} -> 1395 PrelMgcMid = preliminary_mid, 1396 i("tcp transport (tcp) connected: attempt (megaco) connect:"), 1397 {ok, ConnHandle} = 1398 megaco:connect(RH, PrelMgcMid, 1399 SendHandle, ControlPid), 1400 ConnHandle; 1401 {error, Reason} -> 1402 {error, {megaco_tcp_connect, Reason}} 1403 end; 1404 {error, Reason} -> 1405 {error, {megaco_tcp_start_transport, Reason}} 1406 end. 1407 1408 1409mg_start_udp(MgcPort, RH) -> 1410 i("start udp transport"), 1411 case megaco_udp:start_transport() of 1412 {ok, Sup} -> 1413 %% Some linux (Ubuntu) has "crap" in their /etc/hosts, that 1414 %% causes problem for us in this case (UDP). So we can't use 1415 %% local host. Try instead to "figure out" tha actual address... 1416 LocalAddr = which_local_addr(), 1417 Opts = [{port, 0}, {receive_handle, RH}], 1418 i("udp transport started: attempt (udp) open"), 1419 case megaco_udp:open(Sup, Opts) of 1420 {ok, Handle, ControlPid} -> 1421 MgcMid = preliminary_mid, 1422 i("udp transport open: " 1423 "now create send handle with MGC address: " 1424 "~n ~p", [LocalAddr]), 1425 SendHandle = megaco_udp:create_send_handle(Handle, 1426 LocalAddr, 1427 MgcPort), 1428 i("udp transport: attempt (megaco) connect to:" 1429 "~n ~p", [SendHandle]), 1430 {ok, ConnHandle} = 1431 megaco:connect(RH, MgcMid, 1432 SendHandle, ControlPid), 1433 ConnHandle; 1434 {error, Reason} -> 1435 {error, {megaco_udp_open, Reason}} 1436 end; 1437 {error, Reason} -> 1438 {error, {megaco_udp_start_transport, Reason}} 1439 end. 1440 1441 1442mg_service_change(ConnHandle) -> 1443 mg_service_change(ConnHandle, restart, ?megaco_cold_boot). 1444 1445mg_service_change(ConnHandle, Method, Reason) -> 1446 SCP = #'ServiceChangeParm'{serviceChangeMethod = Method, 1447 serviceChangeReason = [Reason]}, 1448 TermId = [?megaco_root_termination_id], 1449 SCR = #'ServiceChangeRequest'{terminationID = TermId, 1450 serviceChangeParms = SCP}, 1451 CR = #'CommandRequest'{command = {serviceChangeReq, SCR}}, 1452 AR = #'ActionRequest'{contextId = ?megaco_null_context_id, 1453 commandRequests = [CR]}, 1454 megaco:cast(ConnHandle, [AR], []). 1455 1456 1457mg_notify_request(CH) -> 1458 TimeStamp = cre_timeNotation("19990729", "22000000"), 1459 Event = cre_observedEvent("al/of",TimeStamp), 1460 Desc = cre_observedEventsDesc(2222,[Event]), 1461 NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A4444}],Desc), 1462 CmdReq = cre_commandReq({notifyReq, NotifyReq}), 1463 ActReq = cre_actionReq(?megaco_null_context_id, [CmdReq]), 1464 megaco:cast(CH, [ActReq], [{reply_data, Desc}]). 1465 1466mg_apply_load(#mg{conn_handle = CH}) -> 1467 mg_notify_request(CH). 1468 1469 1470cre_actionReq(Cid, Cmds) -> 1471 #'ActionRequest'{contextId = Cid, 1472 commandRequests = Cmds}. 1473 1474cre_commandReq(Cmd) -> 1475 #'CommandRequest'{command = Cmd}. 1476 1477cre_notifyReq(Tid, EvsDesc) -> 1478 #'NotifyRequest'{terminationID = Tid, observedEventsDescriptor = EvsDesc}. 1479 1480cre_observedEventsDesc(Id, EvList) -> 1481 #'ObservedEventsDescriptor'{requestId = Id, observedEventLst = EvList}. 1482 1483cre_observedEvent(Name, Not) -> 1484 #'ObservedEvent'{eventName = Name, timeNotation = Not}. 1485 1486cre_timeNotation(D,T) -> 1487 #'TimeNotation'{date = D, time = T}. 1488 1489%% ----------------------- 1490%% Handle megaco callbacks 1491%% 1492 1493mg_handle_request({handle_connect, CH, _PV}, 1494 #mg{state = connecting} = S) -> 1495 {ok, S#mg{conn_handle = CH}}; 1496 1497mg_handle_request({handle_disconnect, CH, _PV, _R}, S) -> 1498 {ok, S#mg{conn_handle = CH}}; 1499 1500mg_handle_request({handle_syntax_error, _RH, _PV, _ED}, S) -> 1501 {reply, S}; 1502 1503mg_handle_request({handle_message_error, CH, _PV, _ED}, S) -> 1504 {no_reply, S#mg{conn_handle = CH}}; 1505 1506mg_handle_request({handle_trans_request, CH, _PV, _AR}, S) -> 1507 ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented, 1508 errorText = "Transaction requests not handled"}, 1509 {{discard_ack, ED}, S#mg{conn_handle = CH}}; 1510 1511mg_handle_request({handle_trans_long_request, CH, _PV, _RD}, S) -> 1512 ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented, 1513 errorText = "Long transaction requests not handled"}, 1514 {{discard_ack, ED}, S#mg{conn_handle = CH}}; 1515 1516mg_handle_request({handle_trans_reply, CH, _PV, _AR, _RD}, 1517 #mg{parent = Pid, state = connecting} = S) -> 1518 %% Should really check this... 1519 Pid ! {service_change_reply, ok, self()}, 1520 {ok, S#mg{conn_handle = CH, state = connected}}; 1521mg_handle_request({handle_trans_reply, _CH, _PV, {error, ED}, RD}, 1522 #mg{parent = Pid, load_counter = 0} = S) 1523 when is_record(ED, 'ErrorDescriptor') andalso 1524 is_record(RD, 'ObservedEventsDescriptor') -> 1525 Pid ! {load_complete, self()}, 1526 {ok, S}; 1527mg_handle_request({handle_trans_reply, _CH, _PV, {error, ED}, RD}, 1528 #mg{load_counter = N} = S) 1529 when is_record(ED, 'ErrorDescriptor') andalso 1530 is_record(RD, 'ObservedEventsDescriptor') -> 1531 apply_load_timer(), 1532 {ok, S#mg{load_counter = N-1}}; 1533 1534mg_handle_request({handle_trans_ack, _CH, _PV, _AS, _AD}, S) -> 1535 {ok, S}. 1536 1537 1538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1539 1540await_started(Pid) -> 1541 receive 1542 {started, Pid} -> 1543 d("await_started ~p: ok", [Pid]), 1544 {ok, Pid}; 1545 {'EXIT', Pid, Reason} -> 1546 i("await_started ~p: received exit signal: ~p", [Pid, Reason]), 1547 exit({failed_starting, Pid, Reason}) 1548 after 10000 -> 1549 i("await_started ~p: timeout", [Pid]), 1550 exit({error, timeout}) 1551 end. 1552 1553stop(Pid) -> 1554 d("stop ~p", [Pid]), 1555 Pid ! {stop, self()}, 1556 receive 1557 {stopped, Pid} -> 1558 d("stop -> received stopped from ~p", [Pid]), 1559 ok; 1560 {'EXIT', Pid, Reason} -> 1561 i("stop ~p: received exit signal: ~p", [Pid, Reason]), 1562 exit({failed_stopping, Pid, Reason}) 1563 after 10000 -> 1564 exit({error, timeout}) 1565 end. 1566 1567get_stats(Pid, No) -> 1568 d("get_stats ~p", [Pid]), 1569 Pid ! {statistics, No, self()}, 1570 receive 1571 {statistics, No, Stats, Pid} -> 1572 {ok, Stats}; 1573 {'EXIT', Pid, Reason} -> 1574 i("get_stats ~p: received exit signal: ~p", [Pid, Reason]), 1575 exit({failed_getting_stats, Pid, Reason}) 1576 after 10000 -> 1577 exit({error, timeout}) 1578 end. 1579 1580service_change(Pid) -> 1581 d("service_change ~p", [Pid]), 1582 Pid ! {service_change, self()}, 1583 receive 1584 {service_change_reply, Res, Pid} -> 1585 {ok, Res}; 1586 {'EXIT', Pid, Reason} -> 1587 i("service_change ~p: received exit signal: ~p", [Pid, Reason]), 1588 exit({failed_service_change, Pid, Reason}) 1589 after 10000 -> 1590 exit({error, timeout}) 1591 end. 1592 1593 1594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1595 1596notify_started(Parent) -> 1597 Parent ! {started, self()}. 1598 1599 1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1601 1602%% The megaco user callback interface 1603 1604handle_connect(CH, PV, Pid) -> 1605% i("handle_connect -> entry with" 1606% "~n CH: ~p" 1607% "~n PV: ~p" 1608% "~n Pid: ~p", [CH, PV, Pid]), 1609 case CH#megaco_conn_handle.remote_mid of 1610 preliminary_mid -> 1611 %% Avoids deadlock 1612 ok; 1613 _ -> 1614 Reply = request(Pid, {handle_connect, CH, PV}), 1615% d("handle_connect -> Reply:~n~p", [Reply]), 1616 Reply 1617 end. 1618 1619handle_disconnect(_CH, _PV, 1620 {user_disconnect, {Pid, ignore}}, 1621 Pid) -> 1622% i("handle_disconnect(ignore) -> entry with" 1623% "~n CH: ~p" 1624% "~n PV: ~p", [CH, PV]), 1625 %% Avoids deadlock 1626 ok; 1627handle_disconnect(CH, PV, R, Pid) -> 1628% i("handle_disconnect -> entry with" 1629% "~n CH: ~p" 1630% "~n PV: ~p" 1631% "~n R: ~p", [CH, PV, R]), 1632 request(Pid, {handle_disconnect, CH, PV, R}). 1633 1634handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Pid) -> 1635% i("handle_syntax_error -> entry with" 1636% "~n ReceiveHandle: ~p" 1637% "~n ProtocolVersion: ~p" 1638% "~n ErrorDescriptor: ~p", 1639% [ReceiveHandle, ProtocolVersion, ErrorDescriptor]), 1640 Req = {handle_syntax_error, ReceiveHandle, ProtocolVersion, 1641 ErrorDescriptor}, 1642 request(Pid, Req). 1643 1644handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) -> 1645% i("handle_message_error -> entry with" 1646% "~n ConnHandle: ~p" 1647% "~n ProtocolVersion: ~p" 1648% "~n ErrorDescriptor: ~p", 1649% [ConnHandle, ProtocolVersion, ErrorDescriptor]), 1650 Req = {handle_message_error, ConnHandle, ProtocolVersion, ErrorDescriptor}, 1651 request(Pid, Req). 1652 1653handle_trans_request(CH, PV, AR, Pid) -> 1654% i("handle_trans_request -> entry with" 1655% "~n CH: ~p" 1656% "~n PV: ~p" 1657% "~n AR: ~p" 1658% "~n Pid: ~p", [CH, PV, AR, Pid]), 1659 Reply = request(Pid, {handle_trans_request, CH, PV, AR}), 1660% i("handle_trans_request -> Reply:~n~p", [Reply]), 1661 Reply. 1662 1663handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Pid) -> 1664% i("handle_trans_long_request -> entry with" 1665% "~n ConnHandle: ~p" 1666% "~n ProtocolVersion: ~p" 1667% "~n ReqData: ~p", [ConnHandle, ProtocolVersion, ReqData]), 1668 Req = {handle_trans_long_request, ConnHandle, ProtocolVersion, ReqData}, 1669 request(Pid, Req). 1670 1671handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData, Pid) -> 1672% i("handle_trans_reply -> entry with" 1673% "~n ConnHandle: ~p" 1674% "~n ProtocolVersion: ~p" 1675% "~n ActualReply: ~p" 1676% "~n ReplyData: ~p", 1677% [ConnHandle, ProtocolVersion, ActualReply, ReplyData]), 1678 Req = {handle_trans_reply, ConnHandle, ProtocolVersion, 1679 ActualReply, ReplyData}, 1680 request(Pid, Req). 1681 1682handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Pid) -> 1683% i("handle_trans_ack -> entry with" 1684% "~n ConnHandle: ~p" 1685% "~n ProtocolVersion: ~p" 1686% "~n AckStatus: ~p" 1687% "~n AckData: ~p", 1688% [ConnHandle, ProtocolVersion, AckStatus, AckData]), 1689 Req = {handle_trans_ack, ConnHandle, ProtocolVersion, AckStatus, AckData}, 1690 request(Pid, Req). 1691 1692 1693request(Pid, Request) -> 1694 Pid ! {request, Request, self()}, 1695 receive 1696 {reply, Reply, Pid} -> 1697 Reply 1698 end. 1699 1700 1701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1702 1703error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A). 1704 1705 1706get_encoding_module(RI) -> 1707 case (catch get_conf(encoding_module, RI)) of 1708 {error, _} -> 1709 undefined; 1710 Val -> 1711 Val 1712 end. 1713 1714get_encoding_config(RI, EM) -> 1715 case text_codec(EM) of 1716 true -> 1717 case megaco:system_info(text_config) of 1718 [Conf] when is_list(Conf) -> 1719 Conf; 1720 _ -> 1721 [] 1722 end; 1723 1724 false -> 1725 get_conf(encoding_config, RI) 1726 end. 1727 1728text_codec(megaco_compact_text_encoder) -> 1729 true; 1730text_codec(megaco_pretty_text_encoder) -> 1731 true; 1732text_codec(_) -> 1733 false. 1734 1735 1736get_transport_module(RI) -> 1737 get_conf(transport_module, RI). 1738 1739get_transport_port(RI) -> 1740 get_conf(port, RI). 1741 1742 1743get_conf(Key, Config) -> 1744 case lists:keysearch(Key, 1, Config) of 1745 {value, {Key, Val}} -> 1746 Val; 1747 _ -> 1748 exit({error, {not_found, Key, Config}}) 1749 end. 1750 1751 1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1753 1754%% Tries to find a valid local address... 1755which_local_addr() -> 1756 case inet:getifaddrs() of 1757 {ok, IFs} -> 1758 which_local_addr(IFs); 1759 {error, Reason} -> 1760 i("Failed get local address: " 1761 "~n ~p", [Reason]), 1762 ?SKIP({failed_get_local_addr, Reason}) 1763 end. 1764 1765%% We explicitly skip some interfaces that we know is not "valid" 1766%% (docker stuff) 1767which_local_addr([]) -> 1768 ?SKIP(failed_get_local_addr); 1769which_local_addr([{"br-" ++ _ = _IfName, _IfOpts}|IFs]) -> 1770 which_local_addr(IFs); 1771which_local_addr([{"docker" ++ _ = _IfName, _IfOpts}|IFs]) -> 1772 which_local_addr(IFs); 1773which_local_addr([{_IfName, IfOpts}|IFs]) -> 1774 case which_local_addr2(IfOpts) of 1775 {ok, Addr} -> 1776 Addr; 1777 error -> 1778 which_local_addr(IFs) 1779 end. 1780 1781which_local_addr2(IfOpts) -> 1782 case if_is_running(IfOpts) of 1783 true -> 1784 which_local_addr3(IfOpts); 1785 false -> 1786 error 1787 end. 1788 1789if_is_running(If) -> 1790 lists:keymember(flags, 1, If) andalso 1791 begin 1792 {value, {flags, Flags}} = lists:keysearch(flags, 1, If), 1793 (not lists:member(loopback, Flags)) andalso lists:member(running, Flags) 1794 end. 1795 1796which_local_addr3([]) -> 1797 error; 1798which_local_addr3([{addr, Addr}|_]) 1799 when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) -> 1800 {ok, Addr}; 1801which_local_addr3([_|T]) -> 1802 which_local_addr3(T). 1803 1804 1805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1806 1807try_tc(TCName, Pre, Case, Post) -> 1808 try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post). 1809 1810try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> 1811 ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post). 1812 1813 1814 1815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1816 1817%% p(F) -> 1818%% p(F, []). 1819 1820p(F, A) -> 1821 p(get(sname), F, A). 1822 1823p(S, F, A) when is_list(S) -> 1824 io:format("*** [~s] ~p ~s ***" 1825 "~n " ++ F ++ "~n", 1826 [?FTS(), self(), S | A]); 1827p(_S, F, A) -> 1828 io:format("*** [~s] ~p *** " 1829 "~n " ++ F ++ "~n", 1830 [?FTS(), self() | A]). 1831 1832 1833i(F) -> 1834 i(F, []). 1835 1836i(F, A) -> 1837 print(info, get(verbosity), "", F, A). 1838 1839 1840d(F) -> 1841 d(F, []). 1842 1843d(F, A) -> 1844 print(debug, get(verbosity), "DBG: ", F, A). 1845 1846 1847printable(_, debug) -> true; 1848printable(info, info) -> true; 1849printable(_,_) -> false. 1850 1851print(Severity, Verbosity, P, F, A) -> 1852 print(printable(Severity,Verbosity), P, F, A). 1853 1854print(true, P, F, A) -> 1855 io:format("~s~p:~s:~s: " ++ F ++ "~n", [P, self(), get(sname), ?FTS() | A]); 1856print(_, _, _, _) -> 1857 ok. 1858 1859 1860progress(F) -> 1861 progress(F, []). 1862 1863progress(F, A) -> 1864 io:format("~s " ++ F ++ "~n", [?FTS()|A]), 1865 io:format(user, "~s " ++ F ++ "~n", [?FTS()|A]). 1866 1867 1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1869 1870random() -> 1871 10 * rand:uniform(50). 1872 1873apply_load_timer() -> 1874 erlang:send_after(random(), self(), apply_load_timeout). 1875 1876