aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/src')
-rw-r--r--lib/megaco/src/app/megaco.appup.src69
-rw-r--r--lib/megaco/src/app/megaco_internal.hrl26
-rw-r--r--lib/megaco/src/engine/megaco_config.erl439
-rw-r--r--lib/megaco/src/engine/megaco_filter.erl286
-rw-r--r--lib/megaco/src/engine/megaco_messenger.erl542
-rw-r--r--lib/megaco/src/engine/megaco_monitor.erl33
-rw-r--r--lib/megaco/src/flex/Makefile.in82
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src7
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_handler.erl45
9 files changed, 1024 insertions, 505 deletions
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 163ff06651..f939f5e6cf 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -1,19 +1,20 @@
+%% This is an -*- erlang -*- file.
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -120,43 +121,97 @@
%% |
%% v
%% 3.13
+%% |
+%% v
+%% 3.14
+%% |
+%% v
+%% 3.14.1
%%
%%
{"%VSN%",
[
+ {"3.14",
+ [
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.13",
+ [
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, soft, soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_13_1},
+ soft_purge, soft_purge, []}
+ ]
+ },
{"3.12",
[
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
{load_module, megaco_udp, soft_purge, soft_purge, []},
{load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
- {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ {update, megaco_config, soft, soft_purge, soft_purge, []},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_13_1},
+ soft_purge, soft_purge, []}
]
},
{"3.11.3",
[
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
{load_module, megaco_udp, soft_purge, soft_purge, []},
{load_module, megaco_messenger, soft_purge, soft_purge,
[megaco_config, megaco_monitor]},
{update, megaco_monitor, soft, soft_purge, soft_purge, []},
{update, megaco_config, {advanced, upgrade_from_pre_3_12},
+ soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_13_1},
soft_purge, soft_purge, []}
]
}
],
[
+ {"3.14",
+ [
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.13",
+ [
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, soft, soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_13_1},
+ soft_purge, soft_purge, []}
+ ]
+ },
{"3.12",
[
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
{load_module, megaco_udp, soft_purge, soft_purge, []},
{load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
- {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ {update, megaco_config, soft, soft_purge, soft_purge, []},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_13_1},
+ soft_purge, soft_purge, []}
]
},
{"3.11.3",
[
+ {load_module, megaco_filter, soft_purge, soft_purge, []},
{load_module, megaco_udp, soft_purge, soft_purge, []},
{load_module, megaco_messenger, soft_purge, soft_purge,
[megaco_config, megaco_monitor]},
{update, megaco_monitor, soft, soft_purge, soft_purge, []},
{update, megaco_config, {advanced, downgrade_to_pre_3_12},
+ soft_purge, soft_purge, []},
+ {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_13_1},
soft_purge, soft_purge, []}
]
}
diff --git a/lib/megaco/src/app/megaco_internal.hrl b/lib/megaco/src/app/megaco_internal.hrl
index adbaacacef..2c124e9060 100644
--- a/lib/megaco/src/app/megaco_internal.hrl
+++ b/lib/megaco/src/app/megaco_internal.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -139,6 +139,22 @@
[?APPLICATION, ?MODULE, self()|A]))).
+-define(megaco_ereport(Label, Report),
+ ?megaco_report(error_report, Label, Report)).
+
+-define(megaco_wreport(Label, Report),
+ ?megaco_report(warning_report, Label, Report)).
+
+-define(megaco_ireport(Label, Report),
+ ?megaco_report(info_report, Label, Report)).
+
+-define(megaco_report(Func, Label, Report),
+ (catch error_logger:Func([{label, Label},
+ {application, ?APPLICATION},
+ {module, ?MODULE},
+ {process, self()} | Report]))).
+
+
%%%----------------------------------------------------------------------
%%% Default (ignore) value of the Extra argument to the
%%% megaco:receive_message/5 and process_received_message functions/5.
diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl
index 2058c53973..6805db790d 100644
--- a/lib/megaco/src/engine/megaco_config.erl
+++ b/lib/megaco/src/engine/megaco_config.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -224,149 +224,278 @@ update_user_info(UserMid, orig_pending_limit, Val) ->
update_user_info(UserMid, Item, Val) ->
call({update_user_info, UserMid, Item, Val}).
-conn_info(CH, Item)
- when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) ->
- case Item of
- conn_handle ->
- CH;
- mid ->
- CH#megaco_conn_handle.local_mid;
- local_mid ->
- CH#megaco_conn_handle.local_mid;
- remote_mid ->
- CH#megaco_conn_handle.remote_mid;
- conn_data ->
- case lookup_local_conn(CH) of
- [] ->
- exit({no_such_connection, CH});
- [ConnData] ->
- ConnData
- end;
- _ ->
- case lookup_local_conn(CH) of
- [] ->
- exit({no_such_connection, CH});
- [ConnData] ->
- conn_info(ConnData, Item)
- end
+
+conn_info(Data, Item) ->
+ %% The purpose of this is a compiler optimization...
+ %% Args are processed from left to right.
+ do_conn_info(Item, Data).
+
+do_conn_info(mid = _Item, #megaco_conn_handle{local_mid = Mid}) ->
+ Mid;
+do_conn_info(local_mid = _Item, #megaco_conn_handle{local_mid = LMid}) ->
+ LMid;
+do_conn_info(remote_mid = _Item, #megaco_conn_handle{remote_mid = RMid}) ->
+ RMid;
+do_conn_info(conn_handle = _Item, CH) when is_record(CH, megaco_conn_handle) ->
+ CH;
+do_conn_info(conn_data = _Item, CH) when is_record(CH, megaco_conn_handle) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ ConnData
+ end;
+do_conn_info(Item, CH) when is_record(CH, megaco_conn_handle) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ do_conn_info(Item, ConnData)
end;
-conn_info(#conn_data{conn_handle = CH}, cancel) ->
+
+do_conn_info(cancel = _Item, #conn_data{conn_handle = CH}) ->
+ %% To minimise raise-condition propabillity,
+ %% we always look in the table instead of
+ %% in the record for this one
+ ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel);
+do_conn_info(cancel = _Item, CH) when is_record(CH, megaco_conn_handle) ->
%% To minimise raise-condition propabillity,
%% we always look in the table instead of
%% in the record for this one
ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel);
-conn_info(CD, Item) when is_record(CD, conn_data) ->
- case Item of
- all ->
- Tags0 = record_info(fields, conn_data),
- Tags1 = replace(serial, trans_id, Tags0),
- Tags = [mid, local_mid, remote_mid] ++
- replace(max_serial, max_trans_id, Tags1),
- [{Tag, conn_info(CD,Tag)} || Tag <- Tags,
- Tag /= conn_data,
- Tag /= trans_sender,
- Tag /= cancel];
- conn_data -> CD;
- conn_handle -> CD#conn_data.conn_handle;
- mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
- local_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
- remote_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.remote_mid;
- trans_id -> CH = CD#conn_data.conn_handle,
- LocalMid = CH#megaco_conn_handle.local_mid,
- Item2 = {LocalMid, trans_id_counter},
- case (catch ets:lookup(megaco_config, Item2)) of
- {'EXIT', _} ->
- undefined_serial;
- [] ->
- user_info(LocalMid, min_trans_id);
- [{_, Serial}] ->
- Max = CD#conn_data.max_serial,
- if
- ((Max =:= infinity) andalso
- is_integer(Serial) andalso
- (Serial < 4294967295)) ->
- Serial + 1;
- (Max =:= infinity) andalso
- is_integer(Serial) andalso
- (Serial =:= 4294967295) ->
- user_info(LocalMid,
- min_trans_id);
- Serial < Max ->
- Serial + 1;
- Serial =:= Max ->
- user_info(LocalMid,
- min_trans_id);
- Serial =:= 4294967295 ->
- user_info(LocalMid,
- min_trans_id);
- true ->
- undefined_serial
- end
- end;
- max_trans_id -> CD#conn_data.max_serial;
- request_timer -> CD#conn_data.request_timer;
- long_request_timer -> CD#conn_data.long_request_timer;
-
- auto_ack -> CD#conn_data.auto_ack;
-
- trans_ack -> CD#conn_data.trans_ack;
- trans_ack_maxcount -> CD#conn_data.trans_ack_maxcount;
-
- trans_req -> CD#conn_data.trans_req;
- trans_req_maxcount -> CD#conn_data.trans_req_maxcount;
- trans_req_maxsize -> CD#conn_data.trans_req_maxsize;
-
- trans_timer -> CD#conn_data.trans_timer;
-
- pending_timer -> CD#conn_data.pending_timer;
- orig_pending_limit -> CD#conn_data.sent_pending_limit;
- sent_pending_limit -> CD#conn_data.sent_pending_limit;
- recv_pending_limit -> CD#conn_data.recv_pending_limit;
- reply_timer -> CD#conn_data.reply_timer;
- control_pid -> CD#conn_data.control_pid;
- monitor_ref -> CD#conn_data.monitor_ref;
- send_mod -> CD#conn_data.send_mod;
- send_handle -> CD#conn_data.send_handle;
- encoding_mod -> CD#conn_data.encoding_mod;
- encoding_config -> CD#conn_data.encoding_config;
- protocol_version -> CD#conn_data.protocol_version;
- auth_data -> CD#conn_data.auth_data;
- user_mod -> CD#conn_data.user_mod;
- user_args -> CD#conn_data.user_args;
- reply_action -> CD#conn_data.reply_action;
- reply_data -> CD#conn_data.reply_data;
- threaded -> CD#conn_data.threaded;
- strict_version -> CD#conn_data.strict_version;
- long_request_resend -> CD#conn_data.long_request_resend;
- call_proxy_gc_timeout -> CD#conn_data.call_proxy_gc_timeout;
- cancel -> CD#conn_data.cancel;
- resend_indication -> CD#conn_data.resend_indication;
- segment_reply_ind -> CD#conn_data.segment_reply_ind;
- segment_recv_acc -> CD#conn_data.segment_recv_acc;
- segment_recv_timer -> CD#conn_data.segment_recv_timer;
- segment_send -> CD#conn_data.segment_send;
- segment_send_timer -> CD#conn_data.segment_send_timer;
- max_pdu_size -> CD#conn_data.max_pdu_size;
- request_keep_alive_timeout -> CD#conn_data.request_keep_alive_timeout;
- receive_handle ->
- LocalMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
- #megaco_receive_handle{local_mid = LocalMid,
- encoding_mod = CD#conn_data.encoding_mod,
- encoding_config = CD#conn_data.encoding_config,
- send_mod = CD#conn_data.send_mod};
- _ ->
- exit({no_such_item, Item})
+do_conn_info(all = _Item,
+ #conn_data{conn_handle = CH,
+ serial = TransId,
+ max_serial = MaxTransId,
+ request_timer = ReqTmr,
+ long_request_timer = LongReqTmr,
+ auto_ack = AutoAck,
+ trans_ack = TransAck,
+ trans_ack_maxcount = TransAckMaxCount,
+ trans_req = TransReq,
+ trans_req_maxcount = TransReqMaxCount,
+ trans_req_maxsize = TransReqMaxSz,
+ trans_timer = TransTmr,
+ %% trans_sender,
+ pending_timer = PendingTmr,
+ sent_pending_limit = SentPendingLimit,
+ recv_pending_limit = RecvPendingLimit,
+ reply_timer = ReplyTmr,
+ control_pid = CtrlPid,
+ monitor_ref = MonRef,
+ send_mod = SendMod,
+ send_handle = SendHandle,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConf,
+ protocol_version = ProtoVersion,
+ auth_data = AuthData,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = ReplyAction,
+ reply_data = ReplyData,
+ threaded = Threaded,
+ strict_version = StrictVersion,
+ long_request_resend = LongReqResend,
+ call_proxy_gc_timeout = CallProxyGCTimeout,
+ %% cancel,
+ resend_indication = ResendInd,
+ segment_reply_ind = SegReplyInd,
+ segment_recv_acc = SegRecvAcc,
+ segment_recv_timer = SegRecvTmr,
+ segment_send = SegSend,
+ segment_send_timer = SegSendTmr,
+ max_pdu_size = MaxPduSz,
+ request_keep_alive_timeout = RequestKeepAliveTmr}) ->
+ [{conn_handle, CH},
+ {trans_id, TransId},
+ {max_trans_id, MaxTransId},
+ {request_timer, ReqTmr},
+ {long_request_timer, LongReqTmr},
+ {mid, CH#megaco_conn_handle.local_mid},
+ {local_mid, CH#megaco_conn_handle.local_mid},
+ {remote_mid, CH#megaco_conn_handle.remote_mid},
+ {auto_ack, AutoAck},
+ {trans_ack, TransAck},
+ {trans_ack_maxcount, TransAckMaxCount},
+ {trans_req, TransReq},
+ {trans_req_maxcount, TransReqMaxCount},
+ {trans_req_maxsize, TransReqMaxSz},
+ {trans_timer, TransTmr},
+ {pending_timer, PendingTmr},
+ {sent_pending_limit, SentPendingLimit},
+ {recv_pending_limit, RecvPendingLimit},
+ {reply_timer, ReplyTmr},
+ {control_pid, CtrlPid},
+ {monitor_ref, MonRef},
+ {send_mod, SendMod},
+ {send_handle, SendHandle},
+ {encoding_mod, EncodingMod},
+ {encoding_config, EncodingConf},
+ {protocol_version, ProtoVersion},
+ {auth_data, AuthData},
+ {user_mod, UserMod},
+ {user_args, UserArgs},
+ {reply_action, ReplyAction},
+ {reply_data, ReplyData},
+ {threaded, Threaded},
+ {strict_version, StrictVersion},
+ {long_request_resend, LongReqResend},
+ {call_proxy_gc_timeout, CallProxyGCTimeout},
+ {resend_indication, ResendInd},
+ {segment_reply_ind, SegReplyInd},
+ {segment_recv_acc, SegRecvAcc},
+ {segment_recv_timer, SegRecvTmr},
+ {segment_send, SegSend},
+ {segment_send_timer, SegSendTmr},
+ {max_pdu_size, MaxPduSz},
+ {request_keep_alive_timeout, RequestKeepAliveTmr}];
+
+do_conn_info(conn_data = _Item, CD) ->
+ CD;
+do_conn_info(conn_handle = _Item, #conn_data{conn_handle = Val}) ->
+ Val;
+do_conn_info(mid = _Item,
+ #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) ->
+ Val;
+do_conn_info(local_mid = _Item,
+ #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) ->
+ Val;
+do_conn_info(remote_mid = _Item,
+ #conn_data{conn_handle = #megaco_conn_handle{remote_mid = Val}}) ->
+ Val;
+do_conn_info(trans_id = _Item,
+ #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid},
+ max_serial = Max}) ->
+ Item2 = {LMid, trans_id_counter},
+ case (catch ets:lookup(megaco_config, Item2)) of
+ {'EXIT', _} ->
+ undefined_serial;
+ [] ->
+ user_info(LMid, min_trans_id);
+ [{_, Serial}] ->
+ if
+ ((Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial < 4294967295)) ->
+ Serial + 1;
+ ((Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial =:= 4294967295)) ->
+ user_info(LMid, min_trans_id);
+ Serial < Max ->
+ Serial + 1;
+ Serial =:= Max ->
+ user_info(LMid, min_trans_id);
+ Serial =:= 4294967295 ->
+ user_info(LMid, min_trans_id);
+ true ->
+ undefined_serial
+ end
end;
-conn_info(BadHandle, _Item) ->
- {error, {no_such_connection, BadHandle}}.
-
-replace(_, _, []) ->
- [];
-replace(Item, WithItem, [Item|List]) ->
- [WithItem|List];
-replace(Item, WithItem, [OtherItem|List]) ->
- [OtherItem | replace(Item, WithItem, List)].
+do_conn_info(max_trans_id = _Item, #conn_data{max_serial = Val}) ->
+ Val;
+do_conn_info(request_timer = _Item, #conn_data{request_timer = Val}) ->
+ Val;
+do_conn_info(long_request_timer = _Item, #conn_data{long_request_timer = Val}) ->
+ Val;
+do_conn_info(auto_ack = _Item, #conn_data{auto_ack = Val}) ->
+ Val;
+do_conn_info(trans_ack = _Item, #conn_data{trans_ack = Val}) ->
+ Val;
+do_conn_info(trans_ack_maxcount = _Item, #conn_data{trans_ack_maxcount = Val}) ->
+ Val;
+do_conn_info(trans_req = _Item, #conn_data{trans_req = Val}) ->
+ Val;
+do_conn_info(trans_req_maxcount = _Item, #conn_data{trans_req_maxcount = Val}) ->
+ Val;
+do_conn_info(trans_req_maxsize = _Item, #conn_data{trans_req_maxsize = Val}) ->
+ Val;
+do_conn_info(trans_timer = _Item, #conn_data{trans_timer = Val}) ->
+ Val;
+do_conn_info(pending_timer = _Item, #conn_data{pending_timer = Val}) ->
+ Val;
+do_conn_info(orig_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) ->
+ Val;
+do_conn_info(sent_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) ->
+ Val;
+do_conn_info(recv_pending_limit = _Item, #conn_data{recv_pending_limit = Val}) ->
+ Val;
+do_conn_info(reply_timer = _Item, #conn_data{reply_timer = Val}) ->
+ Val;
+do_conn_info(control_pid = _Item, #conn_data{control_pid = Val}) ->
+ Val;
+do_conn_info(send_mod = _Item, #conn_data{send_mod = Val}) ->
+ Val;
+do_conn_info(send_handle = _Item, #conn_data{send_handle = Val}) ->
+ Val;
+do_conn_info(encoding_mod = _Item, #conn_data{encoding_mod = Val}) ->
+ Val;
+do_conn_info(encoding_config = _Item, #conn_data{encoding_config = Val}) ->
+ Val;
+do_conn_info(protocol_version = _Item, #conn_data{protocol_version = Val}) ->
+ Val;
+do_conn_info(auth_data = _Item, #conn_data{auth_data = Val}) ->
+ Val;
+do_conn_info(user_mod = _Item, #conn_data{user_mod = Val}) ->
+ Val;
+do_conn_info(user_args = _Item, #conn_data{user_args = Val}) ->
+ Val;
+do_conn_info(reply_action = _Item, #conn_data{reply_action = Val}) ->
+ Val;
+do_conn_info(reply_data = _Item, #conn_data{reply_data = Val}) ->
+ Val;
+do_conn_info(threaded = _Item, #conn_data{threaded = Val}) ->
+ Val;
+do_conn_info(strict_version = _Item, #conn_data{strict_version = Val}) ->
+ Val;
+do_conn_info(long_request_resend = _Item,
+ #conn_data{long_request_resend = Val}) ->
+ Val;
+do_conn_info(call_proxy_gc_timeout = _Item,
+ #conn_data{call_proxy_gc_timeout = Val}) ->
+ Val;
+do_conn_info(resend_indication = _Item, #conn_data{resend_indication = Val}) ->
+ Val;
+do_conn_info(segment_reply_ind = _Item, #conn_data{segment_reply_ind = Val}) ->
+ Val;
+do_conn_info(segment_recv_acc = _Item, #conn_data{segment_recv_acc = Val}) ->
+ Val;
+do_conn_info(segment_recv_timer = _Item,
+ #conn_data{segment_recv_timer = Val}) ->
+ Val;
+do_conn_info(segment_send = _Item, #conn_data{segment_send = Val}) ->
+ Val;
+do_conn_info(segment_send_timer = _Item,
+ #conn_data{segment_send_timer = Val}) ->
+ Val;
+do_conn_info(max_pdu_size = _Item, #conn_data{max_pdu_size = Val}) ->
+ Val;
+do_conn_info(request_keep_alive_timeout = _Item,
+ #conn_data{request_keep_alive_timeout = Val}) ->
+ Val;
+do_conn_info(receive_handle = _Item,
+ #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid},
+ encoding_mod = EM,
+ encoding_config = EC,
+ send_mod = SM}) ->
+ #megaco_receive_handle{local_mid = LMid,
+ encoding_mod = EM,
+ encoding_config = EC,
+ send_mod = SM};
+do_conn_info(Item, Data)
+ when is_record(Data, conn_data) orelse is_record(Data, megaco_conn_handle) ->
+ exit({no_such_item, Item});
+do_conn_info(_Item, BadData) ->
+ {error, {no_such_connection, BadData}}.
+
+
+%% replace(_, _, []) ->
+%% [];
+%% replace(Item, WithItem, [Item|List]) ->
+%% [WithItem|List];
+%% replace(Item, WithItem, [OtherItem|List]) ->
+%% [OtherItem | replace(Item, WithItem, List)].
update_conn_info(#conn_data{conn_handle = CH}, Item, Val) ->
@@ -499,31 +628,19 @@ incr_counter(Item, Incr) ->
end
catch
error:_ ->
+ %% Counter does not exist, so try creat it
try
begin
cre_counter(Item, Incr)
end
catch
exit:_ ->
- %% Ok, some other process got there before us,
- %% so try again
+ %% This is a raise condition.
+ %% When we tried to update the counter above, it
+ %% did not exist, but now it does...
ets:update_counter(megaco_config, Item, Incr)
end
end.
-%% incr_counter(Item, Incr) ->
-%% case (catch ets:update_counter(megaco_config, Item, Incr)) of
-%% {'EXIT', _} ->
-%% case (catch cre_counter(Item, Incr)) of
-%% {'EXIT', _} ->
-%% %% Ok, some other process got there before us,
-%% %% so try again
-%% ets:update_counter(megaco_config, Item, Incr);
-%% NewVal ->
-%% NewVal
-%% end;
-%% NewVal ->
-%% NewVal
-%% end.
cre_counter(Item, Initial) ->
case whereis(?SERVER) =:= self() of
@@ -531,8 +648,8 @@ cre_counter(Item, Initial) ->
case call({cre_counter, Item, Initial}) of
{ok, Value} ->
Value;
- Error ->
- exit(Error)
+ {error, Reason} ->
+ exit({failed_creating_counter, Item, Initial, Reason})
end;
true ->
%% Check that the counter does not already exists
@@ -542,7 +659,7 @@ cre_counter(Item, Initial) ->
ets:insert(megaco_config, {Item, Initial}),
{ok, Initial};
[_] ->
- %% Ouch, now what?
+ %% Possibly a raise condition
{error, already_exists}
end
@@ -1432,7 +1549,7 @@ verify_val(Item, Val) ->
segment_send_timer -> verify_timer(Val);
max_pdu_size -> verify_int(Val) andalso (Val > 0);
request_keep_alive_timeout ->
- (verify_int(Val) andalso (Val >= 0)) orelse (Val =:= plain);
+ (verify_uint(Val) orelse (Val =:= plain));
_ -> false
end.
diff --git a/lib/megaco/src/engine/megaco_filter.erl b/lib/megaco/src/engine/megaco_filter.erl
index 23a91b1f1d..9df752789c 100644
--- a/lib/megaco/src/engine/megaco_filter.erl
+++ b/lib/megaco/src/engine/megaco_filter.erl
@@ -1,37 +1,83 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
%%----------------------------------------------------------------------
-%% Purpose : megaco/H.248 customization of generic event tracer
+%% Purpose : Megaco/H.248 customization of the Event Tracer tool
%%----------------------------------------------------------------------
-module(megaco_filter).
--export([start/0, start/1, filter/1,
+-export([start/0, start/1, filter/1, raw_filter/1,
pretty_error/1, string_to_term/1]).
+
-include_lib("megaco/include/megaco.hrl").
-include_lib("megaco/include/megaco_message_v1.hrl").
-include_lib("megaco/src/app/megaco_internal.hrl").
-include_lib("et/include/et.hrl").
+%%----------------------------------------------------------------------
+%% BUGBUG: There are some opportunities for improvements:
+%%
+%% * This version of the module does only handle version 1 of the messages.
+%%
+%% * The record definition of megaco_transaction_reply is copied from
+%% megaco_message_internal.hrl as that header file contains some
+%% records that already are defined in megaco_message_{v1,v2,v3}.hrl.
+%% * The records megaco_udp and megaco_tcp are copied from the files
+%% megaco_udp.hrl and megaco_tcp.hrl respectively, as we cannot include
+%% both header files. They both defines the macros HEAP_SIZE and GC_MSG_LIMIT.
+
+%%-include("megaco_message_internal.hrl").
+-record('megaco_transaction_reply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+%% -include_lib("megaco/src/udp/megaco_udp.hrl").
+-record(megaco_udp,
+ {port,
+ options = [],
+ socket,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+
+%% -include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-record(megaco_tcp,
+ {host,
+ port,
+ options = [],
+ socket,
+ proxy_pid,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+%%----------------------------------------------------------------------
+
start() ->
start([]).
@@ -47,11 +93,20 @@ start(ExtraOptions) ->
{title, "Megaco tracer - Erlang/OTP"} | ExtraOptions],
et_viewer:start(Options).
-filter(E) when is_record(E, event) ->
+filter(E) ->
+ case catch raw_filter(E) of
+ {'EXIT', Reason} = Error->
+ io:format("~p: ~p\n", [?MODULE, Error]),
+ exit(Reason);
+ E2 ->
+ E2
+ end.
+
+raw_filter(E) when is_record(E, event) ->
From = filter_actor(E#event.from),
To = filter_actor(E#event.to),
E2 = E#event{from = From, to = To},
- E3 = filter_contents(E#event.contents, E2, []),
+ E3 = filter_contents(E#event.contents, E2),
{true, E3}.
filter_actors(From, To, E)
@@ -101,6 +156,9 @@ filter_user_actor(Actor) ->
do_filter_actor(CH) when is_record(CH, megaco_conn_handle) ->
Mid = CH#megaco_conn_handle.local_mid,
do_filter_actor(Mid);
+do_filter_actor(RH) when is_record(RH, megaco_receive_handle) ->
+ Mid = RH#megaco_receive_handle.local_mid,
+ do_filter_actor(Mid);
do_filter_actor(Actor) ->
case Actor of
{ip4Address, {'IP4Address', [A1,A2,A3,A4], asn1_NOVALUE}} ->
@@ -130,86 +188,108 @@ do_filter_actor(Actor) ->
"UNKNOWN"
end.
-filter_contents([], E, Contents) ->
- E#event{contents = lists:flatten(lists:reverse(Contents))};
-filter_contents([H | T], E, Contents) ->
+
+filter_contents(Contents, E) ->
+ do_filter_contents(Contents, E, missing_conn_data, []).
+
+do_filter_contents([H | T], E, ConnData, Contents) ->
case H of
- {line, _Mod, _Line} ->
- filter_contents(T, E, Contents);
+ Udp when is_record(Udp, megaco_udp) ->
+ RH = Udp#megaco_udp.receive_handle,
+ Actor = filter_actor(RH),
+ E2 = E#event{from = Actor, to = Actor},
+ Pretty =
+ ["Port: ", integer_to_list(Udp#megaco_udp.port), "\n",
+ "Encoder: ", atom_to_list(RH#megaco_receive_handle.encoding_mod)],
+ do_filter_contents(T, E2, ConnData, [[Pretty, "\n"], Contents]);
+ Tcp when is_record(Tcp, megaco_tcp) ->
+ RH = Tcp#megaco_tcp.receive_handle,
+ Actor = filter_actor(RH),
+ E2 = E#event{from = Actor, to = Actor},
+ Pretty =
+ ["Port: ", integer_to_list(Tcp#megaco_tcp.port), "\n",
+ "Encoder: ", atom_to_list(RH#megaco_receive_handle.encoding_mod)],
+ do_filter_contents(T, E2, ConnData, [[Pretty, "\n"], Contents]);
CD when is_record(CD, conn_data) ->
CH = CD#conn_data.conn_handle,
From = CH#megaco_conn_handle.local_mid,
- To = CH#megaco_conn_handle.remote_mid,
+ To = CH#megaco_conn_handle.remote_mid,
E2 = filter_actors(From, To, E),
Serial = CD#conn_data.serial,
E3 = append_serial(Serial, E2),
- filter_contents(T, E3, Contents);
+ do_filter_contents(T, E3, CD, Contents);
CH when is_record(CH, megaco_conn_handle) ->
From = CH#megaco_conn_handle.local_mid,
- To = CH#megaco_conn_handle.remote_mid,
+ To = CH#megaco_conn_handle.remote_mid,
E2 = filter_actors(From, To, E),
- filter_contents(T, E2, Contents);
- {orig_conn_handle, _CH} ->
- filter_contents(T, E, Contents);
+ do_filter_contents(T, E2, ConnData, Contents);
RH when is_record(RH, megaco_receive_handle) ->
Actor = RH#megaco_receive_handle.local_mid,
E2 = filter_actors(Actor, Actor, E),
- filter_contents(T, E2, Contents);
- {pid, Pid} when is_pid(Pid) ->
- filter_contents(T, E, Contents);
- pending ->
- filter_contents(T, E, Contents);
- reply ->
- filter_contents(T, E, Contents);
+ do_filter_contents(T, E2, ConnData, Contents);
{error, Reason} ->
Pretty = pretty_error({error, Reason}),
E2 = prepend_error(E),
- filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ do_filter_contents(T, E2, ConnData, [[Pretty, "\n"], Contents]);
{'EXIT', Reason} ->
Pretty = pretty_error({'EXIT', Reason}),
E2 = prepend_error(E),
- filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ do_filter_contents(T, E2, ConnData, [[Pretty, "\n"], Contents]);
ED when is_record(ED, 'ErrorDescriptor') ->
Pretty = pretty_error(ED),
E2 = prepend_error(E),
- filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ do_filter_contents(T, E2, ConnData, [[Pretty, "\n"], Contents]);
Trans when is_record(Trans, 'TransactionRequest') ->
- Pretty = pretty({trans, {transactionRequest, Trans}}),
- filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, {trans, {transactionRequest, Trans}}),
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
+ {transactionRequest, Trans} when is_record(Trans, 'TransactionRequest') ->
+ Pretty = pretty(ConnData, {trans, {transactionRequest, Trans}}),
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
Trans when is_record(Trans, 'TransactionReply') ->
- Pretty = pretty({trans, {transactionReply, Trans}}),
- filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, {trans, {transactionReply, Trans}}),
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, megaco_transaction_reply) ->
+ %% BUGBUG: Version 1 special
+ TransV1 =
+ #'TransactionReply'{transactionId = Trans#megaco_transaction_reply.transactionId,
+ immAckRequired = Trans#megaco_transaction_reply.immAckRequired,
+ transactionResult = Trans#megaco_transaction_reply.transactionResult},
+ Pretty = pretty(ConnData, {trans, {transactionReply, TransV1}}),
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
Trans when is_record(Trans, 'TransactionPending') ->
- Pretty = pretty({trans, {transactionPending, Trans}}),
- filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, {trans, {transactionPending, Trans}}),
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
Trans when is_record(Trans, 'TransactionAck') ->
- Pretty = pretty({trans, {transactionResponseAck, [Trans]}}),
+ Pretty = pretty(ConnData, {trans, {transactionResponseAck, [Trans]}}),
case Trans#'TransactionAck'.lastAck of
asn1_NOVALUE ->
- filter_contents([], E, [[Pretty, "\n"], Contents]);
+ do_filter_contents([], E, ConnData, [[Pretty, "\n"], Contents]);
Last ->
Label = term_to_string(E#event.label),
E2 = E#event{label = Label ++ ".." ++ integer_to_list(Last)},
- filter_contents([], E2, [[Pretty, "\n"], Contents])
+ do_filter_contents([], E2, ConnData, [[Pretty, "\n"], Contents])
end;
{context_id, _ContextId} ->
- Pretty = pretty(H),
- filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, H),
+ do_filter_contents(T, E, ConnData, [[Pretty, "\n"], Contents]);
{command_request, CmdReq} ->
- Pretty = pretty(CmdReq),
- filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, CmdReq),
+ do_filter_contents(T, E, ConnData, [[Pretty, "\n"], Contents]);
{user_reply, {ok, ARS}} ->
- Pretty = [[pretty(AR), "\n"] || AR <- ARS],
- filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ Pretty = [[pretty(ConnData, AR), "\n"] || AR <- ARS],
+ do_filter_contents(T, E, ConnData, [["USER REPLY OK: \n", Pretty, "\n"], Contents]);
{user_reply, Error} ->
Pretty = pretty_error(Error),
- filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ do_filter_contents(T, E, ConnData, [["USER REPLY ERROR: \n", Pretty, "\n"], Contents]);
{actionReplies, ARS} ->
- Pretty = [[pretty(AR), "\n"] || AR <- ARS],
- filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ Pretty = [[pretty(ConnData, AR), "\n"] || AR <- ARS],
+ do_filter_contents(T, E, ConnData, [["ACTION REPLIES: \n", Pretty, "\n"], Contents]);
MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
- Pretty = pretty(MegaMsg),
- filter_contents(T, E, [["MESSAGE: \n", Pretty, "\n"], Contents]);
+ Pretty = pretty(ConnData, MegaMsg),
+ do_filter_contents(T, E, ConnData, [Pretty, "\n", Contents]);
+ {message, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ Pretty = pretty(ConnData, MegaMsg),
+ do_filter_contents(T, E, ConnData, [Pretty, "\n", Contents]);
{bytes, Bin} when is_binary(Bin) ->
E2 =
case E#event.label of
@@ -223,15 +303,37 @@ filter_contents([H | T], E, Contents) ->
E
end,
CharList = erlang:binary_to_list(Bin),
- filter_contents(T, E2, [[CharList , "\n"], Contents]);
- [] ->
- filter_contents(T, E, Contents);
+ do_filter_contents(T, E2, ConnData, [[CharList , "\n"], Contents]);
+ List when is_list(List) ->
+ %% BUGBUG: Workaround as megaco_messenger puts nested lists in its traces
+ do_filter_contents(List ++ T, E, ConnData, Contents);
+ Int when is_integer(Int) ->
+ %% BUGBUG: Workaround as megaco_messenger puts nested lists in its traces
+ do_filter_contents(T, E, ConnData, Contents);
+ {line, _Mod, _Line} ->
+ do_filter_contents(T, E, ConnData, Contents);
+ {orig_conn_handle, _CH} ->
+ do_filter_contents(T, E, ConnData, Contents);
+ {pid, Pid} when is_pid(Pid) ->
+ do_filter_contents(T, E, ConnData, Contents);
+ pending ->
+ do_filter_contents(T, E, ConnData, Contents);
+ reply ->
+ do_filter_contents(T, E, ConnData, Contents);
{test_lib, _Mod, _Fun} ->
- filter_contents(T, E, Contents);
+ do_filter_contents(T, E, ConnData, Contents);
+ {trans_id, _TransId} ->
+ do_filter_contents(T, E, ConnData, Contents);
+ {send_func, _FunName} ->
+ do_filter_contents(T, E, ConnData, Contents);
+ Pid when is_pid(Pid) ->
+ do_filter_contents(T, E, ConnData, Contents);
Other ->
- Pretty = pretty(Other),
- filter_contents(T, E, [[Pretty, "\n"], Contents])
- end.
+ Pretty = pretty(ConnData, Other),
+ do_filter_contents(T, E, ConnData, [[Pretty, "\n"], Contents])
+ end;
+do_filter_contents([], E, _ConnData, Contents) ->
+ E#event{contents = lists:flatten(lists:reverse(Contents))}.
append_serial(Serial, E) when is_integer(Serial) ->
Label = term_to_string(E#event.label),
@@ -243,7 +345,7 @@ prepend_error(E) ->
Label = term_to_string(E#event.label),
E#event{label = "<ERROR> " ++ Label}.
-pretty({context_id, ContextId}) ->
+pretty(_ConnData, {context_id, ContextId}) ->
if
ContextId =:= ?megaco_null_context_id ->
["CONTEXT ID: -\n"];
@@ -254,61 +356,33 @@ pretty({context_id, ContextId}) ->
is_integer(ContextId) ->
["CONTEXT ID: ",integer_to_list(ContextId), "\n"]
end;
-pretty(MegaMsg) when is_record(MegaMsg, 'MegacoMessage') ->
- case catch megaco_pretty_text_encoder:encode_message([], MegaMsg) of
- {ok, Bin} ->
- term_to_string(Bin);
- _Bad ->
- term_to_string(MegaMsg)
- end;
-pretty(CmdReq) when is_record(CmdReq, 'CommandRequest') ->
- case catch megaco_pretty_text_encoder:encode_command_request(CmdReq) of
- {ok, IoList} ->
- IoList2 = lists:flatten(IoList),
- term_to_string(IoList2);
- _Bad ->
- term_to_string(CmdReq)
- end;
-pretty({complete_success, ContextId, RepList} = Res) ->
+pretty(_ConnData, MegaMsg) when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, Bin} = megaco_pretty_text_encoder:encode_message([], MegaMsg),
+ term_to_string(Bin);
+pretty(_ConnData, CmdReq) when is_record(CmdReq, 'CommandRequest') ->
+ {ok, IoList} = megaco_pretty_text_encoder:encode_command_request(CmdReq),
+ term_to_string(lists:flatten(IoList));
+pretty(_ConnData, {complete_success, ContextId, RepList}) ->
ActRep = #'ActionReply'{contextId = ContextId,
commandReply = RepList},
- case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
- {ok, IoList} ->
- IoList2 = lists:flatten(IoList),
- term_to_string(IoList2);
- _Bad ->
- term_to_string(Res)
- end;
-pretty(AR) when is_record(AR, 'ActionReply') ->
- case catch megaco_pretty_text_encoder:encode_action_reply(AR) of
- {ok, IoList} ->
- IoList2 = lists:flatten(IoList),
- term_to_string(IoList2);
- _Bad ->
- term_to_string(AR)
- end;
-pretty({partial_failure, ContextId, RepList} = Res) ->
+ {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(ActRep),
+ term_to_string(lists:flatten(IoList));
+pretty(_ConnData, AR) when is_record(AR, 'ActionReply') ->
+ {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(AR),
+ term_to_string(lists:flatten(IoList));
+pretty(_ConnData, {partial_failure, ContextId, RepList}) ->
ActRep = #'ActionReply'{contextId = ContextId,
commandReply = RepList},
- case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
- {ok, IoList} ->
- IoList2 = lists:flatten(IoList),
- term_to_string(IoList2);
- _Bad ->
- term_to_string(Res)
- end;
-pretty({trans, Trans}) ->
- case catch megaco_pretty_text_encoder:encode_transaction(Trans) of
+ {ok, IoList} = megaco_pretty_text_encoder:encode_action_reply(ActRep),
+ term_to_string(lists:flatten(IoList));
+pretty(_ConnData, {trans, Trans}) ->
+ case megaco_pretty_text_encoder:encode_transaction(Trans) of
{ok, Bin} when is_binary(Bin) ->
- IoList2 = lists:flatten(binary_to_list(Bin)),
- term_to_string(IoList2);
+ term_to_string(binary_to_list(Bin));
{ok, IoList} ->
- IoList2 = lists:flatten(IoList),
- term_to_string(IoList2);
- _Bad ->
- term_to_string(Trans)
+ term_to_string(lists:flatten(IoList))
end;
-pretty(Other) ->
+pretty(__ConnData, Other) ->
term_to_string(Other).
pretty_error({error, Reason}) ->
diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl
index a9e4fd67b2..5fad29931b 100644
--- a/lib/megaco/src/engine/megaco_messenger.erl
+++ b/lib/megaco/src/engine/megaco_messenger.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -99,20 +99,22 @@
%% N.B. Update cancel/1 with '_' when a new field is added
-record(reply,
{
- trans_id,
- local_mid,
- state = prepare, % prepare | eval_request | waiting_for_ack | aborted
- pending_timer_ref,
- handler = undefined, % pid of the proc executing the callback func
- timer_ref,
- version,
- %% bytes: Sent reply data: not acknowledged
- bytes, % binary() | [{integer(), binary(), timer_ref()}]
- ack_action, % discard_ack | {handle_ack, Data}
- send_handle,
- %% segments: Not sent reply data (segments)
- segments = [] % [{integer(), binary()}]
- }).
+ trans_id,
+ local_mid,
+ state = prepare, % prepare | eval_request | waiting_for_ack | aborted
+ pending_timer_ref,
+ handler = undefined, % pid of the proc executing the callback func
+ timer_ref,
+ version,
+ %% bytes: Sent reply data: not acknowledged
+ bytes, % binary() | [{integer(), binary(), timer_ref()}]
+ ack_action, % discard_ack | {handle_ack, Data}
+ send_handle,
+ %% segments: Not sent reply data (segments)
+ segments = [], % [{integer(), binary()}]
+ user_mod,
+ user_args
+ }).
-record(trans_id,
{
@@ -1203,7 +1205,7 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
LocalMid = ConnHandle#megaco_conn_handle.local_mid,
TransId = to_remote_trans_id(ConnData),
?rt2("prepare request", [LocalMid, TransId]),
- case megaco_monitor:lookup_reply(TransId) of
+ case lookup_reply(ConnData, TransId) of
[] ->
?rt3("brand new request"),
@@ -1222,18 +1224,22 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
#conn_data{send_handle = SendHandle,
pending_timer = InitTimer,
- protocol_version = Version} = ConnData,
+ protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs} = ConnData,
{WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
M = ?MODULE,
F = pending_timeout,
- A = [ConnHandle, TransId, CurrTimer],
+ A = [ConnHandle, 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},
+ version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs},
case megaco_monitor:insert_reply_new(Rep) of
true ->
prepare_normal_trans(ConnData, Rest, AckList,
@@ -1250,9 +1256,14 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
Extra)
end;
- [#reply{state = State,
+ %% We can ignore the Converted value here as we *know*
+ %% conn-data to be correct (not faked), so even if
+ %% the record was converted, it will now have correct
+ %% values for user_mod and user_args.
+ {_Converted,
+ #reply{state = State,
handler = Pid,
- pending_timer_ref = Ref} = Rep]
+ pending_timer_ref = Ref} = Rep}
when (State =:= prepare) orelse (State =:= eval_request) ->
?rt2("request resend", [State, Pid, Ref]),
@@ -1364,9 +1375,14 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
end;
- [#reply{state = waiting_for_ack,
+ %% We can ignore the Converted value here as we *know*
+ %% conn-data to be correct (not faked), so even if
+ %% the record was converted, it will now have correct
+ %% values for user_mod and user_args.
+ {_Converted,
+ #reply{state = waiting_for_ack,
bytes = Bin,
- version = Version} = Rep] ->
+ version = Version} = Rep} ->
?rt3("request resend when waiting for ack"),
%% We have already sent a reply, but the receiver
@@ -1384,7 +1400,13 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
end,
prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
- [#reply{state = aborted} = Rep] ->
+
+ %% We can ignore the Converted value here as we *know*
+ %% conn-data to be correct (not faked), so even if
+ %% the record was converted, it will now have correct
+ %% values for user_mod and user_args.
+ {_Converted,
+ #reply{state = aborted} = Rep} ->
?rt3("request resend when already in aborted state"),
%% OTP-4956:
@@ -1424,15 +1446,15 @@ prepare_ack(ConnData, [], Rest, AckList, ReqList, Extra) ->
do_prepare_ack(ConnData, T, AckList) ->
TransId = to_remote_trans_id(ConnData),
- case megaco_monitor:lookup_reply(TransId) of
+ case lookup_reply(ConnData, TransId) of
[] ->
%% The reply has already been garbage collected. Ignore.
?report_trace(ConnData, "discard ack (no receiver)", [T]),
AckList;
- [Rep] when Rep#reply.state =:= waiting_for_ack ->
+ {_Converted, Rep} when Rep#reply.state =:= waiting_for_ack ->
%% Don't care about Msg and Rep version diff
[{ConnData, Rep, T} | AckList];
- [_Rep] ->
+ {_Converted, _Rep} ->
%% Protocol violation from the sender of this ack
?report_important(ConnData, "<ERROR> discard trans",
[T, {error, "got ack before reply was sent"}]),
@@ -1519,30 +1541,6 @@ check_pending_limit(Limit, Direction, TransId) ->
aborted
end.
-%% check_pending_limit(infinity, _, _) ->
-%% {ok, 0};
-%% check_pending_limit(Limit, Direction, TransId) ->
-%% ?rt2("check pending limit", [Direction, Limit, TransId]),
-%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
-%% {'EXIT', _} ->
-%% %% This function is only called when we "know" the
-%% %% counter to exist. So, the only reason that this
-%% %% would happen is of the counter has been removed.
-%% %% This only happen if the pending limit has been
-%% %% reached. In any case, this is basically the same
-%% %% as aborted!
-%% ?rt2("check pending limit - exit", []),
-%% aborted;
-%% Val when Val =< Limit ->
-%% %% Since we have no intention to increment here, it
-%% %% is ok to be _at_ the limit
-%% ?rt2("check pending limit - ok", [Val]),
-%% {ok, Val};
-%% _Val ->
-%% ?rt2("check pending limit - aborted", [_Val]),
-%% aborted
-%% end.
-
check_and_maybe_incr_pending_limit(infinity, _, _) ->
ok;
@@ -1550,59 +1548,42 @@ check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
%%
%% We need this kind of test to detect when we _pass_ the limit
%%
- ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
+ ?rt2("check and maybe incr pending limit", [{direction, Direction},
+ {transaction_id, TransId},
+ {counter_limit, Limit}]),
try megaco_config:get_pending_counter(Direction, TransId) of
Val when Val > Limit ->
- ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
+ ?rt2("check and maybe incr - aborted", [{counter_value, Val}]),
aborted; % Already passed the limit
Val ->
- ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
+ ?rt2("check and maybe incr - incr", [{counter_value, Val}]),
megaco_config:incr_pending_counter(Direction, TransId),
if
Val < Limit ->
ok; % Still within the limit
true ->
?rt2("check and maybe incr - error",
- [Direction, Val, Limit]),
+ [{counter_value, Val}]),
error % Passed the limit
end
catch
_:_ ->
%% Has not been created yet (connect).
- megaco_config:cre_pending_counter(Direction, TransId, 1),
- ok
+ %% Try create it, but bevare of possible raise condition
+ try
+ begin
+ megaco_config:cre_pending_counter(Direction, TransId, 1),
+ ok
+ end
+ catch
+ _:_ ->
+ %% Ouch, raise condition, increment instead...
+ megaco_config:incr_pending_counter(Direction, TransId),
+ ok
+ end
end.
-%% check_and_maybe_incr_pending_limit(infinity, _, _) ->
-%% ok;
-%% check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
-%% %%
-%% %% We need this kind of test to detect when we _pass_ the limit
-%% %%
-%% ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
-%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
-%% {'EXIT', _} ->
-%% %% Has not been created yet (connect).
-%% megaco_config:cre_pending_counter(Direction, TransId, 1),
-%% ok;
-%% Val when Val > Limit ->
-%% ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
-%% aborted; % Already passed the limit
-%% Val ->
-%% ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
-%% megaco_config:incr_pending_counter(Direction, TransId),
-%% if
-%% Val < Limit ->
-%% ok; % Still within the limit
-%% true ->
-%% ?rt2("check and maybe incr - error",
-%% [Direction, Val, Limit]),
-%% error % Passed the limit
-%% end
-%% end.
-
-
%% BUGBUG BUGBUG BUGBUG
%%
%% Do we know that the Rep is still valid? A previous transaction
@@ -1657,8 +1638,8 @@ handle_request(ConnData, TransId, T, Extra) ->
%% Furthermore, the reply timer has not been started,
%% so do the cleanup now
?rt1(ConnData, "pending limit already passed", [TransId]),
- case megaco_monitor:lookup_reply(TransId) of
- [Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, Rep} ->
cancel_reply(ConnData, Rep, aborted);
_ ->
ok
@@ -1671,8 +1652,8 @@ do_handle_request(_, ignore, _ConnData, _TransId) ->
ignore;
do_handle_request(_, ignore_trans_request, ConnData, TransId) ->
?rt1(ConnData, "ignore trans request: don't reply", [TransId]),
- case megaco_monitor:lookup_reply(TransId) of
- [#reply{} = Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, #reply{} = Rep} ->
cancel_reply(ConnData, Rep, ignore);
_ ->
ignore
@@ -1689,8 +1670,8 @@ do_handle_request({pending, RequestData}, _SendReply, _ConnData, _) ->
do_handle_request(AckAction, {ok, Bin}, ConnData, TransId)
when is_binary(Bin) ->
?rt1(ConnData, "handle request - ok", [AckAction, TransId]),
- case megaco_monitor:lookup_reply(TransId) of
- [#reply{pending_timer_ref = PendingRef} = Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, #reply{pending_timer_ref = PendingRef} = Rep} ->
#conn_data{reply_timer = InitTimer,
conn_handle = ConnHandle} = ConnData,
@@ -1729,8 +1710,8 @@ do_handle_request(AckAction, {ok, {Sent, NotSent}}, ConnData, TransId)
?rt1(ConnData, "handle request - ok [segmented reply]",
[AckAction, TransId]),
- case megaco_monitor:lookup_reply(TransId) of
- [#reply{pending_timer_ref = PendingRef} = Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, #reply{pending_timer_ref = PendingRef} = Rep} ->
%% d("do_handle_request -> found reply record:"
%% "~n Rep: ~p", [Rep]),
@@ -1772,8 +1753,8 @@ do_handle_request(AckAction, {ok, {Sent, NotSent}}, ConnData, TransId)
end;
do_handle_request(_, {error, aborted}, ConnData, TransId) ->
?report_trace(ConnData, "aborted during our absence", [TransId]),
- case megaco_monitor:lookup_reply(TransId) of
- [Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, Rep} ->
cancel_reply(ConnData, Rep, aborted);
_ ->
ok
@@ -1781,8 +1762,8 @@ do_handle_request(_, {error, aborted}, ConnData, TransId) ->
ignore;
do_handle_request(AckAction, {error, Reason}, ConnData, TransId) ->
?report_trace(ConnData, "error", [TransId, Reason]),
- case megaco_monitor:lookup_reply(TransId) of
- [Rep] ->
+ case lookup_reply(ConnData, TransId) of
+ {_Converted, Rep} ->
Rep2 = Rep#reply{state = waiting_for_ack,
ack_action = AckAction},
cancel_reply(ConnData, Rep2, Reason);
@@ -2626,33 +2607,84 @@ handle_reply(
handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) ->
TransId = to_local_trans_id(CD),
?rt2("handle reply", [T, TransId]),
- case megaco_monitor:lookup_request(TransId) of
- [Req] when (is_record(Req, request) andalso
- (CD#conn_data.cancel =:= true)) ->
+ case {megaco_monitor:request_lockcnt_inc(TransId),
+ megaco_monitor:lookup_request(TransId)} of
+ {_Cnt, [Req]} when (is_record(Req, request) andalso
+ (CD#conn_data.cancel =:= true)) ->
?TC_AWAIT_REPLY_EVENT(true),
+ ?report_trace(CD, "trans reply - cancel(1)", [T]),
do_handle_reply_cancel(CD, Req, T);
- [#request{remote_mid = RMid} = Req] when ((RMid =:= preliminary_mid) orelse
- (RMid =:= CH#megaco_conn_handle.remote_mid)) ->
+ {Cnt, [#request{remote_mid = RMid} = Req]} when
+ ((Cnt =:= 1) andalso
+ ((RMid =:= preliminary_mid) orelse
+ (RMid =:= CH#megaco_conn_handle.remote_mid))) ->
?TC_AWAIT_REPLY_EVENT(false),
%% Just in case conn_data got update after our lookup
%% but before we looked up the request record, we
%% check the cancel field again.
case megaco_config:conn_info(CD, cancel) of
true ->
+ ?report_trace(CD, "trans reply - cancel(2)", [T]),
+ megaco_monitor:request_lockcnt_del(TransId),
do_handle_reply_cancel(CD, Req, T);
false ->
+ ?report_trace(CD, "trans reply", [T]),
do_handle_reply(CD, Req, TransId, T, Extra)
end;
- [#request{user_mod = UserMod,
- user_args = UserArgs,
- reply_action = Action,
- reply_data = UserData,
- remote_mid = RMid}] ->
+ {Cnt, [#request{remote_mid = RMid} = _Req]} when
+ (is_integer(Cnt) andalso
+ ((RMid =:= preliminary_mid) orelse
+ (RMid =:= CH#megaco_conn_handle.remote_mid))) ->
+ ?TC_AWAIT_REPLY_EVENT(false),
+ %% Ok, someone got there before me, now what?
+ %% This is a plain old raise condition
+ ?report_important(CD, "trans reply - raise condition",
+ [T, {request_lockcnt, Cnt}]),
+ megaco_monitor:request_lockcnt_dec(TransId);
+
+ %% no counter
+ {_Cnt, [#request{remote_mid = RMid} = Req]} when
+ ((RMid =:= preliminary_mid) orelse
+ (RMid =:= CH#megaco_conn_handle.remote_mid)) ->
+ ?TC_AWAIT_REPLY_EVENT(false),
+ %% The counter does not exist.
+ %% This can only mean a code upgrade raise condition.
+ %% That is, this request record was created before
+ %% this feature (the counters) was instroduced.
+ %% The simples solution is this is to behave exactly as
+ %% before, that is pass it along, and leave it to the
+ %% user to figure out.
+
+ %% Just in case conn_data got update after our lookup
+ %% but before we looked up the request record, we
+ %% check the cancel field again.
+ ?report_verbose(CD, "trans reply - old style", [T]),
+ case megaco_config:conn_info(CD, cancel) of
+ true ->
+ megaco_monitor:request_lockcnt_del(TransId),
+ do_handle_reply_cancel(CD, Req, T);
+ false ->
+ do_handle_reply(CD, Req, TransId, T, Extra)
+ end;
+
+ {Cnt, [#request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ remote_mid = RMid}]} ->
?report_trace(CD,
"received trans reply with invalid remote mid",
- [T, RMid]),
+ [{transaction, T},
+ {remote_mid, RMid},
+ {request_lockcnt, Cnt}]),
+ if
+ is_integer(Cnt) ->
+ megaco_monitor:request_lockcnt_dec(TransId);
+ true ->
+ ok
+ end,
WrongMid = CH#megaco_conn_handle.remote_mid,
T2 = transform_transaction_reply_enc(CD#conn_data.protocol_version,
T),
@@ -2663,7 +2695,15 @@ handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) ->
reply_data = UserData},
return_reply(CD2, TransId, UserReply, Extra);
- [] ->
+ {Cnt, []} when is_integer(Cnt) ->
+ ?TC_AWAIT_REPLY_EVENT(undefined),
+ ?report_trace(CD, "trans reply (no receiver)",
+ [T, {request_lockcnt, Cnt}]),
+ megaco_monitor:request_lockcnt_dec(TransId),
+ return_unexpected_trans(CD, T, Extra);
+
+ %% No counter
+ {_Cnt, []} ->
?TC_AWAIT_REPLY_EVENT(undefined),
?report_trace(CD, "trans reply (no receiver)", [T]),
return_unexpected_trans(CD, T, Extra)
@@ -2694,6 +2734,7 @@ do_handle_reply(CD,
%% This is the first reply (maybe of many)
megaco_monitor:delete_request(TransId),
+ megaco_monitor:request_lockcnt_del(TransId),
megaco_monitor:cancel_apply_after(Ref), % OTP-4843
megaco_config:del_pending_counter(recv, TransId), % OTP-7189
@@ -2819,9 +2860,10 @@ handle_segment_reply(CD,
{segment_no, SN},
{segmentation_complete, SC}]),
TransId2 = to_remote_trans_id(CD#conn_data{serial = TransId}),
- case megaco_monitor:lookup_reply(TransId2) of
- [#reply{bytes = Sent,
- segments = []} = Rep] when is_list(Sent) ->
+ case lookup_reply(CD, TransId2) of
+ {_Converted,
+ #reply{bytes = Sent,
+ segments = []} = Rep} when is_list(Sent) ->
?rt2("no unsent segments", [Sent]),
handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
case lists:keysearch(SN, 1, Sent) of
@@ -2845,8 +2887,9 @@ handle_segment_reply(CD,
ok
end;
- [#reply{bytes = Sent,
- segments = NotSent}] when is_list(Sent) andalso
+ {_Converted,
+ #reply{bytes = Sent,
+ segments = NotSent}} when is_list(Sent) andalso
is_list(NotSent) ->
?rt2("unsent segments", [Sent, NotSent]),
handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
@@ -2883,7 +2926,8 @@ handle_segment_reply(CD,
ok
end;
- [#reply{state = State}] ->
+ {_Converted,
+ #reply{state = State}} ->
%% We received a segment reply for a segmented reply we have
%% not yet sent? This is either some sort of race condition
%% or the "the other side" is really confused.
@@ -3012,7 +3056,7 @@ handle_ack_callback(ConnData, AckStatus, {handle_ack, AckData}, T, Extra) ->
_ ->
[ConnHandle, Version, AckStatus, AckData, Extra | UserArgs]
end,
- Res = (catch apply(UserMod, handle_trans_ack, Args)),
+ Res = (catch handle_callback(ConnData, UserMod, handle_trans_ack, Args)),
?report_debug(ConnData, "return: trans ack", [T, AckData, {return, Res}]),
case Res of
ok ->
@@ -3024,6 +3068,14 @@ handle_ack_callback(ConnData, AckStatus, {handle_ack, AckData}, T, Extra) ->
Res.
+handle_callback(ConnData, undefined = _UserMod, Func, Args) ->
+ ?report_important(ConnData, "callback: unknown callback module",
+ [{func, Func}, {args, Args}]),
+ ok;
+handle_callback(_ConnData, UserMod, Func, Args) ->
+ (catch apply(UserMod, Func, Args)).
+
+
handle_message_error(ConnData, _Error, _Extra)
when ConnData#conn_data.monitor_ref == undefined_monitor_ref ->
%% May occur if another process already has setup a
@@ -3706,6 +3758,11 @@ insert_requests(ConnData, ConnHandle,
insert_request(ConnData, ConnHandle, TransId,
Action, Data, InitTimer, LongTimer) ->
+ %% We dont check the result of the lock-counter creation because
+ %% the only way it could already exist is if the transaction-id
+ %% range has wrapped and an old counter was not deleted.
+ megaco_monitor:request_lockcnt_cre(TransId),
+
#megaco_conn_handle{remote_mid = RemoteMid} = ConnHandle,
#conn_data{protocol_version = Version,
user_mod = UserMod,
@@ -4290,6 +4347,7 @@ cancel_request(ConnData, Req, Reason) ->
cancel_request2(ConnData, TransId, UserReply) ->
megaco_monitor:delete_request(TransId),
+ megaco_monitor:request_lockcnt_del(TransId),
megaco_config:del_pending_counter(recv, TransId), % OTP-7189
Serial = TransId#trans_id.serial,
ConnData2 = ConnData#conn_data{serial = Serial},
@@ -4347,34 +4405,76 @@ receive_reply_remote(ConnData, UserReply) ->
receive_reply_remote(ConnData, UserReply, Extra) ->
TransId = to_local_trans_id(ConnData),
- case (catch megaco_monitor:lookup_request(TransId)) of
- [#request{timer_ref = {_Type, Ref}} = Req] -> %% OTP-4843
+ case {megaco_monitor:request_lockcnt_inc(TransId),
+ (catch megaco_monitor:lookup_request(TransId))} of
+ {Cnt, [Req]} when (Cnt =:= 1) andalso is_record(Req, request) ->
%% Don't care about Req and Rep version diff
- megaco_monitor:delete_request(TransId),
- megaco_monitor:cancel_apply_after(Ref), % OTP-4843
- megaco_config:del_pending_counter(recv, TransId), % OTP-7189
-
- UserMod = Req#request.user_mod,
- UserArgs = Req#request.user_args,
- Action = Req#request.reply_action,
- UserData = Req#request.reply_data,
- ConnData2 = ConnData#conn_data{user_mod = UserMod,
- user_args = UserArgs,
- reply_action = Action,
- reply_data = UserData},
- return_reply(ConnData2, TransId, UserReply, Extra);
-
+ do_receive_reply_remote(ConnData, TransId, Req, UserReply, Extra);
+
+ {Cnt, [Req]} when is_integer(Cnt) andalso is_record(Req, request) ->
+ %% Another process is accessing, handle as unexpected
+ %% (so it has a possibillity to get logged).
+ ?report_important(ConnData, "trans reply (no receiver)",
+ [{user_reply, UserReply},
+ {request_lockcnt, Cnt}]),
+ megaco_monitor:request_lockcnt_dec(TransId),
+ return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra);
+
+ %% no counter
+ {_Cnt, [Req]} when is_record(Req, request) ->
+ %% The counter does not exist.
+ %% This can only mean a code upgrade raise condition.
+ %% That is, this request record was created before
+ %% this feature (the counters) was instroduced.
+ %% The simples solution to this is to behave exactly as
+ %% before, that is, pass it along, and leave it to the
+ %% user to figure out.
+ ?report_trace(ConnData,
+ "remote reply - "
+ "code upgrade raise condition",
+ [{user_reply, UserReply}]),
+ do_receive_reply_remote(ConnData, TransId, Req, UserReply, Extra);
+
+ {Cnt, _} when is_integer(Cnt) ->
+ ?report_trace(ConnData, "trans reply (no receiver)",
+ [{user_reply, UserReply}, {request_lockcnt, Cnt}]),
+ megaco_monitor:request_lockcnt_dec(TransId),
+ return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra);
+
_ ->
?report_trace(ConnData, "remote reply (no receiver)",
- [UserReply]),
+ [{user_reply, UserReply}]),
return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra)
end.
-cancel_reply(ConnData, #reply{state = waiting_for_ack} = Rep, Reason) ->
+do_receive_reply_remote(ConnData, TransId,
+ #request{timer_ref = {_Type, Ref},
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData} = _Req,
+ UserReply, Extra) ->
+ megaco_monitor:delete_request(TransId),
+ megaco_monitor:request_lockcnt_del(TransId),
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra).
+
+
+cancel_reply(ConnData, #reply{state = waiting_for_ack,
+ user_mod = UserMod,
+ user_args = UserArgs} = Rep, Reason) ->
?report_trace(ignore, "cancel reply [waiting_for_ack]", [Rep]),
megaco_monitor:cancel_apply_after(Rep#reply.pending_timer_ref),
Serial = (Rep#reply.trans_id)#trans_id.serial,
- ConnData2 = ConnData#conn_data{serial = Serial},
+ ConnData2 = ConnData#conn_data{serial = Serial,
+ user_mod = UserMod,
+ user_args = UserArgs},
T = #'TransactionAck'{firstAck = Serial},
Extra = ?default_user_callback_extra,
handle_ack(ConnData2, {error, Reason}, Rep, T, Extra);
@@ -4558,16 +4658,30 @@ reply_timeout(ConnHandle, TransId, {_, timeout}) ->
reply_timeout(ConnHandle, TransId, Timer) ->
?report_trace(ConnHandle, "reply timeout", [Timer, TransId]),
- case megaco_monitor:lookup_reply(TransId) of
+ case lookup_reply(undefined, TransId) of
[] ->
reply_not_found_ignore;
- [#reply{state = waiting_for_ack,
- ack_action = {handle_ack, _}} = Rep] ->
+ {Converted,
+ #reply{state = waiting_for_ack,
+ ack_action = {handle_ack, _}} = Rep} ->
case megaco_config:lookup_local_conn(ConnHandle) of
[CD] when (CD#conn_data.cancel =:= true) ->
cancel_in_progress_ignore;
- [CD] ->
+ [CD] when (Converted =:= true) ->
+ incNumTimerRecovery(ConnHandle),
+ %% When we did the reply record lookup, we had no
+ %% conn_data record, and the reply record was
+ %% converted. This means that the reply record
+ %% has no valid info about user_mod or user_args.
+ %% Therefor, the user_mod and user_args of the
+ %% conn_data record is better then nothing.
+ #conn_data{user_mod = UserMod,
+ user_args = UserArgs} = CD,
+ Rep2 = Rep#reply{user_mod = UserMod,
+ user_args = UserArgs},
+ do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep2);
+ [CD] when (Converted =:= false) ->
incNumTimerRecovery(ConnHandle),
do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep);
[] ->
@@ -4576,10 +4690,25 @@ reply_timeout(ConnHandle, TransId, Timer) ->
do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep)
end;
- [#reply{state = waiting_for_ack,
- bytes = Sent} = Rep] when is_list(Sent) ->
+ {Converted,
+ #reply{state = waiting_for_ack,
+ bytes = Sent} = Rep} when is_list(Sent) ->
case megaco_config:lookup_local_conn(ConnHandle) of
- [ConnData] ->
+ [ConnData] when (Converted =:= true) ->
+ incNumTimerRecovery(ConnHandle),
+ %% When we did the reply record lookup, we had no
+ %% conn_data record, and the reply record was
+ %% converted. This means that the reply record
+ %% has no valid info about user_mod or user_args.
+ %% Therefor, the user_mod and user_args of the
+ %% conn_data record is better then nothing.
+ #conn_data{user_mod = UserMod,
+ user_args = UserArgs} = ConnData,
+ Rep2 = Rep#reply{user_mod = UserMod,
+ user_args = UserArgs},
+ do_reply_timeout(ConnHandle, TransId, ConnData,
+ Timer, Rep2);
+ [ConnData] when (Converted =:= false) ->
incNumTimerRecovery(ConnHandle),
do_reply_timeout(ConnHandle, TransId, ConnData,
Timer, Rep);
@@ -4590,10 +4719,12 @@ reply_timeout(ConnHandle, TransId, Timer) ->
Timer, Rep)
end;
- [#reply{state = waiting_for_ack} = Rep] ->
+ {_Converted,
+ #reply{state = waiting_for_ack} = Rep} ->
do_reply_timeout(ConnHandle, TransId, Timer, Rep);
- [#reply{state = aborted} = Rep] ->
+ {_Converted,
+ #reply{state = aborted} = Rep} ->
do_reply_timeout(ConnHandle, TransId, Timer, Rep);
_ ->
@@ -4686,22 +4817,41 @@ handle_reply_timer_timeout(ConnHandle, TransId) ->
?report_trace(ConnHandle, "handle reply timeout", [timeout, TransId]),
incNumTimerRecovery(ConnHandle),
%% OTP-4378
- case megaco_monitor:lookup_reply(TransId) of
- [#reply{state = waiting_for_ack} = Rep] ->
+ case lookup_reply(undefined, TransId) of
+ {Converted,
+ #reply{state = waiting_for_ack} = Rep} ->
Serial = (Rep#reply.trans_id)#trans_id.serial,
- ConnData =
+ {Rep2, ConnData} =
case megaco_config:lookup_local_conn(ConnHandle) of
- [ConnData0] ->
- ConnData0;
- [] ->
- fake_conn_data(ConnHandle)
+ [ConnData0] when (Converted =:= false) ->
+ #reply{user_mod = UserMod,
+ user_args = UserArgs} = Rep,
+ {Rep,
+ ConnData0#conn_data{user_mod = UserMod,
+ user_args = UserArgs}};
+ [ConnData0] when (Converted =:= true) ->
+ {Rep#reply{user_mod = ConnData0#conn_data.user_mod,
+ user_args = ConnData0#conn_data.user_args},
+ ConnData0};
+ [] when (Converted =:= false) ->
+ ConnData0 = fake_conn_data(ConnHandle),
+ #reply{user_mod = UserMod,
+ user_args = UserArgs} = Rep,
+ {Rep,
+ ConnData0#conn_data{user_mod = UserMod,
+ user_args = UserArgs}};
+ [] when (Converted =:= true) ->
+ %% We have no valid info about user_mod and user_args
+ {Rep, fake_conn_data(ConnHandle)}
end,
ConnData2 = ConnData#conn_data{serial = Serial},
T = #'TransactionAck'{firstAck = Serial},
Extra = ?default_user_callback_extra,
- handle_ack(ConnData2, {error, timeout}, Rep, T, Extra);
- [#reply{pending_timer_ref = Ref, % aborted?
- bytes = SegSent}] -> % may be a binary
+ handle_ack(ConnData2, {error, timeout}, Rep2, T, Extra);
+
+ {_Converted,
+ #reply{pending_timer_ref = Ref, % aborted?
+ bytes = SegSent}} -> % may be a binary
megaco_monitor:cancel_apply_after(Ref),
cancel_segment_timers(SegSent),
megaco_monitor:delete_reply(TransId),
@@ -4803,9 +4953,10 @@ pending_timeout(ConnHandle, TransId, Timer) ->
handle_pending_timeout(CD, TransId, Timer) ->
?report_trace(CD, "handle pending timeout", []),
- case megaco_monitor:lookup_reply(TransId) of
- [#reply{state = State,
- handler = Pid} = Rep] when (State =:= prepare) orelse
+ case lookup_reply(CD, TransId) of
+ {_Converted,
+ #reply{state = State,
+ handler = Pid} = Rep} when (State =:= prepare) orelse
(State =:= eval_request) ->
#conn_data{sent_pending_limit = Limit,
@@ -4885,12 +5036,14 @@ handle_pending_timeout(CD, TransId, Timer) ->
[] ->
reply_not_found; % Trace ??
- [#reply{state = waiting_for_ack}] ->
+ {_Converted,
+ #reply{state = waiting_for_ack}} ->
%% The reply has already been sent
%% No need for any pending trans reply
reply_has_been_sent;
- [#reply{state = aborted} = Rep] ->
+ {_Converted,
+ #reply{state = aborted} = Rep} ->
%% glitch, but cleanup just the same
cancel_reply(CD, Rep, aborted),
reply_aborted_state
@@ -5096,7 +5249,65 @@ make_transaction_reply(_, TransId, IAR, TransRes) ->
%%-----------------------------------------------------------------
+%% This function is used as a wrapper for reply-record lookups.
+%% The intention is that during upgrade, this function
+%% can perform on-the-fly conversions of reply-records.
+lookup_reply(CD, TransId) ->
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{} = Rep] ->
+ {false, Rep};
+
+ %% Old (pre-3.13.1) version of the record => Convert to new version
+ [{reply, TransId,
+ LocalMid, State, PendingTmrRef, Handler, TimerRef,
+ Version, Bytes, AckAction, SendHandle, Segments}]
+ when is_record(CD, conn_data) ->
+ #conn_data{user_mod = UserMod,
+ user_args = UserArgs} = CD,
+ Rep = #reply{trans_id = TransId,
+ local_mid = LocalMid,
+ state = State,
+ pending_timer_ref = PendingTmrRef,
+ handler = Handler,
+ timer_ref = TimerRef,
+ version = Version,
+ bytes = Bytes,
+ ack_action = AckAction,
+ send_handle = SendHandle,
+ segments = Segments,
+ user_mod = UserMod,
+ user_args = UserArgs},
+ {true, Rep};
+
+ %% Old (pre-3.13.1) version of the record => Convert to new version
+ [{reply, TransId,
+ LocalMid, State, PendingTmrRef, Handler, TimerRef,
+ Version, Bytes, AckAction, SendHandle, Segments}] ->
+ %% ConnData is not known here, so ignore for now
+ Rep = #reply{trans_id = TransId,
+ local_mid = LocalMid,
+ state = State,
+ pending_timer_ref = PendingTmrRef,
+ handler = Handler,
+ timer_ref = TimerRef,
+ version = Version,
+ bytes = Bytes,
+ ack_action = AckAction,
+ send_handle = SendHandle,
+ segments = Segments},
+ {true, Rep};
+
+ Else ->
+ Else
+ end.
+
+
%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% info_msg(F, A) ->
+%% ?megaco_info(F, A).
+
warning_msg(F, A) ->
?megaco_warning(F, A).
@@ -5131,7 +5342,7 @@ error_msg(F, A) ->
%% Time in milli seconds
t() ->
- {A,B,C} = erlang:now(),
+ {A,B,C} = os:timestamp(),
A*1000000000+B*1000+(C div 1000).
@@ -5156,3 +5367,4 @@ incNum(Cnt) ->
Old
end.
+
diff --git a/lib/megaco/src/engine/megaco_monitor.erl b/lib/megaco/src/engine/megaco_monitor.erl
index f95a20cf58..29275371be 100644
--- a/lib/megaco/src/engine/megaco_monitor.erl
+++ b/lib/megaco/src/engine/megaco_monitor.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -51,6 +51,11 @@
update_request_field/3, update_request_fields/2,
delete_request/1,
+ request_lockcnt_cre/1,
+ request_lockcnt_del/1,
+ request_lockcnt_inc/1,
+ request_lockcnt_dec/1,
+
lookup_reply/1,
lookup_reply_field/2,
match_replies/1,
@@ -115,6 +120,24 @@ update_request_fields(Key, NewFields) when is_list(NewFields) ->
delete_request(Key) ->
ets:delete(megaco_requests, Key).
+
+request_lockcnt_cre(TransId) ->
+ Key = {TransId, lockcnt},
+ ets:insert_new(megaco_requests, {Key, 1}).
+
+request_lockcnt_del(TransId) ->
+ Key = {TransId, lockcnt},
+ ets:delete(megaco_requests, Key).
+
+request_lockcnt_inc(TransId) ->
+ Key = {TransId, lockcnt},
+ (catch ets:update_counter(megaco_requests, Key, 1)).
+
+request_lockcnt_dec(TransId) ->
+ Key = {TransId, lockcnt},
+ (catch ets:update_counter(megaco_requests, Key, -1)).
+
+
lookup_reply(Key) ->
ets:lookup(megaco_replies, Key).
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index 782d6a4807..5af651d89b 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2001-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
include $(ERL_TOP)/make/target.mk
@@ -23,13 +23,30 @@ MEGACO_INCLUDEDIR = ../../include
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
# ----------------------------------------------------
# Application version
# ----------------------------------------------------
include ../../vsn.mk
VSN=$(MEGACO_VSN)
+# ----------------------------------------------------
+# Dynamic Erlang Driver
+# ----------------------------------------------------
+HAVE_USABLE_OTP_DED_MK = @HAVE_USABLE_OTP_DED_MK@
+
+ifeq ($(HAVE_USABLE_OTP_DED_MK),yes)
+# otp_ded.mk will be used on R13B04 and later
+include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk
+else
+# megacos configure provide the info instead
+DED_CC = @CC@
+DED__NOWARN_NOTHR_CFLAGS = @DED_CFLAGS@
+DED_THR_DEFS = @DED_THR_DEFS@
+DED_LD = @DED_LD@
+DED_LDFLAGS = @DED_LDFLAGS@
+DED_INCLUDES = @DED_INCLUDES@
+DED_EXT = so
+endif
# ----------------------------------------------------
# The following variables differ on different systems, we set
@@ -39,16 +56,16 @@ VSN=$(MEGACO_VSN)
FLEX_VSN = $(shell flex --version)
-TMP_CFLAGS = @DED_CFLAGS@
+TMP_CFLAGS = $(DED__NOWARN_NOTHR_CFLAGS) @OTP_EXTRA_FLAGS@
ifeq ($(TYPE),valgrind)
CFLAGS = $(subst -O2, , $(TMP_CFLAGS)) -DVALGRIND
else
CFLAGS = $(TMP_CFLAGS)
endif
-CC = @CC@
-CFLAGS_MT = $(CFLAGS) -D_THREAD_SAFE -D_REENTRANT
-LD = @DED_LD@
-LDFLAGS = @DED_LDFLAGS@
+CC = $(DED_CC)
+CFLAGS_MT = $(CFLAGS) $(DED_THR_DEFS)
+LD = $(DED_LD)
+LDFLAGS = $(DED_LDFLAGS)
LEX = @LEX@
LEXLIB = @LEXLIB@
PERL = @PERL@
@@ -87,18 +104,13 @@ ENABLE_MEGACO_FLEX_SCANNER_LINENO = @ENABLE_MEGACO_FLEX_SCANNER_LINENO@
endif
endif
-
-SYSINCLUDE = -I$(ERL_TOP)/erts/emulator/beam \
- -I$(ERL_TOP)/erts/emulator/sys/$(ERLANG_OSTYPE)
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
- SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks
+ DED_INCLUDES += -I$(ERL_TOP)/erts/etc/vxworks
endif
-DRIVER_INCLUDES = $(SYSINCLUDE)
-
PRIVDIR = ../../priv
LIBDIR = $(PRIVDIR)/lib/$(TARGET)
-
+OBJDIR = $(PRIVDIR)/obj/$(TARGET)
# ----------------------------------------------------
# Release directory specification
@@ -138,8 +150,8 @@ ifeq ($(findstring vxworks,$(TARGET)),vxworks)
FLEX_SCANNER_SO =
SOLIBS = $(FLEX_SCANNER_SO)
else
-FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).so
-FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).so
+FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).$(DED_EXT)
+FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).$(DED_EXT)
SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO)
endif
endif
@@ -175,7 +187,7 @@ else
CFLAGS += -DMFS_FLEX_DEBUG=0
endif
-CFLAGS += $(DRIVER_INCLUDES) $(DRV_FLAGS) -funroll-loops -Wall
+CFLAGS += $(DED_INCLUDES) -I$(ERL_TOP)/erts/$(TARGET) $(DRV_FLAGS) -funroll-loops -Wall
#ifneq ($(FLEX_VSN),)
#CFLAGS += -DFLEX_VERSION="$(FLEX_VSN)"
@@ -268,7 +280,7 @@ release_spec: opt
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
$(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex
- $(INSTALL_DATA) $(SOLIBS) $(RELSYSDIR)/priv/lib
+ $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib
endif
@@ -379,18 +391,30 @@ $(STD_DRV).c: $(STD_DRV).flex
$(MT_DRV).c: $(MT_DRV).flex
$(LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
-solibs: $(LIBDIR) $(SOLIBS)
+solibs: $(LIBDIR) $(OBJDIR) $(SOLIBS)
+
+$(OBJDIR)/$(STD_DRV).o: $(STD_DRV).c
+ @echo "compiling std driver:"
+ $(CC) -c $(STD_DRV_NAME) $(CFLAGS) -o $@ $<
+
+$(OBJDIR)/$(MT_DRV).o: $(MT_DRV).c
+ @echo "compiling multi-threaded driver:"
+ $(CC) -c $(MT_DRV_NAME) $(CFLAGS_MT) -o $@ $<
+
# No need to link with -lfl as we have also defined %option noyywrap -
# and having -lfl doesn't work under Darwin for some reason. - Sean
-$(LIBDIR)/$(STD_DRV).so: $(STD_DRV).c
- @echo "std driver:"
- $(CC) $(STD_DRV_NAME) $(CFLAGS) $(LDFLAGS) -o $(LIBDIR)/$(STD_DRV).so $<
+$(LIBDIR)/$(STD_DRV).$(DED_EXT): $(OBJDIR)/$(STD_DRV).o
+ @echo "linking std driver:"
+ $(LD) $(LDFLAGS) -o $@ $<
-$(LIBDIR)/$(MT_DRV).so: $(MT_DRV).c
- @echo "multi-threaded driver:"
- $(CC) $(MT_DRV_NAME) $(CFLAGS_MT) $(LDFLAGS) -o $(LIBDIR)/$(MT_DRV).so $<
+$(LIBDIR)/$(MT_DRV).$(DED_EXT): $(OBJDIR)/$(MT_DRV).o
+ @echo "linking multi-threaded driver:"
+ $(LD) $(LDFLAGS) -o $@ $<
$(LIBDIR):
-mkdir -p $(LIBDIR)
+$(OBJDIR):
+ -mkdir -p $(OBJDIR)
+
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
index 3520c34d50..96621193e8 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
+++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
@@ -8,12 +8,12 @@
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*
* ----------------------------------------------------------------------
@@ -361,9 +361,6 @@ static ErlDrvEntry mfs_entry = {
MEGACO_DRIVER_FLAGS, /* driver_flags, used for port lock indication */
NULL, /* handle2, emulator internal use */
NULL /* process_exit, Called when a process monitor fires */
-#if defined(MEGACO_DRV_ENTRY_HAS_STOP_SELECT)
- ,NULL /* stop_select, Called to close an event object */
-#endif
};
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
index d09e0c6fff..420202134e 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
+++ b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -180,27 +180,28 @@ terminate(_Reason, _S) ->
%% Purpose: Called to change the internal state
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
-%% code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_8) ->
-%% Port = downgrade_flex_scanner(Conf),
-%% {ok, State#state{conf = {flex, Port}}};
+
+code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_13_1) ->
+ NewPorts = bump_flex_scanner(Conf),
+ {ok, State#state{conf = {flex, NewPorts}}};
+
+code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_13_1) ->
+ NewPorts = bump_flex_scanner(Conf),
+ {ok, State#state{conf = {flex, NewPorts}}};
code_change(_Vsn, State, _Extra) ->
{ok, State}.
-%% downgrade_flex_scanner({flex, Port}) when is_port(Port) ->
-%% Port;
-%% downgrade_flex_scanner({flex, [Port]}) when is_port(Port) ->
-%% Port;
-%% downgrade_flex_scanner({flex, Ports}) when is_list(Ports) ->
-%% megaco_flex_scanner:stop(Ports),
-%% case megaco_flex_scanner:start() of
-%% {ok, Port} ->
-%% Port;
-%% Error ->
-%% exit(Error)
-%% end;
-%% downgrade_flex_scanner(BadConfig) ->
-%% exit({invalid_config, BadConfig}).
+bump_flex_scanner({flex, Ports}) ->
+ megaco_flex_scanner:stop(Ports),
+ case start_flex_scanners() of
+ {ok, NewPorts} ->
+ NewPorts;
+ Error ->
+ exit(Error)
+ end;
+bump_flex_scanner(BadConfig) ->
+ exit({invalid_config, BadConfig}).
%%%----------------------------------------------------------------------