⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 megaco_messenger.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
    end.fake_conn_data(CH) when is_record(CH, megaco_conn_handle) ->    case (catch megaco_config:conn_info(CH, receive_handle)) of	RH when is_record(RH, megaco_receive_handle) ->	    RemoteMid = CH#megaco_conn_handle.remote_mid,	    ConnData = 		fake_conn_data(RH, RemoteMid, no_send_handle, no_control_pid),	    ConnData#conn_data{conn_handle = CH};	{'EXIT', _} ->	    UserMid = CH#megaco_conn_handle.local_mid,	    case catch megaco_config:user_info(UserMid, receive_handle) of		{'EXIT', _} -> % No such user		    #conn_data{conn_handle        = CH,			       serial             = undefined_serial,			       control_pid        = no_control_pid,			       monitor_ref        = undefined_monitor_ref,			       send_mod           = no_send_mod,			       send_handle        = no_send_handle,			       encoding_mod       = no_encoding_mod,			       encoding_config    = no_encoding_config,			       reply_action       = undefined,			       sent_pending_limit = infinity,			       recv_pending_limit = infinity};		RH ->		    ConnData = 			fake_conn_data(RH, no_send_handle, no_control_pid),		    ConnData#conn_data{conn_handle = CH}	    end    end.fake_conn_data(RH, SendHandle, ControlPid) ->    fake_conn_data(RH, unknown_remote_mid, SendHandle, ControlPid).fake_conn_data(RH, RemoteMid, SendHandle, ControlPid) ->    case catch megaco_config:init_conn_data(RH, RemoteMid, SendHandle, ControlPid) of	{'EXIT', _} -> % No such user	    fake_user_data(RH, RemoteMid, SendHandle, ControlPid);	ConnData ->	    ConnData    end.fake_user_data(RH, RemoteMid, SendHandle, ControlPid) ->    LocalMid = RH#megaco_receive_handle.local_mid,    RH2 = RH#megaco_receive_handle{local_mid = default},    case catch megaco_config:init_conn_data(RH2, RemoteMid, SendHandle, ControlPid) of	{'EXIT', _} -> % Application stopped?	    ConnHandle     = #megaco_conn_handle{local_mid  = LocalMid,						 remote_mid = RemoteMid},	    EncodingMod    = RH#megaco_receive_handle.encoding_mod,	    EncodingConfig = RH#megaco_receive_handle.encoding_config,	    SendMod        = RH#megaco_receive_handle.send_mod,	    #conn_data{conn_handle        = ConnHandle,		       serial             = undefined_serial,		       control_pid        = ControlPid,		       monitor_ref        = undefined_monitor_ref,		       send_mod           = SendMod,		       send_handle        = SendHandle,		       encoding_mod       = EncodingMod,		       encoding_config    = EncodingConfig,		       reply_action       = undefined,		       sent_pending_limit = infinity,		       recv_pending_limit = infinity};	ConnData ->	    ConnData    end.prepare_error(Error) ->    case Error of        {error, ED} when is_record(ED, 'ErrorDescriptor') ->            Code   = ED#'ErrorDescriptor'.errorCode,            Reason = ED#'ErrorDescriptor'.errorText,            {Code, Reason, Error};        {error, [{reason, {bad_token, [BadToken, _Acc]}, Line}]} when is_integer(Line) ->            Reason = 		lists:flatten(		  io_lib:format("Illegal token (~p) on line ~w", [BadToken, Line])),            Code = ?megaco_bad_request,            {Code, Reason, Error};        {error, [{reason, {bad_token, _}, Line}]} when is_integer(Line) ->            Reason = lists:concat(["Illegal token on line ", Line]),            Code = ?megaco_bad_request,            {Code, Reason, Error};        {error, [{reason, {Line, _ParserMod, RawReasonString}} | _]} when is_integer(Line) and is_list(RawReasonString) ->	    Reason = 		case RawReasonString of		    [[$s, $y, $n, $t, $a, $x | _], TokenString] ->			lists:flatten(			  io_lib:format("Syntax error on line ~w before token ~s", [Line, TokenString]));		    _ ->			lists:flatten(io_lib:format("Syntax error on line ~w", [Line]))		end,            Code = ?megaco_bad_request,            {Code, Reason, Error};        {error, [{reason, {Line, _, _}} | _]} when is_integer(Line) ->            Reason = lists:concat(["Syntax error on line ", Line]),            Code = ?megaco_bad_request,            {Code, Reason, Error};        {error, {connection_refused, ED}} when is_record(ED,'ErrorDescriptor') ->            Code   = ED#'ErrorDescriptor'.errorCode,            Reason = ED#'ErrorDescriptor'.errorText,            {Code, Reason, Error};        {error, {connection_refused, _}} ->            Reason = "Connection refused by user",            Code = ?megaco_unauthorized,            {Code, Reason, Error};        {error, {unsupported_version, V}} ->            Reason = 		lists:flatten(io_lib:format("Unsupported version: ~w",[V])),            Code = ?megaco_version_not_supported,             {Code, Reason, Error};        {error, {not_negotiated_version, NegV, MsgV}} ->            Reason = 		lists:flatten(		  io_lib:format("Not negotiated version: ~w [negotiated ~w]",				[MsgV, NegV])),            Code = ?megaco_version_not_supported,             {Code, Reason, Error};        {error, _} ->            Reason = "Syntax error",            Code = ?megaco_bad_request,            {Code, Reason, Error};        {ok, MegaMsg} when is_record (MegaMsg, 'MegacoMessage') ->            Reason = "MID does not match config",            Code = ?megaco_incorrect_identifier,            {Code, Reason, Error};        _ ->            Reason = "Fatal syntax error",            Code = ?megaco_internal_gateway_error,            {Code, Reason, Error}    end.%% BUGBUG%% Do we need something here, if we send more then one trans per message?prepare_trans(ConnData, [Trans | Rest], AckList, ReqList)   when ConnData#conn_data.monitor_ref == undefined_monitor_ref ->    %% May occur if another process already has setup a    %% temporary connection, but the handle_connect callback    %% function has not yet returned before the eager MG    %% re-sends its initial service change message.    case Trans of        {transactionRequest, T} when is_record(T, 'TransactionRequest') ->	                Serial = T#'TransactionRequest'.transactionId,	    ConnData2 = ConnData#conn_data{serial = Serial},	    ?report_trace(ConnData2, "Pending handle_connect", [T]),	    %% ------------------------------------------	    %% 	    %%   Check pending limit	    %% 	    %% ------------------------------------------	    Limit = ConnData#conn_data.sent_pending_limit,	    TransId = to_remote_trans_id(ConnData2),	    case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of		ok ->		    send_pending(ConnData2);		error ->		    %% Pending limit:		    %% In this (granted, highly hypothetical case)		    %% we would make the user very confused if we 		    %% called the abort callback function, since 		    %% the request callback function has not yet		    %% been called. Alas, we skip this call here.		    send_pending_limit_error(ConnData);		aborted ->		    ignore	    end,	    prepare_trans(ConnData2, Rest, AckList, ReqList);	_ ->	    prepare_trans(ConnData, Rest, AckList, ReqList)    end;prepare_trans(ConnData, [Trans | Rest], AckList, ReqList) ->    ?rt1(ConnData, "prepare trans", [Trans]),    case Trans of        {transactionRequest, #'TransactionRequest'{transactionId = asn1_NOVALUE}} ->            ConnData2 = ConnData#conn_data{serial = 0},	    Code   = ?megaco_bad_request,            Reason = "Syntax error in message: transaction id missing",	    send_trans_error(ConnData2, Code, Reason),            prepare_trans(ConnData2, Rest, AckList, ReqList);        {transactionRequest, T} when is_record(T, 'TransactionRequest') ->            Serial = T#'TransactionRequest'.transactionId,            ConnData2 = ConnData#conn_data{serial = Serial},            prepare_request(ConnData2, T, Rest, AckList, ReqList);        {transactionPending, T} when is_record(T, 'TransactionPending') ->            Serial = T#'TransactionPending'.transactionId,            ConnData2 = ConnData#conn_data{serial = Serial},            handle_pending(ConnData2, T),            prepare_trans(ConnData2, Rest, AckList, ReqList);        {transactionReply, T} when is_record(T, 'TransactionReply') ->            Serial = T#'TransactionReply'.transactionId,            ConnData2 = ConnData#conn_data{serial = Serial},            handle_reply(ConnData2, T),	    prepare_trans(ConnData2, Rest, AckList, ReqList);        {transactionResponseAck, List} when is_list(List) ->            prepare_ack(ConnData, List, Rest, AckList, ReqList)    end;prepare_trans(_ConnData, [], AckList, ReqList) ->    ?SIM({AckList, ReqList}, prepare_trans_done).prepare_request(ConnData, T, Rest, AckList, ReqList) ->    ?rt2("prepare request", [T]),    LocalMid = (ConnData#conn_data.conn_handle)#megaco_conn_handle.local_mid,    TransId = to_remote_trans_id(ConnData),    ?rt2("prepare request", [LocalMid, TransId]),    case megaco_monitor:lookup_reply(TransId) of        [] ->	    ?rt3("brand new request"),            %% Brand new request	    %% Check pending limit:	    %% 	    %% We should actually check the pending limit here	    %% but since we have to do it later in the 	    %% handle_request function (just before we call	    %% the handle_trans_request callback function) we	    %% can just as well wait (this is after all a very	    %% unlikely case: see function prepare_trans when 	    %% monitor_ref == undefined_monitor_ref).	    %% 	    #conn_data{send_handle      = SendHandle,		       pending_timer    = InitTimer,		       protocol_version = Version} = ConnData,	    {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),	    M = ?MODULE,	    F = pending_timeout,	    A = [ConnData, TransId, CurrTimer],	    	    PendingRef = megaco_monitor:apply_after(M, F, A, WaitFor),            Rep = #reply{send_handle       = SendHandle,			 trans_id          = TransId,			 local_mid         = LocalMid,			 pending_timer_ref = PendingRef,			 handler           = self(),			 version           = Version},            megaco_monitor:insert_reply(Rep),            prepare_trans(ConnData, Rest, AckList, 			  [{ConnData, TransId, T} | ReqList]);        [#reply{state             = State, 		handler           = Pid,		pending_timer_ref = Ref} = Rep] 	when (State == prepare) or (State == eval_request) ->	    ?rt2("request resend", [State, Pid, Ref]),            %% Pending limit:	    %% We are still preparing/evaluating the request            %% Check if the pending limit has been exceeded...	    %% If the pending limit is _not_ exceeded then	    %% we shall send a pending (and actually restart 	    %% the pending timer, but that we cannot do).	    %% Don't care about Msg and Rep version diff	    %% ?report_trace(ignore, "still preparing/evaluating request", []),	    #conn_data{sent_pending_limit = Limit} = ConnData,	    	    case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of		ok ->		    %% ------------------------------------------		    %% 		    %%   Pending limit not exceeded		    %% 		    %%   1) Increment number of pendings sent		    %%      (done in the check function above)		    %%   2) Send pending message		    %%      (We should really restart the pending 		    %%      timer, but we have no way of doing that).		    %% 		    %% ------------------------------------------		    send_pending(ConnData),		    prepare_trans(ConnData, Rest, AckList, ReqList);		error ->		    %% -------------------------------------------		    %% 		    %%   Pending limit exceeded		    %% 		    %%   1) Cancel pending timer		    %%   2) Send 506 error message to other side		    %%   3) Inform user (depends on state)		    %%   4) Set reply in aborted state		    %% 		    %% -------------------------------------------		    %% 		    %% State == eval_request:		    %%   This means that the request is currently beeing 		    %%   evaluated by the user, and the reply timer has 		    %%   not yet been started. 		    %%   Either:		    %%   a) The "other side" will resend (which will 		    %%      trigger a pending message send) until we pass the 		    %%      pending limit 		    %%   b) We will send pending messages (when the pending 		    %%      timer expire) until we pass the pending limit.		    %%   In any event, we cannot delete the reply record		    %%   or the pending counter in this case. Is there		    %%   a risk we accumulate aborted reply records?		    %% 		    %% State == prepare:		    %%   The user does not know about this request		    %%   so we can safely perform cleanup.		    %% 		    megaco_monitor:cancel_apply_after(Ref),		    send_pending_limit_error(ConnData),		    if 			State == eval_request ->			    %% 			    %% What if the user never replies?			    %% In that case we will have a record			    %% (and counters) that is never cleaned up...			    Rep2 = Rep#reply{state             = aborted,					     pending_timer_ref = undefined},			    megaco_monitor:insert_reply(Rep2),			    handle_request_abort_callback(ConnData, 							  TransId, Pid);			true ->			    %% Since the user does not know about			    %% this call yet, it is safe to cleanup.			    %% Should we inform?			    Rep2 = Rep#reply{state = aborted},			    cancel_reply(ConnData, Rep2, aborted),			    ok		    end,		    prepare_trans(ConnData, Rest, AckList, ReqList);		aborted ->		    %% -------------------------------------------		    %% 		    %%   Pending limit already exceeded		    %% 		    %%   Cleanup, just to make sure:		    %%     reply record & pending counter		    %% 		    %% -------------------------------------------		    Rep2 = Rep#reply{state = aborted},		    cancel_reply(ConnData, Rep2, aborted),		    prepare_trans(ConnData, Rest, AckList, ReqList)	    end;        [#reply{state   = waiting_for_ack, 		bytes   = Bin, 		version = Version} = Rep] ->	    ?rt3("request resend when waiting for ack"),            %% We have already sent a reply, but the receiver            %% has obviously not got it. Resend the reply but            %% don't restart the reply_timer.            ConnData2 = ConnData#conn_data{protocol_version = Version},            ?report_trace(ConnData2, 			  "re-send trans reply", [T | {bytes, Bin}]),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -