1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2016. 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: Handle configuration of Megaco/H.248 24%%---------------------------------------------------------------------- 25 26-module(megaco_config). 27 28-behaviour(gen_server). 29 30%% Application internal exports 31-export([ 32 start_link/0, 33 stop/0, 34 35 start_user/2, 36 stop_user/1, 37 38 user_info/2, 39 update_user_info/3, 40 conn_info/2, 41 update_conn_info/3, 42 system_info/1, 43 44 %% incr_counter/2, 45 incr_trans_id_counter/1, 46 incr_trans_id_counter/2, 47 48 %% Verification functions 49 verify_val/2, 50%% verify_strict_uint/1, 51%% verify_strict_int/1, verify_strict_int/2, 52%% verify_uint/1, 53%% verify_int/1, verify_int/2, 54 55 56 %% Reply limit counter 57 cre_reply_counter/2, 58 get_reply_counter/2, 59 incr_reply_counter/2, 60 del_reply_counter/2, 61 62 %% Pending limit counter 63 cre_pending_counter/3, 64 get_pending_counter/2, 65 incr_pending_counter/2, 66 del_pending_counter/2, 67 %% Backward compatibillity functions (to be removed in later versions) 68 cre_pending_counter/1, 69 get_pending_counter/1, 70 incr_pending_counter/1, 71 del_pending_counter/1, 72 73 lookup_local_conn/1, 74 connect/4, finish_connect/4, 75 autoconnect/4, 76 disconnect/1, 77 connect_remote/3, 78 disconnect_remote/2, 79 init_conn_data/4, 80 81 trans_sender_exit/2 82 83 ]). 84 85 86%% gen_server callbacks 87-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 88 terminate/2, code_change/3]). 89 90-define(SERVER, ?MODULE). 91-record(state, {parent_pid}). 92 93-include_lib("megaco/include/megaco.hrl"). 94-include_lib("megaco/src/app/megaco_internal.hrl"). 95 96 97-ifdef(MEGACO_TEST_CODE). 98-define(megaco_test_init(), 99 (catch ets:new(megaco_test_data, [set, public, named_table]))). 100-else. 101-define(megaco_test_init(), 102 ok). 103-endif. 104 105-define(TID_CNT(LMID), {LMID, trans_id_counter}). 106 107 108%%%---------------------------------------------------------------------- 109%%% API 110%%%---------------------------------------------------------------------- 111 112start_link() -> 113 ?d("start_link -> entry", []), 114 gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], []). 115 116stop() -> 117 ?d("stop -> entry", []), 118 call({stop, self()}). 119 120start_user(UserMid, Config) -> 121 call({start_user, UserMid, Config}). 122 123stop_user(UserMid) -> 124 call({stop_user, UserMid}). 125 126user_info(UserMid, all) -> 127 All0 = ets:match_object(megaco_config, {{UserMid, '_'}, '_'}), 128 All1 = [{Item, Val} || {{_, Item}, Val} <- All0, Item /= trans_sender], 129 case lists:keysearch(trans_id_counter, 1, All1) of 130 {value, {_, Val}} -> 131 lists:keyreplace(trans_id_counter, 1, All1, {trans_id, Val}); 132 false when UserMid /= default -> 133 [{trans_id, undefined_serial}|All1]; 134 false -> 135 All1 136 end; 137user_info(UserMid, receive_handle) -> 138 case call({receive_handle, UserMid}) of 139 {ok, RH} -> 140 RH; 141 {error, Reason} -> 142 exit(Reason) 143 end; 144user_info(UserMid, conn_data) -> 145 HandlePat = #megaco_conn_handle{local_mid = UserMid, remote_mid = '_'}, 146 Pat = #conn_data{conn_handle = HandlePat, 147 serial = '_', 148 max_serial = '_', 149 request_timer = '_', 150 long_request_timer = '_', 151 152 auto_ack = '_', 153 154 trans_ack = '_', 155 trans_ack_maxcount = '_', 156 157 trans_req = '_', 158 trans_req_maxcount = '_', 159 trans_req_maxsize = '_', 160 161 trans_timer = '_', 162 trans_sender = '_', 163 164 pending_timer = '_', 165 sent_pending_limit = '_', 166 recv_pending_limit = '_', 167 reply_timer = '_', 168 control_pid = '_', 169 monitor_ref = '_', 170 send_mod = '_', 171 send_handle = '_', 172 encoding_mod = '_', 173 encoding_config = '_', 174 protocol_version = '_', 175 auth_data = '_', 176 user_mod = '_', 177 user_args = '_', 178 reply_action = '_', 179 reply_data = '_', 180 threaded = '_', 181 strict_version = '_', 182 long_request_resend = '_', 183 call_proxy_gc_timeout = '_', 184 cancel = '_', 185 resend_indication = '_', 186 segment_reply_ind = '_', 187 segment_recv_acc = '_', 188 segment_recv_timer = '_', 189 segment_send = '_', 190 segment_send_timer = '_', 191 max_pdu_size = '_', 192 request_keep_alive_timeout = '_' 193 }, 194 %% ok = io:format("PATTERN: ~p~n", [Pat]), 195 ets:match_object(megaco_local_conn, Pat); 196user_info(UserMid, connections) -> 197 [C#conn_data.conn_handle || C <- user_info(UserMid, conn_data)]; 198user_info(UserMid, mid) -> 199 ets:lookup_element(megaco_config, {UserMid, mid}, 2); 200user_info(UserMid, orig_pending_limit) -> 201 user_info(UserMid, sent_pending_limit); 202user_info(UserMid, trans_id) -> 203 case (catch user_info(UserMid, trans_id_counter)) of 204 {'EXIT', _} -> 205 %% There is only two cases where this can occure: 206 %% 1) The user does not exist 207 %% 2) Called before the first message is sent, use 208 %% undefined_serial, since there is no 209 %% "current transaction id" 210 case (catch user_info(UserMid, mid)) of 211 {'EXIT', _} -> 212 %% case 1: 213 exit({no_such_user, UserMid}); 214 _ -> 215 undefined_serial 216 end; 217 Else -> 218 Else 219 end; 220user_info(UserMid, Item) -> 221 ets:lookup_element(megaco_config, {UserMid, Item}, 2). 222 223update_user_info(UserMid, orig_pending_limit, Val) -> 224 update_user_info(UserMid, sent_pending_limit, Val); 225update_user_info(UserMid, Item, Val) -> 226 call({update_user_info, UserMid, Item, Val}). 227 228 229conn_info(Data, Item) -> 230 %% The purpose of this is a compiler optimization... 231 %% Args are processed from left to right. 232 do_conn_info(Item, Data). 233 234do_conn_info(mid = _Item, #megaco_conn_handle{local_mid = Mid}) -> 235 Mid; 236do_conn_info(local_mid = _Item, #megaco_conn_handle{local_mid = LMid}) -> 237 LMid; 238do_conn_info(remote_mid = _Item, #megaco_conn_handle{remote_mid = RMid}) -> 239 RMid; 240do_conn_info(conn_handle = _Item, CH) when is_record(CH, megaco_conn_handle) -> 241 CH; 242do_conn_info(conn_data = _Item, CH) when is_record(CH, megaco_conn_handle) -> 243 case lookup_local_conn(CH) of 244 [] -> 245 exit({no_such_connection, CH}); 246 [ConnData] -> 247 ConnData 248 end; 249do_conn_info(Item, CH) when is_record(CH, megaco_conn_handle) -> 250 case lookup_local_conn(CH) of 251 [] -> 252 exit({no_such_connection, CH}); 253 [ConnData] -> 254 do_conn_info(Item, ConnData) 255 end; 256 257do_conn_info(cancel = _Item, #conn_data{conn_handle = CH}) -> 258 %% To minimise raise-condition propabillity, 259 %% we always look in the table instead of 260 %% in the record for this one 261 ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel); 262do_conn_info(cancel = _Item, CH) when is_record(CH, megaco_conn_handle) -> 263 %% To minimise raise-condition propabillity, 264 %% we always look in the table instead of 265 %% in the record for this one 266 ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel); 267 268do_conn_info(all = _Item, 269 #conn_data{conn_handle = CH, 270 serial = TransId, 271 max_serial = MaxTransId, 272 request_timer = ReqTmr, 273 long_request_timer = LongReqTmr, 274 auto_ack = AutoAck, 275 trans_ack = TransAck, 276 trans_ack_maxcount = TransAckMaxCount, 277 trans_req = TransReq, 278 trans_req_maxcount = TransReqMaxCount, 279 trans_req_maxsize = TransReqMaxSz, 280 trans_timer = TransTmr, 281 %% trans_sender, 282 pending_timer = PendingTmr, 283 sent_pending_limit = SentPendingLimit, 284 recv_pending_limit = RecvPendingLimit, 285 reply_timer = ReplyTmr, 286 control_pid = CtrlPid, 287 monitor_ref = MonRef, 288 send_mod = SendMod, 289 send_handle = SendHandle, 290 encoding_mod = EncodingMod, 291 encoding_config = EncodingConf, 292 protocol_version = ProtoVersion, 293 auth_data = AuthData, 294 user_mod = UserMod, 295 user_args = UserArgs, 296 reply_action = ReplyAction, 297 reply_data = ReplyData, 298 threaded = Threaded, 299 strict_version = StrictVersion, 300 long_request_resend = LongReqResend, 301 call_proxy_gc_timeout = CallProxyGCTimeout, 302 %% cancel, 303 resend_indication = ResendInd, 304 segment_reply_ind = SegReplyInd, 305 segment_recv_acc = SegRecvAcc, 306 segment_recv_timer = SegRecvTmr, 307 segment_send = SegSend, 308 segment_send_timer = SegSendTmr, 309 max_pdu_size = MaxPduSz, 310 request_keep_alive_timeout = RequestKeepAliveTmr}) -> 311 [{conn_handle, CH}, 312 {trans_id, TransId}, 313 {max_trans_id, MaxTransId}, 314 {request_timer, ReqTmr}, 315 {long_request_timer, LongReqTmr}, 316 {mid, CH#megaco_conn_handle.local_mid}, 317 {local_mid, CH#megaco_conn_handle.local_mid}, 318 {remote_mid, CH#megaco_conn_handle.remote_mid}, 319 {auto_ack, AutoAck}, 320 {trans_ack, TransAck}, 321 {trans_ack_maxcount, TransAckMaxCount}, 322 {trans_req, TransReq}, 323 {trans_req_maxcount, TransReqMaxCount}, 324 {trans_req_maxsize, TransReqMaxSz}, 325 {trans_timer, TransTmr}, 326 {pending_timer, PendingTmr}, 327 {sent_pending_limit, SentPendingLimit}, 328 {recv_pending_limit, RecvPendingLimit}, 329 {reply_timer, ReplyTmr}, 330 {control_pid, CtrlPid}, 331 {monitor_ref, MonRef}, 332 {send_mod, SendMod}, 333 {send_handle, SendHandle}, 334 {encoding_mod, EncodingMod}, 335 {encoding_config, EncodingConf}, 336 {protocol_version, ProtoVersion}, 337 {auth_data, AuthData}, 338 {user_mod, UserMod}, 339 {user_args, UserArgs}, 340 {reply_action, ReplyAction}, 341 {reply_data, ReplyData}, 342 {threaded, Threaded}, 343 {strict_version, StrictVersion}, 344 {long_request_resend, LongReqResend}, 345 {call_proxy_gc_timeout, CallProxyGCTimeout}, 346 {resend_indication, ResendInd}, 347 {segment_reply_ind, SegReplyInd}, 348 {segment_recv_acc, SegRecvAcc}, 349 {segment_recv_timer, SegRecvTmr}, 350 {segment_send, SegSend}, 351 {segment_send_timer, SegSendTmr}, 352 {max_pdu_size, MaxPduSz}, 353 {request_keep_alive_timeout, RequestKeepAliveTmr}]; 354 355do_conn_info(conn_data = _Item, CD) -> 356 CD; 357do_conn_info(conn_handle = _Item, #conn_data{conn_handle = Val}) -> 358 Val; 359do_conn_info(mid = _Item, 360 #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) -> 361 Val; 362do_conn_info(local_mid = _Item, 363 #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) -> 364 Val; 365do_conn_info(remote_mid = _Item, 366 #conn_data{conn_handle = #megaco_conn_handle{remote_mid = Val}}) -> 367 Val; 368do_conn_info(trans_id = _Item, 369 #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid}, 370 max_serial = Max}) -> 371 Item2 = {LMid, trans_id_counter}, 372 case (catch ets:lookup(megaco_config, Item2)) of 373 {'EXIT', _} -> 374 undefined_serial; 375 [] -> 376 user_info(LMid, min_trans_id); 377 [{_, Serial}] -> 378 if 379 ((Max =:= infinity) andalso 380 is_integer(Serial) andalso 381 (Serial < 4294967295)) -> 382 Serial + 1; 383 ((Max =:= infinity) andalso 384 is_integer(Serial) andalso 385 (Serial =:= 4294967295)) -> 386 user_info(LMid, min_trans_id); 387 Serial < Max -> 388 Serial + 1; 389 Serial =:= Max -> 390 user_info(LMid, min_trans_id); 391 Serial =:= 4294967295 -> 392 user_info(LMid, min_trans_id); 393 true -> 394 undefined_serial 395 end 396 end; 397do_conn_info(max_trans_id = _Item, #conn_data{max_serial = Val}) -> 398 Val; 399do_conn_info(request_timer = _Item, #conn_data{request_timer = Val}) -> 400 Val; 401do_conn_info(long_request_timer = _Item, #conn_data{long_request_timer = Val}) -> 402 Val; 403do_conn_info(auto_ack = _Item, #conn_data{auto_ack = Val}) -> 404 Val; 405do_conn_info(trans_ack = _Item, #conn_data{trans_ack = Val}) -> 406 Val; 407do_conn_info(trans_ack_maxcount = _Item, #conn_data{trans_ack_maxcount = Val}) -> 408 Val; 409do_conn_info(trans_req = _Item, #conn_data{trans_req = Val}) -> 410 Val; 411do_conn_info(trans_req_maxcount = _Item, #conn_data{trans_req_maxcount = Val}) -> 412 Val; 413do_conn_info(trans_req_maxsize = _Item, #conn_data{trans_req_maxsize = Val}) -> 414 Val; 415do_conn_info(trans_timer = _Item, #conn_data{trans_timer = Val}) -> 416 Val; 417do_conn_info(pending_timer = _Item, #conn_data{pending_timer = Val}) -> 418 Val; 419do_conn_info(orig_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) -> 420 Val; 421do_conn_info(sent_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) -> 422 Val; 423do_conn_info(recv_pending_limit = _Item, #conn_data{recv_pending_limit = Val}) -> 424 Val; 425do_conn_info(reply_timer = _Item, #conn_data{reply_timer = Val}) -> 426 Val; 427do_conn_info(control_pid = _Item, #conn_data{control_pid = Val}) -> 428 Val; 429do_conn_info(send_mod = _Item, #conn_data{send_mod = Val}) -> 430 Val; 431do_conn_info(send_handle = _Item, #conn_data{send_handle = Val}) -> 432 Val; 433do_conn_info(encoding_mod = _Item, #conn_data{encoding_mod = Val}) -> 434 Val; 435do_conn_info(encoding_config = _Item, #conn_data{encoding_config = Val}) -> 436 Val; 437do_conn_info(protocol_version = _Item, #conn_data{protocol_version = Val}) -> 438 Val; 439do_conn_info(auth_data = _Item, #conn_data{auth_data = Val}) -> 440 Val; 441do_conn_info(user_mod = _Item, #conn_data{user_mod = Val}) -> 442 Val; 443do_conn_info(user_args = _Item, #conn_data{user_args = Val}) -> 444 Val; 445do_conn_info(reply_action = _Item, #conn_data{reply_action = Val}) -> 446 Val; 447do_conn_info(reply_data = _Item, #conn_data{reply_data = Val}) -> 448 Val; 449do_conn_info(threaded = _Item, #conn_data{threaded = Val}) -> 450 Val; 451do_conn_info(strict_version = _Item, #conn_data{strict_version = Val}) -> 452 Val; 453do_conn_info(long_request_resend = _Item, 454 #conn_data{long_request_resend = Val}) -> 455 Val; 456do_conn_info(call_proxy_gc_timeout = _Item, 457 #conn_data{call_proxy_gc_timeout = Val}) -> 458 Val; 459do_conn_info(resend_indication = _Item, #conn_data{resend_indication = Val}) -> 460 Val; 461do_conn_info(segment_reply_ind = _Item, #conn_data{segment_reply_ind = Val}) -> 462 Val; 463do_conn_info(segment_recv_acc = _Item, #conn_data{segment_recv_acc = Val}) -> 464 Val; 465do_conn_info(segment_recv_timer = _Item, 466 #conn_data{segment_recv_timer = Val}) -> 467 Val; 468do_conn_info(segment_send = _Item, #conn_data{segment_send = Val}) -> 469 Val; 470do_conn_info(segment_send_timer = _Item, 471 #conn_data{segment_send_timer = Val}) -> 472 Val; 473do_conn_info(max_pdu_size = _Item, #conn_data{max_pdu_size = Val}) -> 474 Val; 475do_conn_info(request_keep_alive_timeout = _Item, 476 #conn_data{request_keep_alive_timeout = Val}) -> 477 Val; 478do_conn_info(receive_handle = _Item, 479 #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid}, 480 encoding_mod = EM, 481 encoding_config = EC, 482 send_mod = SM}) -> 483 #megaco_receive_handle{local_mid = LMid, 484 encoding_mod = EM, 485 encoding_config = EC, 486 send_mod = SM}; 487do_conn_info(Item, Data) 488 when is_record(Data, conn_data) orelse is_record(Data, megaco_conn_handle) -> 489 exit({no_such_item, Item}); 490do_conn_info(_Item, BadData) -> 491 {error, {no_such_connection, BadData}}. 492 493 494%% replace(_, _, []) -> 495%% []; 496%% replace(Item, WithItem, [Item|List]) -> 497%% [WithItem|List]; 498%% replace(Item, WithItem, [OtherItem|List]) -> 499%% [OtherItem | replace(Item, WithItem, List)]. 500 501 502update_conn_info(#conn_data{conn_handle = CH}, Item, Val) -> 503 do_update_conn_info(CH, Item, Val); 504update_conn_info(CH, Item, Val) 505 when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) -> 506 do_update_conn_info(CH, Item, Val); 507update_conn_info(BadHandle, _Item, _Val) -> 508 {error, {no_such_connection, BadHandle}}. 509 510do_update_conn_info(CH, orig_pending_limit, Val) -> 511 do_update_conn_info(CH, sent_pending_limit, Val); 512do_update_conn_info(CH, Item, Val) -> 513 call({update_conn_data, CH, Item, Val}). 514 515 516system_info(all) -> 517 AllItems = [n_active_requests, 518 n_active_replies, 519 n_active_connections, 520 users, 521 connections, 522 text_config, 523 reply_counters, 524 pending_counters], 525 [{Item, system_info(Item)} || Item <- AllItems]; 526system_info(Item) -> 527 case Item of 528 n_active_requests -> 529 ets:info(megaco_requests, size); 530 n_active_replies -> 531 ets:info(megaco_replies, size); 532 n_active_connections -> 533 ets:info(megaco_local_conn, size); 534 users -> 535 Pat = {{'_', mid}, '_'}, 536 [Mid || {_, Mid} <- ets:match_object(megaco_config, Pat)]; 537 connections -> 538 [C#conn_data.conn_handle || C <- ets:tab2list(megaco_local_conn)]; 539 text_config -> 540 case ets:lookup(megaco_config, text_config) of 541 [] -> 542 []; 543 [{text_config, Conf}] -> 544 [Conf] 545 end; 546 547 reply_counters -> 548 reply_counters(); 549 550 pending_counters -> 551 pending_counters(); 552 553 recv_pending_counters -> 554 pending_counters(recv); 555 556 sent_pending_counters -> 557 pending_counters(sent); 558 559 BadItem -> 560 exit({no_such_item, BadItem}) 561 562 end. 563 564 565get_env(Env, Default) -> 566 case application:get_env(megaco, Env) of 567 {ok, Val} -> Val; 568 undefined -> Default 569 end. 570 571lookup_local_conn(Handle) -> 572 ets:lookup(megaco_local_conn, Handle). 573 574 575autoconnect(RH, RemoteMid, SendHandle, ControlPid) -> 576 ?d("autoconnect -> entry with " 577 "~n RH: ~p" 578 "~n RemoteMid: ~p" 579 "~n SendHandle: ~p" 580 "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]), 581 case RemoteMid of 582 {MidType, _MidValue} when is_atom(MidType) -> 583 call({connect, RH, RemoteMid, SendHandle, ControlPid, auto}); 584 preliminary_mid -> 585 call({connect, RH, RemoteMid, SendHandle, ControlPid, auto}); 586 BadMid -> 587 {error, {bad_remote_mid, BadMid}} 588 end. 589 590connect(RH, RemoteMid, SendHandle, ControlPid) -> 591 ?d("connect -> entry with " 592 "~n RH: ~p" 593 "~n RemoteMid: ~p" 594 "~n SendHandle: ~p" 595 "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]), 596 case RemoteMid of 597 {MidType, _MidValue} when is_atom(MidType) -> 598 call({connect, RH, RemoteMid, SendHandle, ControlPid, 599 {plain, self()}}); 600 preliminary_mid -> 601 call({connect, RH, RemoteMid, SendHandle, ControlPid, 602 {plain, self()}}); 603 BadMid -> 604 {error, {bad_remote_mid, BadMid}} 605 end. 606 607finish_connect(ConnHandle, SendHandle, ControlPid, MFA) -> 608 ?d("finish_connect -> entry with " 609 "~n ConnHandle: ~p" 610 "~n SendHandle: ~p" 611 "~n ControlPid: ~p" 612 "~n MFA: ~p", [ConnHandle, SendHandle, ControlPid, MFA]), 613 call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA}). 614 615connect_remote(ConnHandle, UserNode, Ref) -> 616 call({connect_remote, ConnHandle, UserNode, Ref}). 617 618disconnect(ConnHandle) -> 619 call({disconnect, ConnHandle}). 620 621disconnect_remote(ConnHandle, UserNode) -> 622 call({disconnect_remote, ConnHandle, UserNode}). 623 624 625incr_counter(Item, Incr) -> 626 try 627 begin 628 ets:update_counter(megaco_config, Item, Incr) 629 end 630 catch 631 error:_ -> 632 %% Counter does not exist, so try creat it 633 try 634 begin 635 cre_counter(Item, Incr) 636 end 637 catch 638 exit:_ -> 639 %% This is a raise condition. 640 %% When we tried to update the counter above, it 641 %% did not exist, but now it does... 642 ets:update_counter(megaco_config, Item, Incr) 643 end 644 end. 645 646cre_counter(Item, Initial) -> 647 case whereis(?SERVER) =:= self() of 648 false -> 649 case call({cre_counter, Item, Initial}) of 650 {ok, Value} -> 651 Value; 652 {error, Reason} -> 653 exit({failed_creating_counter, Item, Initial, Reason}) 654 end; 655 true -> 656 %% Check that the counter does not already exists 657 %% so we don't overwrite an already existing counter 658 case ets:lookup(megaco_config, Item) of 659 [] -> 660 ets:insert(megaco_config, {Item, Initial}), 661 {ok, Initial}; 662 [_] -> 663 %% Possibly a raise condition 664 {error, already_exists} 665 666 end 667 end. 668 669 670cre_reply_counter(ConnHandle, TransId) -> 671 Counter = {reply_counter, ConnHandle, TransId}, 672 Initial = 1, 673 cre_counter(Counter, Initial). 674 675incr_reply_counter(ConnHandle, TransId) -> 676 Counter = {reply_counter, ConnHandle, TransId}, 677 incr_counter(Counter, 1). 678 679get_reply_counter(ConnHandle, TransId) -> 680 Counter = {reply_counter, ConnHandle, TransId}, 681 [{Counter, Val}] = ets:lookup(megaco_config, Counter), 682 Val. 683 684del_reply_counter(ConnHandle, TransId) -> 685 Counter = {reply_counter, ConnHandle, TransId}, 686 ets:delete(megaco_config, Counter). 687 688reply_counters() -> 689 Pattern = {{reply_counter, '_', '_'}, '_'}, 690 Counters1 = ets:match_object(megaco_config, Pattern), 691 [{ConnHandle, TransId, CounterVal} || 692 {{reply_counter, ConnHandle, TransId}, CounterVal} <- Counters1]. 693 694 695cre_pending_counter(TransId) -> 696 cre_pending_counter(sent, TransId, 0). 697 698cre_pending_counter(Direction, TransId, Initial) -> 699 Counter = {pending_counter, Direction, TransId}, 700 cre_counter(Counter, Initial). 701 702incr_pending_counter(TransId) -> 703 incr_pending_counter(sent, TransId). 704 705incr_pending_counter(Direction, TransId) -> 706 Counter = {pending_counter, Direction, TransId}, 707 incr_counter(Counter, 1). 708 709get_pending_counter(TransId) -> 710 get_pending_counter(sent, TransId). 711 712get_pending_counter(Direction, TransId) -> 713 Counter = {pending_counter, Direction, TransId}, 714 [{Counter, Val}] = ets:lookup(megaco_config, Counter), 715 Val. 716 717del_pending_counter(TransId) -> 718 del_pending_counter(sent, TransId). 719 720del_pending_counter(Direction, TransId) -> 721 Counter = {pending_counter, Direction, TransId}, 722 ets:delete(megaco_config, Counter). 723 724 725pending_counters() -> 726 Pattern = {{pending_counter, '_', '_'}, '_'}, 727 Counters1 = ets:match_object(megaco_config, Pattern), 728 Counters2 = [{Direction, TransId, CounterVal} || 729 {{pending_counter, Direction, TransId}, CounterVal} <- 730 Counters1], 731 RecvCounters = [{TransId, CounterVal} || 732 {recv, TransId, CounterVal} <- Counters2], 733 SentCounters = [{TransId, CounterVal} || 734 {sent, TransId, CounterVal} <- Counters2], 735 [{recv, RecvCounters}, {sent, SentCounters}]. 736 737 738pending_counters(Direction) 739 when ((Direction =:= sent) orelse (Direction =:= recv)) -> 740 Pattern = {{pending_counter, Direction, '_'}, '_'}, 741 Counters = ets:match_object(megaco_config, Pattern), 742 [{TransId, CounterVal} || 743 {{pending_counter, D, TransId}, CounterVal} <- 744 Counters, (Direction == D)]. 745 746%% A wrapping transaction id counter 747incr_trans_id_counter(ConnHandle) -> 748 incr_trans_id_counter(ConnHandle, 1). 749incr_trans_id_counter(ConnHandle, Incr) 750 when is_integer(Incr) andalso (Incr > 0) -> 751 case megaco_config:lookup_local_conn(ConnHandle) of 752 [] -> 753 {error, {no_such_connection, ConnHandle}}; 754 [ConnData] -> 755 LocalMid = ConnHandle#megaco_conn_handle.local_mid, 756 Min = user_info(LocalMid, min_trans_id), 757 Max = 758 case ConnData#conn_data.max_serial of 759 infinity -> 760 4294967295; 761 MS -> 762 MS 763 end, 764 Item = ?TID_CNT(LocalMid), 765 do_incr_trans_id_counter(ConnData, Item, Min, Max, Incr, -1) 766 end. 767 768do_incr_trans_id_counter(ConnData, _Item, _Min, _Max, 0, Serial) -> 769 ConnData2 = ConnData#conn_data{serial = Serial}, 770 {ok, ConnData2}; 771do_incr_trans_id_counter(ConnData, Item, Min, Max, N, _) -> 772 case (catch ets:update_counter(megaco_config, Item, {2, 1, Max, Min})) of 773 {'EXIT', _} -> 774 %% This can only happen for the first ever increment, 775 %% in which case N is equal to (the initial) Incr 776 ConnHandle = ConnData#conn_data.conn_handle, 777 init_trans_id_counter(ConnHandle, Item, N); 778 Serial -> 779 do_incr_trans_id_counter(ConnData, Item, Min, Max, N-1, Serial) 780 end. 781 782init_trans_id_counter(ConnHandle, Item, Incr) -> 783 case whereis(?SERVER) == self() of 784 false -> 785 call({init_trans_id_counter, ConnHandle, Item, Incr}); 786 true -> 787 do_init_trans_id_counter(ConnHandle, Item, Incr) 788 end. 789 790do_init_trans_id_counter(ConnHandle, Item, Incr) -> 791 case megaco_config:lookup_local_conn(ConnHandle) of 792 [] -> 793 {error, {no_such_connection, ConnHandle}}; 794 [ConnData] -> 795 %% Make sure that the counter still does not exist 796 LocalMid = ConnHandle#megaco_conn_handle.local_mid, 797 Min = user_info(LocalMid, min_trans_id), 798 Max = 799 case ConnData#conn_data.max_serial of 800 infinity -> 801 4294967295; 802 MS -> 803 MS 804 end, 805 Item = ?TID_CNT(LocalMid), 806 Incr2 = {2, Incr, Max, Min}, 807 case (catch ets:update_counter(megaco_config, Item, Incr2)) of 808 {'EXIT', _} -> 809 %% Yep, we are the first one here 810 Serial1 = Min + (Incr-1), 811 ets:insert(megaco_config, {Item, Serial1}), 812 ConnData2 = ConnData#conn_data{serial = Serial1}, 813 {ok, ConnData2}; 814 Serial2 -> 815 %% No, someone got there before we did 816 ConnData2 = ConnData#conn_data{serial = Serial2}, 817 {ok, ConnData2} 818 end 819 end. 820 821%% For backward compatibillity (during code upgrade) 822reset_trans_id_counter(ConnHandle, Item, Serial) -> 823 LocalMid = ConnHandle#megaco_conn_handle.local_mid, 824 case megaco_config:lookup_local_conn(ConnHandle) of 825 [] -> 826 {error, {no_such_connection, ConnHandle}}; 827 [ConnData] -> 828 do_reset_trans_id_counter(ConnData, LocalMid, 829 Item, Serial) 830 end. 831 832do_reset_trans_id_counter(ConnData, LocalMid, Item, Serial) 833 when is_integer(Serial) -> 834 Max = ConnData#conn_data.max_serial, 835 Overflow = 836 if 837 (Max == infinity) -> 838 Serial - 4294967295; 839 840 is_integer(Max) -> 841 Serial - Max 842 end, 843 NewSerial = user_info(LocalMid, min_trans_id) + (Overflow-1), 844 ConnData2 = ConnData#conn_data{serial = NewSerial}, 845 ets:insert(megaco_config, {Item, NewSerial}), 846 {ok, ConnData2}. 847 848 849trans_sender_exit(Reason, CH) -> 850 ?d("trans_sender_exit -> entry with" 851 "~n Reason: ~p" 852 "~n CH: ~p", [Reason, CH]), 853 cast({trans_sender_exit, Reason, CH}). 854 855 856call(Request) -> 857 case (catch gen_server:call(?SERVER, Request, infinity)) of 858 {'EXIT', _} -> 859 {error, megaco_not_started}; 860 Res -> 861 Res 862 end. 863 864 865cast(Msg) -> 866 case (catch gen_server:cast(?SERVER, Msg)) of 867 {'EXIT', _} -> 868 {error, megaco_not_started}; 869 Res -> 870 Res 871 end. 872 873 874%%%---------------------------------------------------------------------- 875%%% Callback functions from gen_server 876%%%---------------------------------------------------------------------- 877 878%%---------------------------------------------------------------------- 879%% Func: init/1 880%% Returns: {ok, State} | 881%% {ok, State, Timeout} | 882%% ignore | 883%% {stop, Reason} 884%%---------------------------------------------------------------------- 885 886init([Parent]) -> 887 ?d("init -> entry with " 888 "~n Parent: ~p", [Parent]), 889 process_flag(trap_exit, true), 890 case (catch do_init()) of 891 ok -> 892 ?d("init -> init ok", []), 893 {ok, #state{parent_pid = Parent}}; 894 Else -> 895 ?d("init -> init error: " 896 "~n ~p", [Else]), 897 {stop, Else} 898 end. 899 900do_init() -> 901 ?megaco_test_init(), 902 ets:new(megaco_config, [public, named_table, {keypos, 1}]), 903 ets:new(megaco_local_conn, [public, named_table, {keypos, 2}]), 904 ets:new(megaco_remote_conn, [public, named_table, {keypos, 2}, bag]), 905 megaco_stats:init(megaco_stats, global_snmp_counters()), 906 init_scanner(), 907 init_user_defaults(), 908 init_users(). 909 910 911 912init_scanner() -> 913 case get_env(scanner, undefined) of 914 undefined -> 915 Key = text_config, 916 Data = [], 917 ets:insert(megaco_config, {Key, Data}); 918 flex -> 919 start_scanner(megaco_flex_scanner_handler, 920 start_link, [], [gen_server]); 921 {flex, Opts} when is_list(Opts) -> % For future use 922 start_scanner(megaco_flex_scanner_handler, 923 start_link, [Opts], [gen_server]); 924 {M, F, A, Mods} when is_atom(M) andalso 925 is_atom(F) andalso 926 is_list(A) andalso 927 is_list(Mods) -> 928 start_scanner(M, F, A, Mods) 929 end. 930 931start_scanner(M, F, A, Mods) -> 932 case megaco_misc_sup:start_permanent_worker(M, F, A, Mods) of 933 {ok, Pid, Conf} when is_pid(Pid) -> 934 Key = text_config, 935 Data = [Conf], 936 ets:insert(megaco_config, {Key, Data}); 937 Else -> 938 throw({scanner_start_failed, Else}) 939 end. 940 941init_user_defaults() -> 942 init_user_default(min_trans_id, 1), 943 init_user_default(max_trans_id, infinity), 944 init_user_default(request_timer, #megaco_incr_timer{}), 945 init_user_default(long_request_timer, timer:seconds(60)), 946 947 init_user_default(auto_ack, false), 948 949 init_user_default(trans_ack, false), 950 init_user_default(trans_ack_maxcount, 10), 951 952 init_user_default(trans_req, false), 953 init_user_default(trans_req_maxcount, 10), 954 init_user_default(trans_req_maxsize, 2048), 955 956 init_user_default(trans_timer, 0), 957 init_user_default(trans_sender, undefined), 958 959 init_user_default(pending_timer, timer:seconds(30)), 960 init_user_default(sent_pending_limit, infinity), 961 init_user_default(recv_pending_limit, infinity), 962 init_user_default(reply_timer, timer:seconds(30)), 963 init_user_default(send_mod, megaco_tcp), 964 init_user_default(encoding_mod, megaco_pretty_text_encoder), 965 init_user_default(protocol_version, 1), 966 init_user_default(auth_data, asn1_NOVALUE), 967 init_user_default(encoding_config, []), 968 init_user_default(user_mod, megaco_user_default), 969 init_user_default(user_args, []), 970 init_user_default(reply_data, undefined), 971 init_user_default(threaded, false), 972 init_user_default(strict_version, true), 973 init_user_default(long_request_resend, false), 974 init_user_default(call_proxy_gc_timeout, timer:seconds(5)), 975 init_user_default(cancel, false), 976 init_user_default(resend_indication, false), 977 init_user_default(segment_reply_ind, false), 978 init_user_default(segment_recv_acc, false), 979 init_user_default(segment_recv_timer, timer:seconds(10)), 980 init_user_default(segment_send, none), 981 init_user_default(segment_send_timer, timer:seconds(5)), 982 init_user_default(max_pdu_size, infinity), 983 init_user_default(request_keep_alive_timeout, plain). 984 985init_user_default(Item, Default) when Item /= mid -> 986 Val = get_env(Item, Default), 987 case do_update_user(default, Item, Val) of 988 ok -> 989 ok; 990 {error, Reason} -> 991 throw(Reason) 992 end. 993 994init_users() -> 995 Users = get_env(users, []), 996 init_users(Users). 997 998init_users([]) -> 999 ok; 1000init_users([{UserMid, Config} | Rest]) -> 1001 case handle_start_user(UserMid, Config) of 1002 ok -> 1003 init_users(Rest); 1004 Else -> 1005 throw({bad_user, UserMid, Else}) 1006 end; 1007init_users(BadConfig) -> 1008 throw({bad_config, users, BadConfig}). 1009 1010%%---------------------------------------------------------------------- 1011%% Func: handle_call/3 1012%% Returns: {reply, Reply, State} | 1013%% {reply, Reply, State, Timeout} | 1014%% {noreply, State} | 1015%% {noreply, State, Timeout} | 1016%% {stop, Reason, Reply, State} | (terminate/2 is called) 1017%% {stop, Reason, State} (terminate/2 is called) 1018%%---------------------------------------------------------------------- 1019 1020handle_call({cre_counter, Item, Incr}, _From, S) -> 1021 Reply = cre_counter(Item, Incr), 1022 {reply, Reply, S}; 1023 1024handle_call({del_counter, Item, Incr}, _From, S) -> 1025 Reply = cre_counter(Item, Incr), 1026 {reply, Reply, S}; 1027 1028%% For backward compatibillity (code upgrade) 1029handle_call({incr_trans_id_counter, ConnHandle}, _From, S) -> 1030 Reply = incr_trans_id_counter(ConnHandle), 1031 {reply, Reply, S}; 1032 1033handle_call({init_trans_id_counter, ConnHandle, Item, Incr}, _From, S) -> 1034 Reply = do_init_trans_id_counter(ConnHandle, Item, Incr), 1035 {reply, Reply, S}; 1036 1037%% For backward compatibillity (code upgrade) 1038handle_call({reset_trans_id_counter, ConnHandle, Item, Serial}, _From, S) -> 1039 Reply = reset_trans_id_counter(ConnHandle, Item, Serial), 1040 {reply, Reply, S}; 1041 1042handle_call({receive_handle, UserMid}, _From, S) -> 1043 case catch make_receive_handle(UserMid) of 1044 {'EXIT', _} -> 1045 {reply, {error, {no_receive_handle, UserMid}}, S}; 1046 RH -> 1047 {reply, {ok, RH}, S} 1048 end; 1049handle_call({connect, RH, RemoteMid, SendHandle, ControlPid}, _From, S) -> 1050 Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, auto), 1051 {reply, Reply, S}; 1052handle_call({connect, RH, RemoteMid, SendHandle, ControlPid, Auto}, _From, S) -> 1053 Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto), 1054 {reply, Reply, S}; 1055 1056handle_call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA}, 1057 _From, S) -> 1058 Reply = handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA), 1059 {reply, Reply, S}; 1060 1061handle_call({connect_remote, CH, UserNode, Ref}, _From, S) -> 1062 Reply = handle_connect_remote(CH, UserNode, Ref), 1063 {reply, Reply, S}; 1064 1065handle_call({disconnect, ConnHandle}, _From, S) -> 1066 Reply = handle_disconnect(ConnHandle), 1067 {reply, Reply, S}; 1068handle_call({disconnect_remote, CH, UserNode}, _From, S) -> 1069 Reply = handle_disconnect_remote(CH, UserNode), 1070 {reply, Reply, S}; 1071 1072handle_call({start_user, UserMid, Config}, _From, S) -> 1073 Reply = handle_start_user(UserMid, Config), 1074 {reply, Reply, S}; 1075handle_call({stop_user, UserMid}, _From, S) -> 1076 Reply = handle_stop_user(UserMid), 1077 {reply, Reply, S}; 1078handle_call({update_conn_data, CH, Item, Val}, _From, S) -> 1079 case lookup_local_conn(CH) of 1080 [] -> 1081 {reply, {error, {no_such_connection, CH}}, S}; 1082 [CD] -> 1083 Reply = handle_update_conn_data(CD, Item, Val), 1084 {reply, Reply, S} 1085 end; 1086handle_call({update_user_info, UserMid, Item, Val}, _From, S) -> 1087 case catch user_info(UserMid, mid) of 1088 {'EXIT', _} -> 1089 {reply, {error, {no_such_user, UserMid}}, S}; 1090 _ -> 1091 Reply = do_update_user(UserMid, Item, Val), 1092 {reply, Reply, S} 1093 end; 1094 1095handle_call({stop, ParentPid}, _From, #state{parent_pid = ParentPid} = S) -> 1096 Reason = normal, 1097 Reply = ok, 1098 {stop, Reason, Reply, S}; 1099 1100handle_call(Req, From, S) -> 1101 warning_msg("received unexpected request from ~p: " 1102 "~n~w", [From, Req]), 1103 {reply, {error, {bad_request, Req}}, S}. 1104 1105 1106%%---------------------------------------------------------------------- 1107%% Func: handle_cast/2 1108%% Returns: {noreply, State} | 1109%% {noreply, State, Timeout} | 1110%% {stop, Reason, State} (terminate/2 is called) 1111%%---------------------------------------------------------------------- 1112 1113handle_cast({trans_sender_exit, Reason, CH}, S) -> 1114 warning_msg("transaction sender [~p] restarting: " 1115 "~n~p", [CH, Reason]), 1116 case lookup_local_conn(CH) of 1117 [] -> 1118 error_msg("connection data not found for ~p~n" 1119 "when restarting transaction sender", [CH]); 1120 [CD] -> 1121 CD2 = trans_sender_start(CD#conn_data{trans_sender = undefined}), 1122 ets:insert(megaco_local_conn, CD2) 1123 end, 1124 {noreply, S}; 1125 1126handle_cast(Msg, S) -> 1127 warning_msg("received unexpected message: " 1128 "~n~w", [Msg]), 1129 {noreply, S}. 1130 1131 1132 1133%%---------------------------------------------------------------------- 1134%% Func: handle_info/2 1135%% Returns: {noreply, State} | 1136%% {noreply, State, Timeout} | 1137%% {stop, Reason, State} (terminate/2 is called) 1138%%---------------------------------------------------------------------- 1139 1140handle_info({'EXIT', Pid, Reason}, S) when Pid =:= S#state.parent_pid -> 1141 {stop, Reason, S}; 1142 1143handle_info(Info, S) -> 1144 warning_msg("received unknown info: " 1145 "~n~w", [Info]), 1146 {noreply, S}. 1147 1148 1149 1150%%---------------------------------------------------------------------- 1151%% Func: terminate/2 1152%% Purpose: Shutdown the server 1153%% Returns: any (ignored by gen_server) 1154%%---------------------------------------------------------------------- 1155 1156terminate(_Reason, _State) -> 1157 ok. 1158 1159 1160%%---------------------------------------------------------------------- 1161%% Func: code_change/3 1162%% Purpose: Convert process state when code is changed 1163%% Returns: {ok, NewState} 1164%%---------------------------------------------------------------------- 1165 1166code_change(_Vsn, S, upgrade_from_pre_3_12) -> 1167 upgrade_user_info_from_pre_3_12(), 1168 upgrade_conn_data_from_pre_3_12(), 1169 {ok, S}; 1170 1171code_change(_Vsn, S, downgrade_to_pre_3_12) -> 1172 downgrade_user_info_to_pre_3_12(), 1173 downgrade_conn_data_to_pre_3_12(), 1174 {ok, S}; 1175 1176code_change(_Vsn, S, _Extra) -> 1177 {ok, S}. 1178 1179 1180%% -- Upgrade user info -- 1181 1182upgrade_user_info_from_pre_3_12() -> 1183 NewValues = [{request_keep_alive_timeout, plain}], 1184 upgrade_user_info(NewValues). 1185 1186%% upgrade_user_info_from_pre_3_7() -> 1187%% NewValues = [{segment_reply_ind, false}, 1188%% {segment_recv_acc, false}, 1189%% {segment_recv_timer, #megaco_incr_timer{}}, 1190%% {segment_send, none}, 1191%% {segment_send_timer, infinity}, 1192%% {max_pdu_size, infinity}], 1193%% upgrade_user_info(NewValues). 1194 1195upgrade_user_info(NewValues) -> 1196 Users = [default|system_info(users)], 1197 F = fun({Item, Val}) -> 1198 upgrade_user_info(Users, Item, Val) 1199 end, 1200 lists:foreach(F, NewValues), 1201 ok. 1202 1203upgrade_user_info(Users, Item, Val) -> 1204 F = fun(User) -> do_update_user(User, Item, Val) end, 1205 lists:foreach(F, Users), 1206 ok. 1207 1208 1209%% %% -- Downgrade user info -- 1210 1211downgrade_user_info_to_pre_3_12() -> 1212 NewItems = [ 1213 request_keep_alive_timeout 1214 ], 1215 downgrade_user_info(NewItems). 1216 1217%% downgrade_user_info_to_pre_3_7() -> 1218%% NewItems = [ 1219%% segment_reply_ind, 1220%% segment_recv_acc, 1221%% segment_recv_timer, 1222%% segment_send, 1223%% segment_send_timer, 1224%% max_pdu_size 1225%% ], 1226%% downgrade_user_info(NewItems). 1227 1228downgrade_user_info(NewItems) -> 1229 Users = [default|system_info(users)], 1230 F = fun(Item) -> 1231 downgrade_user_info(Users, Item) 1232 end, 1233 lists:foreach(F, NewItems), 1234 ok. 1235 1236downgrade_user_info(Users, Item) -> 1237 F = fun(User) -> do_downgrade_user_info(User, Item) end, 1238 lists:foreach(F, Users), 1239 ok. 1240 1241do_downgrade_user_info(User, Item) -> 1242 ets:delete(megaco_config, {User, Item}). 1243 1244 1245%% %% -- Upgrade conn data -- 1246 1247upgrade_conn_data_from_pre_3_12() -> 1248 Conns = system_info(connections), 1249 Defaults = [{request_keep_alive_timeout, plain}], 1250 upgrade_conn_data(Conns, Defaults). 1251 1252%% upgrade_conn_data_from_pre_3_7() -> 1253%% Conns = system_info(connections), 1254%% Defaults = [{segment_reply_ind, false}, 1255%% {segment_recv_acc, false}, 1256%% {segment_recv_timer, #megaco_incr_timer{}}, 1257%% {segment_send, false}, 1258%% {segment_send_timer, #megaco_incr_timer{}}, 1259%% {max_pdu_size, infinity}], 1260%% upgrade_conn_data(Conns, Defaults). 1261 1262upgrade_conn_data(Conns, Defaults) -> 1263 F = fun(CH) -> 1264 case lookup_local_conn(CH) of 1265 [] -> 1266 ok; 1267 [CD] -> 1268 do_upgrade_conn_data(CD, Defaults) 1269 end 1270 end, 1271 lists:foreach(F, Conns), 1272 ok. 1273 1274do_upgrade_conn_data(OldStyleCD, Defaults) -> 1275 NewStyleCD = new_conn_data(OldStyleCD, Defaults), 1276 ets:insert(megaco_local_conn, NewStyleCD). 1277 1278%% Pre 3.12 1279new_conn_data({conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr, 1280 AutoAck, 1281 TransAck, TransAckMaxCnt, 1282 TransReq, TransReqMaxCnt, TransReqMaxSz, 1283 TransTmr, TransSndr, 1284 1285 PendingTmr, 1286 SentPendingLimit, 1287 RecvPendingLimit, 1288 ReplyTmr, CtrPid, MonRef, 1289 Sendmod, SendHandle, 1290 EncodeMod, EncodeConf, 1291 ProtV, AuthData, 1292 UserMod, UserArgs, ReplyAction, ReplyData, 1293 Threaded, 1294 StrictVersion, 1295 LongReqResend, 1296 Cancel, 1297 ResendIndication, 1298 SegmentReplyInd, 1299 SegmentRecvAcc, 1300 SegmentRecvTimer, 1301 SegmentSend, 1302 SegmentSendTimer, 1303 MaxPDUSize 1304 %% RequestKeepAliveTimerDefault - New values 1305 }, 1306 Defaults) -> 1307 #conn_data{conn_handle = CH, 1308 serial = Serial, 1309 max_serial = MaxSerial, 1310 request_timer = ReqTmr, 1311 long_request_timer = LongReqTmr, 1312 1313 auto_ack = AutoAck, 1314 1315 trans_ack = TransAck, 1316 trans_ack_maxcount = TransAckMaxCnt, 1317 1318 trans_req = TransReq, 1319 trans_req_maxcount = TransReqMaxCnt, 1320 trans_req_maxsize = TransReqMaxSz, 1321 1322 trans_timer = TransTmr, 1323 trans_sender = TransSndr, 1324 1325 pending_timer = PendingTmr, 1326 sent_pending_limit = SentPendingLimit, 1327 recv_pending_limit = RecvPendingLimit, 1328 1329 reply_timer = ReplyTmr, 1330 control_pid = CtrPid, 1331 monitor_ref = MonRef, 1332 send_mod = Sendmod, 1333 send_handle = SendHandle, 1334 encoding_mod = EncodeMod, 1335 encoding_config = EncodeConf, 1336 protocol_version = ProtV, 1337 auth_data = AuthData, 1338 user_mod = UserMod, 1339 user_args = UserArgs, 1340 reply_action = ReplyAction, 1341 reply_data = ReplyData, 1342 threaded = Threaded, 1343 strict_version = StrictVersion, 1344 long_request_resend = LongReqResend, 1345 cancel = Cancel, 1346 resend_indication = ResendIndication, 1347 segment_reply_ind = SegmentReplyInd, 1348 segment_recv_acc = SegmentRecvAcc, 1349 segment_recv_timer = SegmentRecvTimer, 1350 segment_send = SegmentSend, 1351 segment_send_timer = SegmentSendTimer, 1352 max_pdu_size = MaxPDUSize, 1353 request_keep_alive_timeout = get_default(request_keep_alive_timeout, Defaults) 1354 }. 1355 1356 1357get_default(Key, Defaults) -> 1358 {value, {Key, Default}} = lists:keysearch(Key, 1, Defaults), 1359 Default. 1360 1361 1362%% %% -- Downgrade conn data -- 1363 1364downgrade_conn_data_to_pre_3_12() -> 1365 Conns = system_info(connections), 1366 Downgrade = fun(NewCD) -> old_conn_data_to_pre_3_12(NewCD) end, 1367 downgrade_conn_data(Downgrade, Conns). 1368 1369downgrade_conn_data(Downgrade, Conns) -> 1370 F = fun(CH) -> 1371 case lookup_local_conn(CH) of 1372 [] -> 1373 ok; 1374 [CD] -> 1375 do_downgrade_conn_data(Downgrade, CD) 1376 end 1377 end, 1378 lists:foreach(F, Conns). 1379 1380do_downgrade_conn_data(Downgrade, NewStyleCD) -> 1381 OldStyleCD = Downgrade(NewStyleCD), 1382 ets:insert(megaco_local_conn, OldStyleCD). 1383 1384old_conn_data_to_pre_3_12( 1385 #conn_data{conn_handle = CH, 1386 serial = Serial, 1387 max_serial = MaxSerial, 1388 request_timer = ReqTmr, 1389 long_request_timer = LongReqTmr, 1390 1391 auto_ack = AutoAck, 1392 1393 trans_ack = TransAck, 1394 trans_ack_maxcount = TransAckMaxCnt, 1395 1396 trans_req = TransReq, 1397 trans_req_maxcount = TransReqMaxCnt, 1398 trans_req_maxsize = TransReqMaxSz, 1399 1400 trans_timer = TransTmr, 1401 trans_sender = TransSndr, 1402 1403 pending_timer = PendingTmr, 1404 sent_pending_limit = SentPendingLimit, 1405 recv_pending_limit = RecvPendingLimit, 1406 1407 reply_timer = ReplyTmr, 1408 control_pid = CtrPid, 1409 monitor_ref = MonRef, 1410 send_mod = Sendmod, 1411 send_handle = SendHandle, 1412 encoding_mod = EncodeMod, 1413 encoding_config = EncodeConf, 1414 protocol_version = ProtV, 1415 auth_data = AuthData, 1416 user_mod = UserMod, 1417 user_args = UserArgs, 1418 reply_action = ReplyAction, 1419 reply_data = ReplyData, 1420 threaded = Threaded, 1421 strict_version = StrictVersion, 1422 long_request_resend = LongReqResend, 1423 cancel = Cancel, 1424 resend_indication = ResendIndication, 1425 segment_reply_ind = SegmentRecvAcc, 1426 segment_recv_acc = SegmentRecvAcc, 1427 segment_recv_timer = SegmentRecvTimer, 1428 segment_send = SegmentSend, 1429 segment_send_timer = SegmentSendTimer, 1430 max_pdu_size = MaxPDUSize 1431 %% request_keep_alive_timeout = RequestKeepAliveTimeout 1432 }) -> 1433 {conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr, 1434 AutoAck, 1435 TransAck, TransAckMaxCnt, 1436 TransReq, TransReqMaxCnt, TransReqMaxSz, 1437 TransTmr, TransSndr, 1438 PendingTmr, 1439 SentPendingLimit, 1440 RecvPendingLimit, 1441 ReplyTmr, CtrPid, MonRef, 1442 Sendmod, SendHandle, 1443 EncodeMod, EncodeConf, 1444 ProtV, AuthData, 1445 UserMod, UserArgs, ReplyAction, ReplyData, 1446 Threaded, 1447 StrictVersion, 1448 LongReqResend, 1449 Cancel, 1450 ResendIndication, 1451 SegmentRecvAcc, 1452 SegmentRecvAcc, 1453 SegmentRecvTimer, 1454 SegmentSend, 1455 SegmentSendTimer, 1456 MaxPDUSize}. 1457 1458 1459 1460%%%---------------------------------------------------------------------- 1461%%% Internal functions 1462%%%---------------------------------------------------------------------- 1463 1464handle_start_user(default, _Config) -> 1465 {error, bad_user_mid}; 1466handle_start_user(Mid, Config) -> 1467 case catch user_info(Mid, mid) of 1468 {'EXIT', _} -> 1469 DefaultConfig = user_info(default, all), 1470 do_handle_start_user(Mid, DefaultConfig), 1471 do_handle_start_user(Mid, Config); 1472 _LocalMid -> 1473 {error, {user_already_exists, Mid}} 1474 end. 1475 1476do_handle_start_user(UserMid, [{Item, Val} | Rest]) -> 1477 case do_update_user(UserMid, Item, Val) of 1478 ok -> 1479 do_handle_start_user(UserMid, Rest); 1480 {error, Reason} -> 1481 ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}), 1482 {error, Reason} 1483 end; 1484do_handle_start_user(UserMid, []) -> 1485 do_update_user(UserMid, mid, UserMid), 1486 ok; 1487do_handle_start_user(UserMid, BadConfig) -> 1488 ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}), 1489 {error, {bad_user_config, UserMid, BadConfig}}. 1490 1491do_update_user(UserMid, Item, Val) -> 1492 case verify_val(Item, Val) of 1493 true -> 1494 ets:insert(megaco_config, {{UserMid, Item}, Val}), 1495 ok; 1496 false -> 1497 {error, {bad_user_val, UserMid, Item, Val}} 1498 end. 1499 1500verify_val(Item, Val) -> 1501 case Item of 1502 mid -> true; 1503 local_mid -> true; 1504 remote_mid -> true; 1505 min_trans_id -> 1506 megaco_config_misc:verify_strict_uint(Val, 4294967295); % uint32 1507 max_trans_id -> 1508 megaco_config_misc:verify_uint(Val, 4294967295); % uint32 1509 request_timer -> verify_timer(Val); 1510 long_request_timer -> verify_timer(Val); 1511 1512 auto_ack -> 1513 megaco_config_misc:verify_bool(Val); 1514 1515 trans_ack -> 1516 megaco_config_misc:verify_bool(Val); 1517 trans_ack_maxcount -> 1518 megaco_config_misc:verify_uint(Val); 1519 1520 trans_req -> 1521 megaco_config_misc:verify_bool(Val); 1522 trans_req_maxcount -> 1523 megaco_config_misc:verify_uint(Val); 1524 trans_req_maxsize -> 1525 megaco_config_misc:verify_uint(Val); 1526 1527 trans_timer -> 1528 verify_timer(Val) and (Val >= 0); 1529 trans_sender when Val =:= undefined -> true; 1530 1531 pending_timer -> verify_timer(Val); 1532 sent_pending_limit -> 1533 megaco_config_misc:verify_uint(Val) andalso (Val > 0); 1534 recv_pending_limit -> 1535 megaco_config_misc:verify_uint(Val) andalso (Val > 0); 1536 reply_timer -> verify_timer(Val); 1537 control_pid when is_pid(Val) -> true; 1538 monitor_ref -> true; % Internal usage only 1539 send_mod when is_atom(Val) -> true; 1540 send_handle -> true; 1541 encoding_mod when is_atom(Val) -> true; 1542 encoding_config when is_list(Val) -> 1543 case Val of 1544 [{version3, V3}|_] when (V3 =/= v3) -> 1545 error_msg("Encoding Config version3 ~p is " 1546 "no longer supported!~n"), 1547 ok; 1548 _ -> 1549 ok 1550 end, 1551 true; 1552 protocol_version -> 1553 megaco_config_misc:verify_strict_uint(Val); 1554 auth_data -> true; 1555 user_mod when is_atom(Val) -> true; 1556 user_args when is_list(Val) -> true; 1557 reply_data -> true; 1558 threaded -> 1559 megaco_config_misc:verify_bool(Val); 1560 strict_version -> 1561 megaco_config_misc:verify_bool(Val); 1562 long_request_resend -> 1563 megaco_config_misc:verify_bool(Val); 1564 call_proxy_gc_timeout -> 1565 megaco_config_misc:verify_strict_uint(Val); 1566 cancel -> 1567 megaco_config_misc:verify_bool(Val); 1568 resend_indication -> verify_resend_indication(Val); 1569 1570 segment_reply_ind -> 1571 megaco_config_misc:verify_bool(Val); 1572 segment_recv_acc -> 1573 megaco_config_misc:verify_bool(Val); 1574 segment_recv_timer -> verify_timer(Val); 1575 segment_send -> verify_segmentation_window(Val); 1576 segment_send_timer -> verify_timer(Val); 1577 max_pdu_size -> 1578 megaco_config_misc:verify_int(Val) andalso (Val > 0); 1579 request_keep_alive_timeout -> 1580 (megaco_config_misc:verify_uint(Val) orelse (Val =:= plain)); 1581 1582 _ -> false 1583 end. 1584 1585 1586 1587verify_resend_indication(flag) -> true; 1588verify_resend_indication(Val) -> megaco_config_misc:verify_bool(Val). 1589 1590verify_timer(Timer) -> 1591 megaco_timer:verify(Timer). 1592 1593verify_segmentation_window(none) -> 1594 true; 1595verify_segmentation_window(K) -> 1596 megaco_config_misc:verify_int(K, 1, infinity). 1597 1598handle_stop_user(UserMid) -> 1599 case catch user_info(UserMid, mid) of 1600 {'EXIT', _} -> 1601 {error, {no_such_user, UserMid}}; 1602 _ -> 1603 case catch user_info(UserMid, connections) of 1604 [] -> 1605 ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}), 1606 ok; 1607 {'EXIT', _} -> 1608 {error, {no_such_user, UserMid}}; 1609 _Else -> 1610 {error, {active_connections, UserMid}} 1611 end 1612 end. 1613 1614handle_update_conn_data(CD, Item = receive_handle, RH) -> 1615 UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid, 1616 if 1617 is_record(RH, megaco_receive_handle) andalso 1618 is_atom(RH#megaco_receive_handle.encoding_mod) andalso 1619 is_list(RH#megaco_receive_handle.encoding_config) andalso 1620 is_atom(RH#megaco_receive_handle.send_mod) andalso 1621 (RH#megaco_receive_handle.local_mid /= UserMid) -> 1622 CD2 = CD#conn_data{ 1623 encoding_mod = RH#megaco_receive_handle.encoding_mod, 1624 encoding_config = RH#megaco_receive_handle.encoding_config, 1625 send_mod = RH#megaco_receive_handle.send_mod}, 1626 ets:insert(megaco_local_conn, CD2), 1627 ok; 1628 true -> 1629 {error, {bad_user_val, UserMid, Item, RH}} 1630 end; 1631handle_update_conn_data(CD, Item, Val) -> 1632 case verify_val(Item, Val) of 1633 true -> 1634 CD2 = replace_conn_data(CD, Item, Val), 1635 ets:insert(megaco_local_conn, CD2), 1636 ok; 1637 false -> 1638 UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid, 1639 {error, {bad_user_val, UserMid, Item, Val}} 1640 end. 1641 1642replace_conn_data(CD, Item, Val) -> 1643 case Item of 1644 trans_id -> CD#conn_data{serial = Val}; 1645 max_trans_id -> CD#conn_data{max_serial = Val}; 1646 request_timer -> CD#conn_data{request_timer = Val}; 1647 long_request_timer -> CD#conn_data{long_request_timer = Val}; 1648 1649 auto_ack -> update_auto_ack(CD, Val); 1650 1651 %% Accumulate trans ack before sending 1652 trans_ack -> update_trans_ack(CD, Val); 1653 trans_ack_maxcount -> update_trans_ack_maxcount(CD, Val); 1654 1655 %% Accumulate trans req before sending 1656 trans_req -> update_trans_req(CD, Val); 1657 trans_req_maxcount -> update_trans_req_maxcount(CD, Val); 1658 trans_req_maxsize -> update_trans_req_maxsize(CD, Val); 1659 1660 trans_timer -> update_trans_timer(CD, Val); 1661 %% trans_sender - Automagically updated by 1662 %% update_auto_ack & update_trans_timer & 1663 %% update_trans_ack & update_trans_req 1664 1665 pending_timer -> CD#conn_data{pending_timer = Val}; 1666 sent_pending_limit -> CD#conn_data{sent_pending_limit = Val}; 1667 recv_pending_limit -> CD#conn_data{recv_pending_limit = Val}; 1668 reply_timer -> CD#conn_data{reply_timer = Val}; 1669 control_pid -> CD#conn_data{control_pid = Val}; 1670 monitor_ref -> CD#conn_data{monitor_ref = Val}; 1671 send_mod -> CD#conn_data{send_mod = Val}; 1672 send_handle -> CD#conn_data{send_handle = Val}; 1673 encoding_mod -> CD#conn_data{encoding_mod = Val}; 1674 encoding_config -> CD#conn_data{encoding_config = Val}; 1675 protocol_version -> CD#conn_data{protocol_version = Val}; 1676 auth_data -> CD#conn_data{auth_data = Val}; 1677 user_mod -> CD#conn_data{user_mod = Val}; 1678 user_args -> CD#conn_data{user_args = Val}; 1679 reply_action -> CD#conn_data{reply_action = Val}; 1680 reply_data -> CD#conn_data{reply_data = Val}; 1681 threaded -> CD#conn_data{threaded = Val}; 1682 strict_version -> CD#conn_data{strict_version = Val}; 1683 long_request_resend -> CD#conn_data{long_request_resend = Val}; 1684 call_proxy_gc_timeout -> CD#conn_data{call_proxy_gc_timeout = Val}; 1685 cancel -> CD#conn_data{cancel = Val}; 1686 resend_indication -> CD#conn_data{resend_indication = Val}; 1687 segment_reply_ind -> CD#conn_data{segment_reply_ind = Val}; 1688 segment_recv_acc -> CD#conn_data{segment_recv_acc = Val}; 1689 segment_recv_timer -> CD#conn_data{segment_recv_timer = Val}; 1690 segment_send -> CD#conn_data{segment_send = Val}; 1691 segment_send_timer -> CD#conn_data{segment_send_timer = Val}; 1692 max_pdu_size -> CD#conn_data{max_pdu_size = Val}; 1693 request_keep_alive_timeout -> CD#conn_data{request_keep_alive_timeout = Val} 1694 end. 1695 1696%% update auto_ack 1697update_auto_ack(#conn_data{trans_sender = Pid, 1698 trans_req = false} = CD, 1699 false) when is_pid(Pid) -> 1700 megaco_trans_sender:stop(Pid), 1701 CD#conn_data{auto_ack = false, trans_sender = undefined}; 1702 1703update_auto_ack(#conn_data{trans_timer = To, 1704 trans_ack = true, 1705 trans_sender = undefined} = CD, 1706 true) when To > 0 -> 1707 #conn_data{conn_handle = CH, 1708 trans_ack_maxcount = AcksMax, 1709 trans_req_maxcount = ReqsMax, 1710 trans_req_maxsize = ReqsMaxSz} = CD, 1711 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1712 ReqsMax, AcksMax), 1713 1714 %% Make sure we are notified when/if the transaction 1715 %% sender goes down. 1716 %% Do we need to store the ref? Will we ever need to 1717 %% cancel this (apply_at_exit)? 1718 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1719 1720 CD#conn_data{auto_ack = true, trans_sender = Pid}; 1721 1722update_auto_ack(CD, Val) -> 1723 ?d("update_auto_ack -> entry with ~p", [Val]), 1724 CD#conn_data{auto_ack = Val}. 1725 1726%% update trans_ack 1727update_trans_ack(#conn_data{auto_ack = true, 1728 trans_req = false, 1729 trans_sender = Pid} = CD, 1730 false) when is_pid(Pid) -> 1731 megaco_trans_sender:stop(Pid), 1732 CD#conn_data{trans_ack = false, trans_sender = undefined}; 1733 1734update_trans_ack(#conn_data{trans_timer = To, 1735 auto_ack = true, 1736 trans_sender = undefined} = CD, 1737 true) when To > 0 -> 1738 #conn_data{conn_handle = CH, 1739 trans_ack_maxcount = AcksMax, 1740 trans_req_maxcount = ReqsMax, 1741 trans_req_maxsize = ReqsMaxSz} = CD, 1742 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1743 ReqsMax, AcksMax), 1744 1745 %% Make sure we are notified when/if the transaction 1746 %% sender goes down. 1747 %% Do we need to store the ref? Will we ever need to 1748 %% cancel this (apply_at_exit)? 1749 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1750 1751 CD#conn_data{trans_ack = true, trans_sender = Pid}; 1752 1753update_trans_ack(CD, Val) -> 1754 ?d("update_trans_ack -> entry with ~p", [Val]), 1755 CD#conn_data{trans_ack = Val}. 1756 1757%% update trans_req 1758update_trans_req(#conn_data{trans_ack = false, 1759 trans_sender = Pid} = CD, 1760 false) when is_pid(Pid) -> 1761 megaco_trans_sender:stop(Pid), 1762 CD#conn_data{trans_req = false, trans_sender = undefined}; 1763 1764update_trans_req(#conn_data{trans_timer = To, 1765 trans_sender = undefined} = CD, 1766 true) when To > 0 -> 1767 #conn_data{conn_handle = CH, 1768 trans_ack_maxcount = AcksMax, 1769 trans_req_maxcount = ReqsMax, 1770 trans_req_maxsize = ReqsMaxSz} = CD, 1771 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1772 ReqsMax, AcksMax), 1773 1774 %% Make sure we are notified when/if the transaction 1775 %% sender goes down. 1776 %% Do we need to store the ref? Will we ever need to 1777 %% cancel this (apply_at_exit)? 1778 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1779 1780 CD#conn_data{trans_req = true, trans_sender = Pid}; 1781 1782update_trans_req(CD, Val) -> 1783 ?d("update_trans_req -> entry with ~p", [Val]), 1784 CD#conn_data{trans_req = Val}. 1785 1786%% update trans_timer 1787update_trans_timer(#conn_data{auto_ack = true, 1788 trans_ack = true, 1789 trans_sender = undefined} = CD, 1790 To) when To > 0 -> 1791 #conn_data{conn_handle = CH, 1792 trans_ack_maxcount = AcksMax, 1793 trans_req_maxcount = ReqsMax, 1794 trans_req_maxsize = ReqsMaxSz} = CD, 1795 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1796 ReqsMax, AcksMax), 1797 1798 %% Make sure we are notified when/if the transaction 1799 %% sender goes down. 1800 %% Do we need to store the ref? Will we ever need to 1801 %% cancel this (apply_at_exit)? 1802 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1803 1804 CD#conn_data{trans_timer = To, trans_sender = Pid}; 1805 1806update_trans_timer(#conn_data{trans_req = true, 1807 trans_sender = undefined} = CD, 1808 To) when To > 0 -> 1809 #conn_data{conn_handle = CH, 1810 trans_ack_maxcount = AcksMax, 1811 trans_req_maxcount = ReqsMax, 1812 trans_req_maxsize = ReqsMaxSz} = CD, 1813 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1814 ReqsMax, AcksMax), 1815 1816 %% Make sure we are notified when/if the transaction 1817 %% sender goes down. 1818 %% Do we need to store the ref? Will we ever need to 1819 %% cancel this (apply_at_exit)? 1820 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1821 1822 CD#conn_data{trans_timer = To, trans_sender = Pid}; 1823 1824update_trans_timer(#conn_data{trans_sender = Pid} = CD, 0) when is_pid(Pid) -> 1825 megaco_trans_sender:stop(Pid), 1826 CD#conn_data{trans_timer = 0, trans_sender = undefined}; 1827 1828update_trans_timer(#conn_data{trans_sender = Pid} = CD, To) 1829 when is_pid(Pid) and (To > 0) -> 1830 megaco_trans_sender:timeout(Pid, To), 1831 CD#conn_data{trans_timer = To}; 1832 1833update_trans_timer(CD, To) when To > 0 -> 1834 CD#conn_data{trans_timer = To}. 1835 1836%% update trans_ack_maxcount 1837update_trans_ack_maxcount(#conn_data{trans_sender = Pid} = CD, Max) 1838 when is_pid(Pid) and (Max > 0) -> 1839 megaco_trans_sender:ack_maxcount(Pid, Max), 1840 CD#conn_data{trans_ack_maxcount = Max}; 1841 1842update_trans_ack_maxcount(CD, Max) 1843 when Max > 0 -> 1844 ?d("update_trans_ack_maxcount -> entry with ~p", [Max]), 1845 CD#conn_data{trans_ack_maxcount = Max}. 1846 1847%% update trans_req_maxcount 1848update_trans_req_maxcount(#conn_data{trans_sender = Pid} = CD, Max) 1849 when is_pid(Pid) and (Max > 0) -> 1850 megaco_trans_sender:req_maxcount(Pid, Max), 1851 CD#conn_data{trans_req_maxcount = Max}; 1852 1853update_trans_req_maxcount(CD, Max) 1854 when Max > 0 -> 1855 ?d("update_trans_req_maxcount -> entry with ~p", [Max]), 1856 CD#conn_data{trans_req_maxcount = Max}. 1857 1858%% update trans_req_maxsize 1859update_trans_req_maxsize(#conn_data{trans_sender = Pid} = CD, Max) 1860 when is_pid(Pid) and (Max > 0) -> 1861 megaco_trans_sender:req_maxsize(Pid, Max), 1862 CD#conn_data{trans_req_maxsize = Max}; 1863 1864update_trans_req_maxsize(CD, Max) 1865 when Max > 0 -> 1866 ?d("update_trans_req_maxsize -> entry with ~p", [Max]), 1867 CD#conn_data{trans_req_maxsize = Max}. 1868 1869 1870 1871handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto) -> 1872 LocalMid = RH#megaco_receive_handle.local_mid, 1873 ConnHandle = #megaco_conn_handle{local_mid = LocalMid, 1874 remote_mid = RemoteMid}, 1875 ?d("handle_connect -> entry with" 1876 "~n ConnHandle: ~p", [ConnHandle]), 1877 case ets:lookup(megaco_local_conn, ConnHandle) of 1878 [] -> 1879 PrelMid = preliminary_mid, 1880 PrelHandle = ConnHandle#megaco_conn_handle{remote_mid = PrelMid}, 1881 case ets:lookup(megaco_local_conn, PrelHandle) of 1882 [] -> 1883 case (catch init_conn_data(RH, 1884 RemoteMid, SendHandle, 1885 ControlPid, Auto)) of 1886 {'EXIT', _Reason} -> 1887 ?d("handle_connect -> init conn data failed: " 1888 "~n ~p",[_Reason]), 1889 {error, {no_such_user, LocalMid}}; 1890 ConnData -> 1891 ?d("handle_connect -> new connection" 1892 "~n ConnData: ~p", [ConnData]), 1893 %% Brand new connection, use 1894 %% When is the preliminary_mid used? 1895 create_snmp_counters(ConnHandle), 1896 %% Maybe start transaction sender 1897 ConnData2 = trans_sender_start(ConnData), 1898 ets:insert(megaco_local_conn, ConnData2), 1899 {ok, ConnData2} 1900 end; 1901 [PrelData] -> 1902 ?d("handle_connect -> connection upgrade" 1903 "~n PrelData: ~p", [PrelData]), 1904 %% OK, we need to fix the snmp counters. Used 1905 %% with the temporary (preliminary_mid) conn_handle. 1906 create_snmp_counters(ConnHandle), 1907 ConnData = PrelData#conn_data{conn_handle = ConnHandle}, 1908 trans_sender_upgrade(ConnData), 1909 ets:insert(megaco_local_conn, ConnData), 1910 ets:delete(megaco_local_conn, PrelHandle), 1911 update_snmp_counters(ConnHandle, PrelHandle), 1912 TH = ConnHandle#megaco_conn_handle{local_mid = PrelMid, 1913 remote_mid = RemoteMid}, 1914 TD = ConnData#conn_data{conn_handle = TH}, 1915 ?report_debug(TD, 1916 "Upgrade preliminary_mid to " 1917 "actual remote_mid", 1918 [{preliminary_mid, preliminary_mid}, 1919 {local_mid, LocalMid}, 1920 {remote_mid, RemoteMid}]), 1921 {ok, ConnData} 1922 end; 1923 [_ConnData] -> 1924 {error, {already_connected, ConnHandle}} 1925 end. 1926 1927handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA) -> 1928 case (catch ets:lookup(megaco_local_conn, ConnHandle)) of 1929 [#conn_data{monitor_ref = connected} = CD] -> 1930 {M, F, A} = MFA, 1931 Ref = megaco_monitor:apply_at_exit(M, F, A, ControlPid), 1932 ConnData2 = CD#conn_data{monitor_ref = Ref, 1933 control_pid = ControlPid, 1934 send_handle = SendHandle}, 1935 ets:insert(megaco_local_conn, ConnData2), 1936 {ok, Ref}; 1937 [#conn_data{monitor_ref = Ref}] -> 1938 {ok, Ref}; 1939 [] -> 1940 {error, {no_such_connection, ConnHandle}} 1941 end. 1942 1943 1944%% also trans_req == true 1945trans_sender_start(#conn_data{conn_handle = CH, 1946 auto_ack = true, 1947 trans_ack = true, 1948 trans_ack_maxcount = AcksMax, 1949 trans_req_maxcount = ReqsMax, 1950 trans_req_maxsize = ReqsMaxSz, 1951 trans_timer = To, 1952 trans_sender = undefined} = CD) 1953 when To > 0 -> 1954 1955 ?d("trans_sender_start(ack) -> entry when" 1956 "~n CH: ~p" 1957 "~n To: ~p" 1958 "~n AcksMax: ~p" 1959 "~n ReqsMax: ~p" 1960 "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]), 1961 1962 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1963 ReqsMax, AcksMax), 1964 1965 ?d("trans_sender_start(ack) -> Pid: ~p", [Pid]), 1966 1967 %% Make sure we are notified when/if the transaction 1968 %% sender goes down. 1969 %% Do we need to store the ref? Will we ever need to 1970 %% cancel this (apply_at_exit)? 1971 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 1972 1973 CD#conn_data{trans_sender = Pid}; 1974 1975trans_sender_start(#conn_data{conn_handle = CH, 1976 trans_req = true, 1977 trans_ack_maxcount = AcksMax, 1978 trans_req_maxcount = ReqsMax, 1979 trans_req_maxsize = ReqsMaxSz, 1980 trans_timer = To, 1981 trans_sender = undefined} = CD) 1982 when To > 0 -> 1983 1984 ?d("trans_sender_start(req) -> entry when" 1985 "~n CH: ~p" 1986 "~n To: ~p" 1987 "~n AcksMax: ~p" 1988 "~n ReqsMax: ~p" 1989 "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]), 1990 1991 {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz, 1992 ReqsMax, AcksMax), 1993 1994 ?d("trans_sender_start(req) -> Pid: ~p", [Pid]), 1995 1996 %% Make sure we are notified when/if the transaction 1997 %% sender goes down. 1998 %% Do we need to store the ref? Will we ever need to 1999 %% cancel this (apply_at_exit)? 2000 megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), 2001 2002 CD#conn_data{trans_sender = Pid}; 2003 2004trans_sender_start(CD) -> 2005 ?d("trans_sender_start -> undefined", []), 2006 CD#conn_data{trans_sender = undefined}. 2007 2008trans_sender_upgrade(#conn_data{conn_handle = CH, 2009 trans_sender = Pid}) 2010 when is_pid(Pid) -> 2011 ?d("trans_sende_upgrade -> entry when" 2012 "~n CH: ~p" 2013 "~n Pid: ~p", [CH, Pid]), 2014 megaco_trans_sender:upgrade(Pid, CH); 2015trans_sender_upgrade(_CD) -> 2016 ok. 2017 2018 2019handle_connect_remote(ConnHandle, UserNode, Ref) -> 2020 Pat = #remote_conn_data{conn_handle = ConnHandle, 2021 user_node = UserNode, 2022 monitor_ref = '_'}, 2023 case ets:match_object(megaco_remote_conn, Pat) of 2024 [] -> 2025 RCD = #remote_conn_data{conn_handle = ConnHandle, 2026 user_node = UserNode, 2027 monitor_ref = Ref}, 2028 ets:insert(megaco_remote_conn, RCD), 2029 ok; 2030 _ -> 2031 {error, {already_connected, ConnHandle, UserNode}} 2032 end. 2033 2034init_conn_data(RH, RemoteMid, SendHandle, ControlPid) -> 2035 init_conn_data(RH, RemoteMid, SendHandle, ControlPid, auto). 2036init_conn_data(RH, RemoteMid, SendHandle, ControlPid, Auto) -> 2037 Mid = RH#megaco_receive_handle.local_mid, 2038 ConnHandle = #megaco_conn_handle{local_mid = Mid, 2039 remote_mid = RemoteMid}, 2040 EncodingMod = RH#megaco_receive_handle.encoding_mod, 2041 EncodingConfig = RH#megaco_receive_handle.encoding_config, 2042 SendMod = RH#megaco_receive_handle.send_mod, 2043 MonitorRef = 2044 case Auto of 2045 auto -> 2046 undefined_auto_monitor_ref; 2047 {plain, ConnectorPid} -> 2048 {connecting, ConnectorPid} 2049 end, 2050 #conn_data{conn_handle = ConnHandle, 2051 serial = undefined_serial, 2052 max_serial = user_info(Mid, max_trans_id), 2053 request_timer = user_info(Mid, request_timer), 2054 long_request_timer = user_info(Mid, long_request_timer), 2055 2056 auto_ack = user_info(Mid, auto_ack), 2057 trans_ack = user_info(Mid, trans_req), 2058 trans_req = user_info(Mid, trans_req), 2059 2060 trans_timer = user_info(Mid, trans_timer), 2061 trans_req_maxsize = user_info(Mid, trans_req_maxsize), 2062 trans_req_maxcount = user_info(Mid, trans_req_maxcount), 2063 trans_ack_maxcount = user_info(Mid, trans_ack_maxcount), 2064 2065 pending_timer = user_info(Mid, pending_timer), 2066 sent_pending_limit = user_info(Mid, sent_pending_limit), 2067 recv_pending_limit = user_info(Mid, recv_pending_limit), 2068 reply_timer = user_info(Mid, reply_timer), 2069 control_pid = ControlPid, 2070 monitor_ref = MonitorRef, 2071 send_mod = SendMod, 2072 send_handle = SendHandle, 2073 encoding_mod = EncodingMod, 2074 encoding_config = EncodingConfig, 2075 protocol_version = user_info(Mid, protocol_version), 2076 auth_data = user_info(Mid, auth_data), 2077 user_mod = user_info(Mid, user_mod), 2078 user_args = user_info(Mid, user_args), 2079 reply_action = undefined, 2080 reply_data = user_info(Mid, reply_data), 2081 threaded = user_info(Mid, threaded), 2082 strict_version = user_info(Mid, strict_version), 2083 long_request_resend = user_info(Mid, long_request_resend), 2084 call_proxy_gc_timeout = user_info(Mid, call_proxy_gc_timeout), 2085 cancel = false, 2086 resend_indication = user_info(Mid, resend_indication), 2087 segment_reply_ind = user_info(Mid, segment_reply_ind), 2088 segment_recv_acc = user_info(Mid, segment_recv_acc), 2089 segment_recv_timer = user_info(Mid, segment_recv_timer), 2090 segment_send = user_info(Mid, segment_send), 2091 segment_send_timer = user_info(Mid, segment_send_timer), 2092 max_pdu_size = user_info(Mid, max_pdu_size), 2093 request_keep_alive_timeout = user_info(Mid, request_keep_alive_timeout) 2094 }. 2095 2096handle_disconnect(ConnHandle) when is_record(ConnHandle, megaco_conn_handle) -> 2097 case ets:lookup(megaco_local_conn, ConnHandle) of 2098 [ConnData] -> 2099 ets:delete(megaco_local_conn, ConnHandle), 2100 RemoteConnData = handle_disconnect_remote(ConnHandle, '_'), 2101 {ok, ConnData, RemoteConnData}; 2102 [] -> 2103 {error, {already_disconnected, ConnHandle}} 2104 end. 2105 2106handle_disconnect_remote(ConnHandle, UserNode) -> 2107 Pat = #remote_conn_data{conn_handle = ConnHandle, 2108 user_node = UserNode, 2109 monitor_ref = '_'}, 2110 RemoteConnData = ets:match_object(megaco_remote_conn, Pat), 2111 ets:match_delete(megaco_remote_conn, Pat), 2112 RemoteConnData. 2113 2114make_receive_handle(UserMid) -> 2115 #megaco_receive_handle{local_mid = UserMid, 2116 encoding_mod = user_info(UserMid, encoding_mod), 2117 encoding_config = user_info(UserMid, encoding_config), 2118 send_mod = user_info(UserMid, send_mod)}. 2119 2120 2121%%----------------------------------------------------------------- 2122%% Func: create_snmp_counters/1, update_snmp_counters/2 2123%% Description: create/update all the SNMP statistic counters 2124%%----------------------------------------------------------------- 2125 2126create_snmp_counters(CH) -> 2127 create_snmp_counters(CH, snmp_counters()). 2128 2129% create_snmp_counters(CH, []) -> 2130% ok; 2131% create_snmp_counters(CH, [Counter|Counters]) -> 2132% Key = {CH, Counter}, 2133% ets:insert(megaco_stats, {Key, 0}), 2134% create_snmp_counters(CH, Counters). 2135 2136create_snmp_counters(CH, Counters) -> 2137 F = fun(Counter) -> 2138 Key = {CH, Counter}, 2139 ets:insert(megaco_stats, {Key, 0}) 2140 end, 2141 lists:foreach(F, Counters). 2142 2143 2144update_snmp_counters(CH, PrelCH) -> 2145 update_snmp_counters(CH, PrelCH, snmp_counters()). 2146 2147update_snmp_counters(_CH, _PrelCH, []) -> 2148 ok; 2149update_snmp_counters(CH, PrelCH, [Counter|Counters]) -> 2150 PrelKey = {PrelCH, Counter}, 2151 Key = {CH, Counter}, 2152 [{PrelKey,PrelVal}] = ets:lookup(megaco_stats, PrelKey), 2153 ets:update_counter(megaco_stats, Key, PrelVal), 2154 ets:delete(megaco_stats, PrelKey), 2155 update_snmp_counters(CH, PrelCH, Counters). 2156 2157 2158global_snmp_counters() -> 2159 [medGwyGatewayNumErrors]. 2160 2161snmp_counters() -> 2162 [medGwyGatewayNumTimerRecovery, 2163 medGwyGatewayNumErrors]. 2164 2165 2166 2167%%----------------------------------------------------------------- 2168 2169%% Time in milli seconds 2170%% t() -> 2171%% {A,B,C} = erlang:now(), 2172%% A*1000000000+B*1000+(C div 1000). 2173 2174 2175%%----------------------------------------------------------------- 2176 2177%% warning_msg(F) -> 2178%% warning_msg(F, []). 2179warning_msg(F, A) -> 2180 ?megaco_warning("Config server: " ++ F, A). 2181 2182error_msg(F) -> 2183 error_msg(F, []). 2184error_msg(F, A) -> 2185 ?megaco_error("Config server: " ++ F, A). 2186 2187