From 61b1feed86ccf574613b913c5eea57d138eeb178 Mon Sep 17 00:00:00 2001
From: Micael Karlberg
Date: Mon, 7 Jun 2010 12:00:00 +0200
Subject: megaco: Patch 1123
OTP-8561 A minor compiler related performance improvement.
OTP-8529 A raise condition when, during high load, processing both
the original and a resent message and delivering this as
two separate messages to the user. Note that this solution
only protects against multiple reply deliveries!
OTP-8627 Fix shared libraries installation. The flex shared lib(s)
were incorrectly installed as data files.
OTP-8634 Eliminated a possible raise condition while creating pending
counters.
---
lib/megaco/doc/src/megaco.xml | 16 +-
lib/megaco/doc/src/megaco_mib.xml | 12 +-
lib/megaco/doc/src/megaco_run.xml | 8 +-
lib/megaco/doc/src/megaco_user.xml | 11 +-
lib/megaco/doc/src/notes.xml | 62 +++++
lib/megaco/doc/src/notes_history.xml | 10 +-
lib/megaco/src/app/megaco.appup.src | 23 +-
lib/megaco/src/app/megaco_internal.hrl | 26 +-
lib/megaco/src/engine/megaco_config.erl | 427 ++++++++++++++++++-----------
lib/megaco/src/engine/megaco_messenger.erl | 239 ++++++++++------
lib/megaco/src/engine/megaco_monitor.erl | 33 ++-
lib/megaco/src/flex/Makefile.in | 2 +-
lib/megaco/test/megaco_app_test.erl | 14 +-
lib/megaco/test/megaco_config_test.erl | 362 +++++++++++++-----------
lib/megaco/vsn.mk | 6 +-
15 files changed, 805 insertions(+), 446 deletions(-)
(limited to 'lib/megaco')
diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml
index 0fb9d5aac6..ae9e250965 100644
--- a/lib/megaco/doc/src/megaco.xml
+++ b/lib/megaco/doc/src/megaco.xml
@@ -4,7 +4,7 @@
- 20002009
+ 20002010
Ericsson AB. All Rights Reserved.
@@ -13,12 +13,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.
-
+
megaco
@@ -40,6 +40,16 @@
DATA TYPES
- 20022009
+ 20022010
Ericsson AB. All Rights Reserved.
@@ -13,12 +13,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.
-
+
Megaco mib
@@ -50,15 +50,15 @@
lightweight. I.e. the statistic counters are handled
separately by different entities of the application. For
instance our two transport module(s) (see megaco_tcp and megaco_udp) maintain their
- own counters and the application engine (see megaco) maintain it's own
+ own counters and the application engine (see megaco) maintain its own
counters.
This also means that if a user implement their own transport
- service then it has to maintain it's own statistics.
+ service then it has to maintain its own statistics.
Distribution
- Each megaco application maintains it's own set of counters. So
+
Each megaco application maintains its own set of counters. So
in a large (distributed) MG/MGC it could be necessary to
collect the statistics from several nodes (each) running the
megaco application (only one of them with the transport).
diff --git a/lib/megaco/doc/src/megaco_run.xml b/lib/megaco/doc/src/megaco_run.xml
index 3afc638bcf..9ed589b079 100644
--- a/lib/megaco/doc/src/megaco_run.xml
+++ b/lib/megaco/doc/src/megaco_run.xml
@@ -4,7 +4,7 @@
- 20002009
+ 20002010
Ericsson AB. All Rights Reserved.
@@ -13,12 +13,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.
-
+
Running the stack
@@ -365,7 +365,7 @@
then the specified max message size (see the
max_pdu_size option).
Finally, if segmentation is decided, then each action reply
- will make up it's own (segment) message.
+ will make up its own (segment) message.
diff --git a/lib/megaco/doc/src/megaco_user.xml b/lib/megaco/doc/src/megaco_user.xml
index 37942007bc..7332fa684d 100644
--- a/lib/megaco/doc/src/megaco_user.xml
+++ b/lib/megaco/doc/src/megaco_user.xml
@@ -4,7 +4,7 @@
- 20002009
+ 20002010
Ericsson AB. All Rights Reserved.
@@ -13,12 +13,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.
-
+
megaco_user
@@ -471,7 +471,7 @@ protocol_version() = integer() ]]>
transaction_result() = action_reps()
segment_result() = {segment_no(), last_segment(), action_reps()}
action_reps() = [action_reply()]
- failure() = {error, reason()}
+ failure() = {error, reason()} | {error, ReplyNo, reason()}
reason() = transaction_reason() | segment_reason() | user_cancel_reason() | send_reason() | other_reason()
transaction_reason() = error_desc()
segment_reason() = {segment_no(), last_segment(), error_desc()}
@@ -486,6 +486,7 @@ protocol_version() = integer() ]]>
send_failed_reason() = {send_message_failed, reason_for_send_failure()}
reason_for_send_failure() = term()
ReplyData = reply_data()
+ ReplyNo = integer() > 0
reply_data() = term()
Extra = term()
@@ -669,7 +670,7 @@ protocol_version() = integer() ]]>
Invoked when a unexpected message is received
If a reply to a request is not received in time, the
megaco stack removes all info about the request from
- it's tables. If a reply should arrive after this has been
+ its tables. If a reply should arrive after this has been
done the app has no way of knowing where to send this message.
The message is delivered to the "user" by calling this
function on the local node (the node which has the link).
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index 65bf0345f5..99a3784402 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -35,6 +35,68 @@
thus constitutes one section in this document. The title of each
section is the version number of Megaco.
+
+ Megaco 3.14.1
+
+ Version 3.14.1 supports code replacement in runtime from/to
+ version 3.14, 3.13, 3.12 and 3.11.3.
+
+
+ Improvements and new features
+
+
+
+
+ -
+
A minor compiler related performance improvement.
+ Own Id: OTP-8561
+
+
+
+
+
+
+
+ Fixed bugs and malfunctions
+
+
+
+ -
+
A raise condition when, during high load, processing
+ both the original and a resent message and delivering
+ this as two separate messages to the user.
+ Note that this solution only protects against multiple
+ reply deliveries!
+ Own Id: OTP-8529
+ Aux Id: Seq 10915
+
+
+ -
+
Fix shared libraries installation.
+ The flex shared lib(s) were incorrectly installed as data
+ files.
+ Peter Lemenkov
+ Own Id: OTP-8627
+
+
+ -
+
Eliminated a possible raise condition while creating
+ pending counters.
+ Own Id: OTP-8634
+ Aux Id: Seq 11579
+
+
+
+
+
+
+
+
+
Megaco 3.14
diff --git a/lib/megaco/doc/src/notes_history.xml b/lib/megaco/doc/src/notes_history.xml
index 97aa4c66a5..640b62230f 100644
--- a/lib/megaco/doc/src/notes_history.xml
+++ b/lib/megaco/doc/src/notes_history.xml
@@ -4,7 +4,7 @@
- 20062009
+ 20062010
Ericsson AB. All Rights Reserved.
@@ -13,12 +13,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.
-
+
Megaco Release Notes history
@@ -2764,7 +2764,7 @@
Added a new configuration parameter, threaded.
This tells the megaco app, that all
transaction requests in a message should be executed
- in parallel (e.g. each in it's own process).
+ in parallel (e.g. each in its own process).
See the
threaded parameter
of the user_info function (also conn_info).
@@ -2911,7 +2911,7 @@
Improvements and new features
-
-
This is just a code up-/downgrade cleanup release. I.e. It's the
+
This is just a code up-/downgrade cleanup release. I.e. it's the
same as version 1.2 minus the ugly stuff needed to handle up-/downgrade
from/to version 1.1.2, 1.1.1 and 1.1.0.
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 4f781478ef..f939f5e6cf 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -124,14 +124,25 @@
%% |
%% 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, []},
+ {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, []}
@@ -163,10 +174,18 @@
}
],
[
+ {"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, []},
+ {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, []}
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 1c7a141be7..6805db790d 100644
--- a/lib/megaco/src/engine/megaco_config.erl
+++ b/lib/megaco/src/engine/megaco_config.erl
@@ -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
diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl
index 5756e8e896..5fad29931b 100644
--- a/lib/megaco/src/engine/megaco_messenger.erl
+++ b/lib/megaco/src/engine/megaco_messenger.erl
@@ -1541,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;
@@ -1572,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
@@ -2648,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;
+
+ {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;
- [#request{user_mod = UserMod,
- user_args = UserArgs,
- reply_action = Action,
- reply_data = UserData,
- remote_mid = RMid}] ->
+ {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),
@@ -2685,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)
@@ -2716,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
@@ -3739,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,
@@ -4323,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},
@@ -4380,29 +4405,67 @@ 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.
+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) ->
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 6ce9b34617..5af651d89b 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -280,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
diff --git a/lib/megaco/test/megaco_app_test.erl b/lib/megaco/test/megaco_app_test.erl
index 8e2148c236..597ec26338 100644
--- a/lib/megaco/test/megaco_app_test.erl
+++ b/lib/megaco/test/megaco_app_test.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2002-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%
%%
@@ -87,6 +87,10 @@ is_app(App) ->
case file:consult(File) of
{ok, [{application, App, AppFile}]} ->
{ok, AppFile};
+ {error, {LineNo, Mod, Code}} ->
+ IoList = lists:concat([File, ":", LineNo, ": ",
+ Mod:format_error(Code)]),
+ {error, list_to_atom(lists:flatten(IoList))};
Error ->
{error, {invalid_format, Error}}
end.
diff --git a/lib/megaco/test/megaco_config_test.erl b/lib/megaco/test/megaco_config_test.erl
index 453c1b8964..9ab1a7d90d 100644
--- a/lib/megaco/test/megaco_config_test.erl
+++ b/lib/megaco/test/megaco_config_test.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%
%%
@@ -106,166 +106,197 @@ config(Config) when is_list(Config) ->
Evil = 400,
End = 500,
+ InitialCmd =
+ fun(No, Desc, Cmd, VerifyVal) ->
+ initial_command(Initial + No, Desc, Cmd, VerifyVal)
+ end,
+
+ VerifyCmd =
+ fun(M, No, Key, V) ->
+ verify_user_default_command(M, Verify + No, Key, V)
+ end,
+
+ NiceCmd =
+ fun(M, No, Key, Val) ->
+ nice_user_update_command(M, Nice + No, Key, Val)
+ end,
+
+ EvilCmd =
+ fun(M, No, Key, Val) ->
+ evil_user_update_command(M, Evil + No, Key, Val)
+ end,
+
+ %% End commands
+ ExitCmd =
+ fun(No, Desc, Cmd) ->
+ exit_command(End + No, Desc, Cmd)
+ end,
+ ErrorCmd =
+ fun(No, Desc, Cmd, MainReason, TS) ->
+ error_command(End + No, Desc, Cmd, MainReason, TS)
+ end,
+ PlainCmd =
+ fun(No, Desc, Cmd, V) ->
+ command(End + No, Desc, Cmd, V)
+ end,
+
Commands =
[
%% Initial commands
- initial_command( Initial + 0,
- "enable trace",
- fun() -> megaco:enable_trace(100, io) end, ok),
- initial_command( Initial + 1,
- "start",
- fun() -> megaco:start() end, ok),
- initial_command( Initial + 2,
- "Verify no active requests",
- fun() -> megaco:system_info(n_active_requests) end,
- 0),
- initial_command( Initial + 3,
- "Verify no active replies",
- fun() -> megaco:system_info(n_active_replies) end,
- 0),
- initial_command( Initial + 4,
- "Verify no active connections",
- fun() ->
- megaco:system_info(n_active_connections)
- end,
- 0),
- initial_command( Initial + 5,
- "Verify no connections",
- fun() -> megaco:system_info(connections) end, []),
- initial_command( Initial + 6,
- "Verify no users",
- fun() -> megaco:system_info(users) end, []),
- initial_command( Initial + 7,
- "Start user",
- fun() -> megaco:start_user(Mid, []) end, ok),
-
+ InitialCmd(0,
+ "enable trace",
+ fun() -> megaco:enable_trace(100, io) end,
+ ok),
+ InitialCmd(1,
+ "start",
+ fun() -> megaco:start() end,
+ ok),
+ InitialCmd(2,
+ "Verify no active requests",
+ fun() -> megaco:system_info(n_active_requests) end,
+ 0),
+ InitialCmd(3,
+ "Verify no active replies",
+ fun() -> megaco:system_info(n_active_replies) end,
+ 0),
+ InitialCmd(4,
+ "Verify no active connections",
+ fun() -> megaco:system_info(n_active_connections) end,
+ 0),
+ InitialCmd(5,
+ "Verify no connections",
+ fun() -> megaco:system_info(connections) end,
+ []),
+ InitialCmd(6,
+ "Verify no users",
+ fun() -> megaco:system_info(users) end,
+ []),
+ InitialCmd(7,
+ "Start user",
+ fun() -> megaco:start_user(Mid, []) end,
+ ok),
+
%% Verify user defaults
- verify_user_default_command(Mid, Verify + 1, connections, []),
- verify_user_default_command(Mid, Verify + 2, min_trans_id, 1),
- verify_user_default_command(Mid, Verify + 3, max_trans_id, infinity),
- verify_user_default_command(Mid, Verify + 4, request_timer,
- #megaco_incr_timer{}),
- verify_user_default_command(Mid, Verify + 5, long_request_timer, timer:seconds(60)),
- verify_user_default_command(Mid, Verify + 6, auto_ack, false),
- verify_user_default_command(Mid, Verify + 7, pending_timer, 30000),
- verify_user_default_command(Mid, Verify + 8, reply_timer, 30000),
- verify_user_default_command(Mid, Verify + 9, send_mod, megaco_tcp),
- verify_user_default_command(Mid, Verify + 10, encoding_mod,
- megaco_pretty_text_encoder),
- verify_user_default_command(Mid, Verify + 11, encoding_config, []),
- verify_user_default_command(Mid, Verify + 12, protocol_version, 1),
- verify_user_default_command(Mid, Verify + 13, reply_data, undefined),
- verify_user_default_command(Mid, Verify + 14, receive_handle,
- fun(H) when is_record(H, megaco_receive_handle) -> {ok, H};
- (R) -> {error, R}
- end),
+ VerifyCmd(Mid, 1, connections, []),
+ VerifyCmd(Mid, 2, min_trans_id, 1),
+ VerifyCmd(Mid, 3, max_trans_id, infinity),
+ VerifyCmd(Mid, 4, request_timer, #megaco_incr_timer{}),
+ VerifyCmd(Mid, 5, long_request_timer, timer:seconds(60)),
+ VerifyCmd(Mid, 6, auto_ack, false),
+ VerifyCmd(Mid, 7, pending_timer, 30000),
+ VerifyCmd(Mid, 8, reply_timer, 30000),
+ VerifyCmd(Mid, 9, send_mod, megaco_tcp),
+ VerifyCmd(Mid, 10, encoding_mod, megaco_pretty_text_encoder),
+ VerifyCmd(Mid, 11, encoding_config, []),
+ VerifyCmd(Mid, 12, protocol_version, 1),
+ VerifyCmd(Mid, 13, reply_data, undefined),
+ VerifyCmd(Mid, 14, receive_handle,
+ fun(H) when is_record(H, megaco_receive_handle) ->
+ {ok, H};
+ (R) ->
+ {error, R}
+ end),
%% Nice update
- nice_user_update_command(Mid, Nice + 1, min_trans_id, Int),
- nice_user_update_command(Mid, Nice + 2, max_trans_id, Int),
- nice_user_update_command(Mid, Nice + 3, max_trans_id, infinity),
- nice_user_update_command(Mid, Nice + 4, request_timer, Int),
- nice_user_update_command(Mid, Nice + 5, request_timer, infinity),
- nice_user_update_command(Mid, Nice + 6, request_timer, IT),
- nice_user_update_command(Mid, Nice + 7, long_request_timer, Int),
- nice_user_update_command(Mid, Nice + 8, long_request_timer, infinity),
- nice_user_update_command(Mid, Nice + 9, long_request_timer, IT),
- nice_user_update_command(Mid, Nice + 10, auto_ack, true),
- nice_user_update_command(Mid, Nice + 11, auto_ack, false),
- nice_user_update_command(Mid, Nice + 12, pending_timer, Int),
- nice_user_update_command(Mid, Nice + 13, pending_timer, infinity),
- nice_user_update_command(Mid, Nice + 14, pending_timer, IT),
- nice_user_update_command(Mid, Nice + 15, reply_timer, Int),
- nice_user_update_command(Mid, Nice + 16, reply_timer, infinity),
- nice_user_update_command(Mid, Nice + 17, reply_timer, IT),
- nice_user_update_command(Mid, Nice + 18, send_mod, an_atom),
- nice_user_update_command(Mid, Nice + 19, encoding_mod, an_atom),
- nice_user_update_command(Mid, Nice + 20, encoding_config, []),
- nice_user_update_command(Mid, Nice + 21, protocol_version, Int),
- nice_user_update_command(Mid, Nice + 23, reply_data, IT),
- nice_user_update_command(Mid, Nice + 23, resend_indication, true),
- nice_user_update_command(Mid, Nice + 24, resend_indication, false),
- nice_user_update_command(Mid, Nice + 25, resend_indication, flag),
+ NiceCmd(Mid, 1, min_trans_id, Int),
+ NiceCmd(Mid, 2, max_trans_id, Int),
+ NiceCmd(Mid, 3, max_trans_id, infinity),
+ NiceCmd(Mid, 4, request_timer, Int),
+ NiceCmd(Mid, 5, request_timer, infinity),
+ NiceCmd(Mid, 6, request_timer, IT),
+ NiceCmd(Mid, 7, long_request_timer, Int),
+ NiceCmd(Mid, 8, long_request_timer, infinity),
+ NiceCmd(Mid, 9, long_request_timer, IT),
+ NiceCmd(Mid, 10, auto_ack, true),
+ NiceCmd(Mid, 11, auto_ack, false),
+ NiceCmd(Mid, 12, pending_timer, Int),
+ NiceCmd(Mid, 13, pending_timer, infinity),
+ NiceCmd(Mid, 14, pending_timer, IT),
+ NiceCmd(Mid, 15, reply_timer, Int),
+ NiceCmd(Mid, 16, reply_timer, infinity),
+ NiceCmd(Mid, 17, reply_timer, IT),
+ NiceCmd(Mid, 18, send_mod, an_atom),
+ NiceCmd(Mid, 19, encoding_mod, an_atom),
+ NiceCmd(Mid, 20, encoding_config, []),
+ NiceCmd(Mid, 21, protocol_version, Int),
+ NiceCmd(Mid, 23, reply_data, IT),
+ NiceCmd(Mid, 23, resend_indication, true),
+ NiceCmd(Mid, 24, resend_indication, false),
+ NiceCmd(Mid, 25, resend_indication, flag),
%% Evil update
- evil_user_update_command(Mid, Evil + 1, min_trans_id, NonInt),
- evil_user_update_command(Mid, Evil + 2, max_trans_id, NonInt),
- evil_user_update_command(Mid, Evil + 3, max_trans_id, non_infinity),
- evil_user_update_command(Mid, Evil + 4, request_timer, NonInt),
- evil_user_update_command(Mid, Evil + 5, request_timer, non_infinity),
- evil_user_update_command(Mid, Evil + 6, request_timer, IT2),
- evil_user_update_command(Mid, Evil + 7, request_timer, IT3),
- evil_user_update_command(Mid, Evil + 8, request_timer, IT4),
- evil_user_update_command(Mid, Evil + 9, request_timer, IT5),
- evil_user_update_command(Mid, Evil + 10, long_request_timer, NonInt),
- evil_user_update_command(Mid, Evil + 11, long_request_timer, non_infinity),
- evil_user_update_command(Mid, Evil + 12, long_request_timer, IT2),
- evil_user_update_command(Mid, Evil + 13, long_request_timer, IT3),
- evil_user_update_command(Mid, Evil + 14, long_request_timer, IT4),
- evil_user_update_command(Mid, Evil + 15, long_request_timer, IT5),
- evil_user_update_command(Mid, Evil + 16, auto_ack, non_bool),
- evil_user_update_command(Mid, Evil + 17, pending_timer, NonInt),
- evil_user_update_command(Mid, Evil + 18, pending_timer, non_infinity),
- evil_user_update_command(Mid, Evil + 19, pending_timer, IT2),
- evil_user_update_command(Mid, Evil + 20, pending_timer, IT3),
- evil_user_update_command(Mid, Evil + 21, pending_timer, IT4),
- evil_user_update_command(Mid, Evil + 22, pending_timer, IT5),
- evil_user_update_command(Mid, Evil + 23, reply_timer, NonInt),
- evil_user_update_command(Mid, Evil + 24, reply_timer, non_infinity),
- evil_user_update_command(Mid, Evil + 25, reply_timer, IT2),
- evil_user_update_command(Mid, Evil + 26, reply_timer, IT3),
- evil_user_update_command(Mid, Evil + 27, reply_timer, IT4),
- evil_user_update_command(Mid, Evil + 28, reply_timer, IT5),
- evil_user_update_command(Mid, Evil + 29, send_mod, {non_atom}),
- evil_user_update_command(Mid, Evil + 30, encoding_mod, {non_atom}),
- evil_user_update_command(Mid, Evil + 31, encoding_config, non_list),
- evil_user_update_command(Mid, Evil + 32, protocol_version, NonInt),
- evil_user_update_command(Mid, Evil + 33, resend_indication, flagg),
-
-
- exit_command(End + 1,
- "Verify non-existing system info",
- fun() -> megaco:system_info(non_exist) end),
- exit_command(End + 2,
- "Verify non-existing user user info",
- fun() -> megaco:user_info(non_exist, trans_id) end),
- exit_command(End + 3, "Verify non-existing user info",
- fun() -> megaco:user_info(Mid, non_exist) end),
-
- error_command(End + 4,
- "Try updating user info for non-existing user",
- fun() ->
- megaco:update_user_info(non_exist, trans_id, 1)
- end,
- no_such_user, 2),
- error_command(End + 11,
- "Try updating non-existing user info",
- fun() ->
- megaco:update_user_info(Mid, trans_id, 4711)
- end,
- bad_user_val, 4),
- error_command(End + 12,
- "Try start already started user",
- fun() ->
- megaco:start_user(Mid, [])
- end,
- user_already_exists, 2),
-
- command(End + 13, "Verify started users",
- fun() -> megaco:system_info(users) end, [Mid]),
- command(End + 14, "Stop user", fun() -> megaco:stop_user(Mid) end, ok),
- command(End + 15, "Verify started users",
- fun() -> megaco:system_info(users) end, []),
- error_command(End + 16, "Try stop not started user",
- fun() -> megaco:stop_user(Mid) end, no_such_user, 2),
- error_command(End + 17, "Try start megaco (it's already started)",
- fun() -> megaco:start() end, already_started, 2),
- command(End + 18, "Stop megaco", fun() -> megaco:stop() end, ok),
- error_command(End + 19, "Try stop megaco (it's not running)",
- fun() -> megaco:stop() end, not_started, 2)
+ EvilCmd(Mid, 1, min_trans_id, NonInt),
+ EvilCmd(Mid, 2, max_trans_id, NonInt),
+ EvilCmd(Mid, 3, max_trans_id, non_infinity),
+ EvilCmd(Mid, 4, request_timer, NonInt),
+ EvilCmd(Mid, 5, request_timer, non_infinity),
+ EvilCmd(Mid, 6, request_timer, IT2),
+ EvilCmd(Mid, 7, request_timer, IT3),
+ EvilCmd(Mid, 8, request_timer, IT4),
+ EvilCmd(Mid, 9, request_timer, IT5),
+ EvilCmd(Mid, 10, long_request_timer, NonInt),
+ EvilCmd(Mid, 11, long_request_timer, non_infinity),
+ EvilCmd(Mid, 12, long_request_timer, IT2),
+ EvilCmd(Mid, 13, long_request_timer, IT3),
+ EvilCmd(Mid, 14, long_request_timer, IT4),
+ EvilCmd(Mid, 15, long_request_timer, IT5),
+ EvilCmd(Mid, 16, auto_ack, non_bool),
+ EvilCmd(Mid, 17, pending_timer, NonInt),
+ EvilCmd(Mid, 18, pending_timer, non_infinity),
+ EvilCmd(Mid, 19, pending_timer, IT2),
+ EvilCmd(Mid, 20, pending_timer, IT3),
+ EvilCmd(Mid, 21, pending_timer, IT4),
+ EvilCmd(Mid, 22, pending_timer, IT5),
+ EvilCmd(Mid, 23, reply_timer, NonInt),
+ EvilCmd(Mid, 24, reply_timer, non_infinity),
+ EvilCmd(Mid, 25, reply_timer, IT2),
+ EvilCmd(Mid, 26, reply_timer, IT3),
+ EvilCmd(Mid, 27, reply_timer, IT4),
+ EvilCmd(Mid, 28, reply_timer, IT5),
+ EvilCmd(Mid, 29, send_mod, {non_atom}),
+ EvilCmd(Mid, 30, encoding_mod, {non_atom}),
+ EvilCmd(Mid, 31, encoding_config, non_list),
+ EvilCmd(Mid, 32, protocol_version, NonInt),
+ EvilCmd(Mid, 33, resend_indication, flagg),
+
+
+ %% End
+ ExitCmd(1, "Verify non-existing system info",
+ fun() -> megaco:system_info(non_exist) end),
+ ExitCmd(2, "Verify non-existing user user info",
+ fun() -> megaco:user_info(non_exist, trans_id) end),
+ ExitCmd(3, "Verify non-existing user info",
+ fun() -> megaco:user_info(Mid, non_exist) end),
+
+ ErrorCmd(4, "Try updating user info for non-existing user",
+ fun() ->
+ megaco:update_user_info(non_exist, trans_id, 1)
+ end,
+ no_such_user, 2),
+ ErrorCmd(11, "Try updating non-existing user info",
+ fun() ->
+ megaco:update_user_info(Mid, trans_id, 4711)
+ end,
+ bad_user_val, 4),
+ ErrorCmd(12, "Try start already started user",
+ fun() -> megaco:start_user(Mid, []) end,
+ user_already_exists, 2),
+
+ PlainCmd(13, "Verify started users",
+ fun() -> megaco:system_info(users) end, [Mid]),
+ PlainCmd(14, "Stop user", fun() -> megaco:stop_user(Mid) end, ok),
+ PlainCmd(15, "Verify started users",
+ fun() -> megaco:system_info(users) end, []),
+ ErrorCmd(16, "Try stop not started user",
+ fun() -> megaco:stop_user(Mid) end, no_such_user, 2),
+ ErrorCmd(17, "Try start megaco (it's already started)",
+ fun() -> megaco:start() end, already_started, 2),
+ PlainCmd(18, "Stop megaco", fun() -> megaco:stop() end, ok),
+ ErrorCmd(19, "Try stop megaco (it's not running)",
+ fun() -> megaco:stop() end, not_started, 2)
],
@@ -279,7 +310,7 @@ exec([#command{id = No,
desc = Desc,
cmd = Cmd,
verify = Verify}|Commands]) ->
- io:format("Executing command ~2w: ~s: ", [No, Desc]),
+ io:format("Executing command ~3w: ~s: ", [No, Desc]),
case (catch Verify((catch Cmd()))) of
{ok, OK} ->
io:format("ok => ~p~n", [OK]),
@@ -320,7 +351,7 @@ nice_user_update_command(Mid, No, Key, Val) ->
evil_user_update_command(Mid, No, Key, Val) ->
- Desc = lists:flatten(io_lib:format("Evil: Update ~w", [Key])),
+ Desc = lists:flatten(io_lib:format("Evil - Update ~w", [Key])),
Cmd = fun() ->
case (catch megaco:user_info(Mid, Key)) of
{'EXIT', R} ->
@@ -371,14 +402,19 @@ error_command(No, Desc, Cmd, MainReason, TS) when is_function(Cmd) ->
end,
command(No, Desc, Cmd, Verify).
-command(No, Desc, Cmd, Verify) when is_integer(No) and is_list(Desc) and
- is_function(Cmd) and is_function(Verify) ->
+command(No, Desc, Cmd, Verify)
+ when (is_integer(No) andalso
+ is_list(Desc) andalso
+ is_function(Cmd) andalso
+ is_function(Verify)) ->
#command{id = No,
desc = Desc,
cmd = Cmd,
verify = Verify};
-command(No, Desc, Cmd, VerifyVal) when is_integer(No) and is_list(Desc) and
- is_function(Cmd) ->
+command(No, Desc, Cmd, VerifyVal)
+ when (is_integer(No) andalso
+ is_list(Desc) andalso
+ is_function(Cmd)) ->
Verify = fun(Val) ->
case Val of
VerifyVal ->
@@ -881,6 +917,12 @@ otp_8167(Config) when is_list(Config) ->
p("connect ok: CD = ~n~p", [CD]),
CH = CD#conn_data.conn_handle,
+ p("get value for item cancel from connection: ~p", [CH]),
+ false = megaco_config:conn_info(CH, cancel),
+
+ p("get value for item cancel from connection data", []),
+ false = megaco_config:conn_info(CD, cancel),
+
p("get value for item call_proxy_gc_timeout for connection: ~p", [CH]),
10101 = megaco_config:conn_info(CH, call_proxy_gc_timeout),
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index 19eca6d309..4ef0ed8f18 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,11 +18,13 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.14
+MEGACO_VSN = 3.14.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
-TICKETS = OTP-8317 OTP-8323 OTP-8328 OTP-8362 OTP-8403
+TICKETS = OTP-8529 OTP-8561 OTP-8627 OTP-8634
+
+TICKETS_3_14 = OTP-8317 OTP-8323 OTP-8328 OTP-8362 OTP-8403
TICKETS_3_13 = OTP-8205 OTP-8239 OTP-8249
--
cgit v1.2.3