diff options
author | Micael Karlberg <[email protected]> | 2010-06-07 12:00:00 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2010-08-20 08:57:11 +0200 |
commit | 61b1feed86ccf574613b913c5eea57d138eeb178 (patch) | |
tree | f4e25826fff8e222c95741ff401c5a112a912456 | |
parent | 6769f83da0f193052a30ff8933a014e9cf3b0cdf (diff) | |
download | otp-61b1feed86ccf574613b913c5eea57d138eeb178.tar.gz otp-61b1feed86ccf574613b913c5eea57d138eeb178.tar.bz2 otp-61b1feed86ccf574613b913c5eea57d138eeb178.zip |
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.
-rw-r--r-- | lib/megaco/doc/src/megaco.xml | 16 | ||||
-rw-r--r-- | lib/megaco/doc/src/megaco_mib.xml | 12 | ||||
-rw-r--r-- | lib/megaco/doc/src/megaco_run.xml | 8 | ||||
-rw-r--r-- | lib/megaco/doc/src/megaco_user.xml | 11 | ||||
-rw-r--r-- | lib/megaco/doc/src/notes.xml | 62 | ||||
-rw-r--r-- | lib/megaco/doc/src/notes_history.xml | 10 | ||||
-rw-r--r-- | lib/megaco/src/app/megaco.appup.src | 23 | ||||
-rw-r--r-- | lib/megaco/src/app/megaco_internal.hrl | 26 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_config.erl | 427 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_messenger.erl | 239 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_monitor.erl | 33 | ||||
-rw-r--r-- | lib/megaco/src/flex/Makefile.in | 2 | ||||
-rw-r--r-- | lib/megaco/test/megaco_app_test.erl | 14 | ||||
-rw-r--r-- | lib/megaco/test/megaco_config_test.erl | 362 | ||||
-rw-r--r-- | lib/megaco/vsn.mk | 6 |
15 files changed, 805 insertions, 446 deletions
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 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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. - + </legalnotice> <title>megaco</title> @@ -40,6 +40,16 @@ <section> <title>DATA TYPES</title> <code type="none"><![CDATA[ +megaco_mid() = ip4Address() | ip6Address() | + domainName() | deviceName() | + mtpAddress() +ip4Address() = #'IP4Address'{} +ip6Address() = #'IP6Address'{} +domainName() = #'DomainName'{} +deviceName() = pathName() +pathName() = ia5String(1..64) +mtpAddress() = octetString(2..4) + action_request() = #'ActionRequest'{} action_reply() = #'ActionReply'{} error_desc() = #'ErrorDescriptor'{} diff --git a/lib/megaco/doc/src/megaco_mib.xml b/lib/megaco/doc/src/megaco_mib.xml index 3c0a549590..f1abe08fb5 100644 --- a/lib/megaco/doc/src/megaco_mib.xml +++ b/lib/megaco/doc/src/megaco_mib.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2009</year> + <year>2002</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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. - + </legalnotice> <title>Megaco mib</title> @@ -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 <seealso marker="megaco_tcp#stats">megaco_tcp</seealso> and <seealso marker="megaco_udp#stats">megaco_udp</seealso>) maintain their - own counters and the application engine (see <seealso marker="megaco#stats">megaco</seealso>) maintain it's own + own counters and the application engine (see <seealso marker="megaco#stats">megaco</seealso>) maintain its own counters.</p> <p>This also means that if a user implement their own transport - service then it has to maintain it's own statistics.</p> + service then it has to maintain its own statistics.</p> </section> <section> <title>Distribution</title> - <p>Each megaco application maintains it's own set of counters. So + <p>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).</p> 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 @@ <chapter> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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. - + </legalnotice> <title>Running the stack</title> @@ -365,7 +365,7 @@ then the specified max message size (see the <seealso marker="megaco#user_info">max_pdu_size</seealso> option). Finally, if segmentation is decided, then each action reply - will make up it's own (segment) message.</p> + will make up its own (segment) message.</p> </item> </list> </section> 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 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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. - + </legalnotice> <title>megaco_user</title> @@ -471,7 +471,7 @@ protocol_version() = integer() ]]></code> <v>transaction_result() = action_reps()</v> <v>segment_result() = {segment_no(), last_segment(), action_reps()}</v> <v>action_reps() = [action_reply()]</v> - <v>failure() = {error, reason()}</v> + <v>failure() = {error, reason()} | {error, ReplyNo, reason()}</v> <v>reason() = transaction_reason() | segment_reason() | user_cancel_reason() | send_reason() | other_reason()</v> <v>transaction_reason() = error_desc()</v> <v>segment_reason() = {segment_no(), last_segment(), error_desc()}</v> @@ -486,6 +486,7 @@ protocol_version() = integer() ]]></code> <v>send_failed_reason() = {send_message_failed, reason_for_send_failure()}</v> <v>reason_for_send_failure() = term()</v> <v>ReplyData = reply_data()</v> + <v>ReplyNo = integer() > 0</v> <v>reply_data() = term()</v> <v>Extra = term()</v> </type> @@ -669,7 +670,7 @@ protocol_version() = integer() ]]></code> <p>Invoked when a unexpected message is received</p> <p>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).</p> 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 @@ -36,6 +36,68 @@ section is the version number of Megaco.</p> <section> + <title>Megaco 3.14.1</title> + + <p>Version 3.14.1 supports code replacement in runtime from/to + version 3.14, 3.13, 3.12 and 3.11.3.</p> + + <section> + <title>Improvements and new features</title> + +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>A minor compiler related performance improvement. </p> + <p>Own Id: OTP-8561</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed bugs and malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>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. </p> + <p>Note that this solution only protects against multiple + reply deliveries! </p> + <p>Own Id: OTP-8529</p> + <p>Aux Id: Seq 10915</p> + </item> + + <item> + <p>Fix shared libraries installation. </p> + <p>The flex shared lib(s) were incorrectly installed as data + files. </p> + <p>Peter Lemenkov</p> + <p>Own Id: OTP-8627</p> + </item> + + <item> + <p>Eliminated a possible raise condition while creating + pending counters. </p> + <p>Own Id: OTP-8634</p> + <p>Aux Id: Seq 11579</p> + </item> + + </list> + + </section> + + </section> <!-- 3.14.1 --> + + + <section> <title>Megaco 3.14</title> <p>Version 3.14 supports code replacement in runtime from/to 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 @@ <chapter> <header> <copyright> - <year>2006</year><year>2009</year> + <year>2006</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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. - + </legalnotice> <title>Megaco Release Notes history</title> @@ -2764,7 +2764,7 @@ <p>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). <br></br>See the <seealso marker="megaco#user_info">threaded</seealso> parameter of the user_info function (also conn_info).</p> @@ -2911,7 +2911,7 @@ <title>Improvements and new features</title> <list type="bulleted"> <item> - <p>This is just a code up-/downgrade cleanup release. I.e. It's the + <p>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.</p> </item> 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 |