asterisk/main/pbx.c

12691 lines
378 KiB
C
Raw Normal View History

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2008, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Core PBX routines.
*
* \author Mark Spencer <markster@digium.com>
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
#include "asterisk.h"
git migration: Refactor the ASTERISK_FILE_VERSION macro Git does not support the ability to replace a token with a version string during check-in. While it does have support for replacing a token on clone, this is somewhat sub-optimal: the token is replaced with the object hash, which is not particularly easy for human consumption. What's more, in practice, the source file version was often not terribly useful. Generally, when triaging bugs, the overall version of Asterisk is far more useful than an individual SVN version of a file. As a result, this patch removes Asterisk's support for showing source file versions. Specifically, it does the following: * Rename ASTERISK_FILE_VERSION macro to ASTERISK_REGISTER_FILE, and remove passing the version in with the macro. Other facilities than 'core show file version' make use of the file names, such as setting a debug level only on a specific file. As such, the act of registering source files with the Asterisk core still has use. The macro rename now reflects the new macro purpose. * main/asterisk: - Refactor the file_version structure to reflect that it no longer tracks a version field. - Remove the "core show file version" CLI command. Without the file version, it is no longer useful. - Remove the ast_file_version_find function. The file version is no longer tracked. - Rename ast_register_file_version/ast_unregister_file_version to ast_register_file/ast_unregister_file, respectively. * main/manager: Remove value from the Version key of the ModuleCheck Action. The actual key itself has not been removed, as doing so would absolutely constitute a backwards incompatible change. However, since the file version is no longer tracked, there is no need to attempt to include it in the Version key. * UPGRADE: Add notes for: - Modification to the ModuleCheck AMI Action - Removal of the "core show file version" CLI command Change-Id: I6cf0ff280e1668bf4957dc21f32a5ff43444a40e
2015-04-12 02:38:22 +00:00
ASTERISK_REGISTER_FILE()
#include "asterisk/_private.h"
#include "asterisk/paths.h" /* use ast_config_AST_SYSTEM_NAME */
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#if defined(HAVE_SYSINFO)
#include <sys/sysinfo.h>
#endif
#if defined(SOLARIS)
#include <sys/loadavg.h>
#endif
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/cdr.h"
#include "asterisk/config.h"
#include "asterisk/term.h"
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
#include "asterisk/time.h"
#include "asterisk/manager.h"
#include "asterisk/ast_expr.h"
#include "asterisk/linkedlists.h"
#define SAY_STUBS /* generate declarations and stubs for say methods */
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
#include "asterisk/presencestate.h"
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
#include "asterisk/hashtab.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/xmldoc.h"
#include "asterisk/astobj2.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/dial.h"
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
#include "asterisk/vector.h"
/*!
* \note I M P O R T A N T :
*
* The speed of extension handling will likely be among the most important
* aspects of this PBX. The switching scheme as it exists right now isn't
* terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
* of priorities, but a constant search time here would be great ;-)
*
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* A new algorithm to do searching based on a 'compiled' pattern tree is introduced
* here, and shows a fairly flat (constant) search time, even for over
* 10000 patterns.
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
* Also, using a hash table for context/priority name lookup can help prevent
* the find_extension routines from absorbing exponential cpu cycles as the number
* of contexts/priorities grow. I've previously tested find_extension with red-black trees,
* which have O(log2(n)) speed. Right now, I'm using hash tables, which do
* searches (ideally) in O(1) time. While these techniques do not yield much
* speed in small dialplans, they are worth the trouble in large dialplans.
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
*/
/*** DOCUMENTATION
<application name="Answer" language="en_US">
<synopsis>
Answer a channel if ringing.
</synopsis>
<syntax>
<parameter name="delay">
<para>Asterisk will wait this number of milliseconds before returning to
the dialplan after answering the call.</para>
</parameter>
</syntax>
<description>
<para>If the call has not been answered, this application will
answer it. Otherwise, it has no effect on the call.</para>
</description>
<see-also>
<ref type="application">Hangup</ref>
</see-also>
</application>
<application name="BackGround" language="en_US">
<synopsis>
Play an audio file while waiting for digits of an extension to go to.
</synopsis>
<syntax>
<parameter name="filenames" required="true" argsep="&amp;">
<argument name="filename1" required="true" />
<argument name="filename2" multiple="true" />
</parameter>
<parameter name="options">
<optionlist>
<option name="s">
<para>Causes the playback of the message to be skipped
if the channel is not in the <literal>up</literal> state (i.e. it
hasn't been answered yet). If this happens, the
application will return immediately.</para>
</option>
<option name="n">
<para>Don't answer the channel before playing the files.</para>
</option>
<option name="m">
<para>Only break if a digit hit matches a one digit
extension in the destination context.</para>
</option>
</optionlist>
</parameter>
<parameter name="langoverride">
<para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
</parameter>
<parameter name="context">
<para>This is the dialplan context that this application will use when exiting
to a dialed extension.</para>
</parameter>
</syntax>
<description>
<para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
while waiting for an extension to be dialed by the calling channel. To continue waiting
for digits after this application has finished playing files, the <literal>WaitExten</literal>
application should be used.</para>
<para>If one of the requested sound files does not exist, call processing will be terminated.</para>
<para>This application sets the following channel variable upon completion:</para>
<variablelist>
<variable name="BACKGROUNDSTATUS">
<para>The status of the background attempt as a text string.</para>
<value name="SUCCESS" />
<value name="FAILED" />
</variable>
</variablelist>
</description>
<see-also>
<ref type="application">ControlPlayback</ref>
<ref type="application">WaitExten</ref>
<ref type="application">BackgroundDetect</ref>
<ref type="function">TIMEOUT</ref>
</see-also>
</application>
<application name="Busy" language="en_US">
<synopsis>
Indicate the Busy condition.
</synopsis>
<syntax>
<parameter name="timeout">
<para>If specified, the calling channel will be hung up after the specified number of seconds.
Otherwise, this application will wait until the calling channel hangs up.</para>
</parameter>
</syntax>
<description>
<para>This application will indicate the busy condition to the calling channel.</para>
</description>
<see-also>
<ref type="application">Congestion</ref>
<ref type="application">Progress</ref>
<ref type="application">Playtones</ref>
<ref type="application">Hangup</ref>
</see-also>
</application>
<application name="Congestion" language="en_US">
<synopsis>
Indicate the Congestion condition.
</synopsis>
<syntax>
<parameter name="timeout">
<para>If specified, the calling channel will be hung up after the specified number of seconds.
Otherwise, this application will wait until the calling channel hangs up.</para>
</parameter>
</syntax>
<description>
<para>This application will indicate the congestion condition to the calling channel.</para>
</description>
<see-also>
<ref type="application">Busy</ref>
<ref type="application">Progress</ref>
<ref type="application">Playtones</ref>
<ref type="application">Hangup</ref>
</see-also>
</application>
<application name="ExecIfTime" language="en_US">
<synopsis>
Conditional application execution based on the current time.
</synopsis>
<syntax argsep="?">
<parameter name="day_condition" required="true">
<argument name="times" required="true" />
<argument name="weekdays" required="true" />
<argument name="mdays" required="true" />
<argument name="months" required="true" />
<argument name="timezone" required="false" />
</parameter>
<parameter name="appname" required="true" hasparams="optional">
<argument name="appargs" required="true" />
</parameter>
</syntax>
<description>
<para>This application will execute the specified dialplan application, with optional
arguments, if the current time matches the given time specification.</para>
</description>
<see-also>
<ref type="application">Exec</ref>
<ref type="application">ExecIf</ref>
<ref type="application">TryExec</ref>
<ref type="application">GotoIfTime</ref>
</see-also>
</application>
<application name="Goto" language="en_US">
<synopsis>
Jump to a particular priority, extension, or context.
</synopsis>
<syntax>
<parameter name="context" />
<parameter name="extensions" />
<parameter name="priority" required="true" />
</syntax>
<description>
<para>This application will set the current context, extension, and priority in the channel structure.
After it completes, the pbx engine will continue dialplan execution at the specified location.
If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
<replaceable>context</replaceable>, are specified, then this application will
just set the specified <replaceable>priority</replaceable> of the current extension.</para>
<para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
return a <literal>-1</literal>, and the channel and call will be terminated.</para>
<para>If the location that is put into the channel information is bogus, and asterisk cannot
find that location in the dialplan, then the execution engine will try to find and execute the code in
the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
<literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
What this means is that, for example, you specify a context that does not exist, then
it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
and the call will terminate!</para>
</description>
<see-also>
<ref type="application">GotoIf</ref>
<ref type="application">GotoIfTime</ref>
<ref type="application">Gosub</ref>
<ref type="application">Macro</ref>
</see-also>
</application>
<application name="GotoIf" language="en_US">
<synopsis>
Conditional goto.
</synopsis>
<syntax argsep="?">
<parameter name="condition" required="true" />
<parameter name="destination" required="true" argsep=":">
<argument name="labeliftrue">
<para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
Takes the form similar to Goto() of [[context,]extension,]priority.</para>
</argument>
<argument name="labeliffalse">
<para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
Takes the form similar to Goto() of [[context,]extension,]priority.</para>
</argument>
</parameter>
</syntax>
<description>
<para>This application will set the current context, extension, and priority in the channel structure
based on the evaluation of the given condition. After this application completes, the
pbx engine will continue dialplan execution at the specified location in the dialplan.
The labels are specified with the same syntax as used within the Goto application.
If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
next instruction. If the target location is bogus, and does not exist, the execution engine will try
to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
If that does not exist, it will try to execute the <literal>h</literal> extension.
If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
the channel is hung up, and the execution of instructions on the channel is terminated.
Remember that this command can set the current context, and if the context specified
does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
the channel and call will both be terminated!.</para>
</description>
<see-also>
<ref type="application">Goto</ref>
<ref type="application">GotoIfTime</ref>
<ref type="application">GosubIf</ref>
<ref type="application">MacroIf</ref>
</see-also>
</application>
<application name="GotoIfTime" language="en_US">
<synopsis>
Conditional Goto based on the current time.
</synopsis>
<syntax argsep="?">
<parameter name="condition" required="true">
<argument name="times" required="true" />
<argument name="weekdays" required="true" />
<argument name="mdays" required="true" />
<argument name="months" required="true" />
<argument name="timezone" required="false" />
</parameter>
<parameter name="destination" required="true" argsep=":">
<argument name="labeliftrue">
<para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
Takes the form similar to Goto() of [[context,]extension,]priority.</para>
</argument>
<argument name="labeliffalse">
<para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
Takes the form similar to Goto() of [[context,]extension,]priority.</para>
</argument>
</parameter>
</syntax>
<description>
<para>This application will set the context, extension, and priority in the channel structure
based on the evaluation of the given time specification. After this application completes,
the pbx engine will continue dialplan execution at the specified location in the dialplan.
If the current time is within the given time specification, the channel will continue at
<replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
Further information on the time specification can be found in examples
illustrating how to do time-based context includes in the dialplan.</para>
</description>
<see-also>
<ref type="application">GotoIf</ref>
<ref type="application">Goto</ref>
<ref type="function">IFTIME</ref>
<ref type="function">TESTTIME</ref>
</see-also>
</application>
<application name="ImportVar" language="en_US">
<synopsis>
Import a variable from a channel into a new variable.
</synopsis>
<syntax argsep="=">
<parameter name="newvar" required="true" />
<parameter name="vardata" required="true">
<argument name="channelname" required="true" />
<argument name="variable" required="true" />
</parameter>
</syntax>
<description>
<para>This application imports a <replaceable>variable</replaceable> from the specified
<replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
(<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
application). Variables created by this application have the same inheritance properties as those
created with the <literal>Set</literal> application.</para>
</description>
<see-also>
<ref type="application">Set</ref>
</see-also>
</application>
<application name="Hangup" language="en_US">
<synopsis>
Hang up the calling channel.
</synopsis>
<syntax>
<parameter name="causecode">
<para>If a <replaceable>causecode</replaceable> is given the channel's
hangup cause will be set to the given value.</para>
</parameter>
</syntax>
<description>
<para>This application will hang up the calling channel.</para>
</description>
<see-also>
<ref type="application">Answer</ref>
<ref type="application">Busy</ref>
<ref type="application">Congestion</ref>
</see-also>
</application>
<application name="Incomplete" language="en_US">
<synopsis>
Returns AST_PBX_INCOMPLETE value.
</synopsis>
<syntax>
<parameter name="n">
<para>If specified, then Incomplete will not attempt to answer the channel first.</para>
<note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
</parameter>
</syntax>
<description>
<para>Signals the PBX routines that the previous matched extension is incomplete
and that further input should be allowed before matching can be considered
to be complete. Can be used within a pattern match when certain criteria warrants
a longer match.</para>
</description>
</application>
<application name="NoOp" language="en_US">
<synopsis>
Do Nothing (No Operation).
</synopsis>
<syntax>
<parameter name="text">
<para>Any text provided can be viewed at the Asterisk CLI.</para>
</parameter>
</syntax>
<description>
<para>This application does nothing. However, it is useful for debugging purposes.</para>
<para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
</description>
<see-also>
<ref type="application">Verbose</ref>
<ref type="application">Log</ref>
</see-also>
</application>
<application name="Proceeding" language="en_US">
<synopsis>
Indicate proceeding.
</synopsis>
<syntax />
<description>
<para>This application will request that a proceeding message be provided to the calling channel.</para>
</description>
</application>
<application name="Progress" language="en_US">
<synopsis>
Indicate progress.
</synopsis>
<syntax />
<description>
<para>This application will request that in-band progress information be provided to the calling channel.</para>
</description>
<see-also>
<ref type="application">Busy</ref>
<ref type="application">Congestion</ref>
<ref type="application">Ringing</ref>
<ref type="application">Playtones</ref>
</see-also>
</application>
<application name="RaiseException" language="en_US">
<synopsis>
Handle an exceptional condition.
</synopsis>
<syntax>
<parameter name="reason" required="true" />
</syntax>
<description>
<para>This application will jump to the <literal>e</literal> extension in the current context, setting the
dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
</description>
<see-also>
<ref type="function">Exception</ref>
</see-also>
</application>
<application name="Ringing" language="en_US">
<synopsis>
Indicate ringing tone.
</synopsis>
<syntax />
<description>
<para>This application will request that the channel indicate a ringing tone to the user.</para>
</description>
<see-also>
<ref type="application">Busy</ref>
<ref type="application">Congestion</ref>
<ref type="application">Progress</ref>
<ref type="application">Playtones</ref>
</see-also>
</application>
<application name="SayAlpha" language="en_US">
<synopsis>
Say Alpha.
</synopsis>
<syntax>
<parameter name="string" required="true" />
</syntax>
<description>
<para>This application will play the sounds that correspond to the letters
of the given <replaceable>string</replaceable>. If the channel variable
<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
then this application will react to DTMF in the same way as
<literal>Background</literal>.</para>
</description>
<see-also>
<ref type="application">SayDigits</ref>
<ref type="application">SayNumber</ref>
<ref type="application">SayPhonetic</ref>
<ref type="function">CHANNEL</ref>
</see-also>
</application>
<application name="SayAlphaCase" language="en_US">
<synopsis>
Say Alpha.
</synopsis>
<syntax>
<parameter name="casetype" required="true" >
<enumlist>
<enum name="a">
<para>Case sensitive (all) pronunciation.
(Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
</enum>
<enum name="l">
<para>Case sensitive (lower) pronunciation.
(Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
</enum>
<enum name="n">
<para>Case insensitive pronunciation. Equivalent to SayAlpha.
(Ex: SayAlphaCase(n,aBc) - a b c).</para>
</enum>
<enum name="u">
<para>Case sensitive (upper) pronunciation.
(Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
</enum>
</enumlist>
</parameter>
<parameter name="string" required="true" />
</syntax>
<description>
<para>This application will play the sounds that correspond to the letters of the
given <replaceable>string</replaceable>. Optionally, a <replaceable>casetype</replaceable> may be
specified. This will be used for case-insensitive or case-sensitive pronunciations. If the channel
variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
application will react to DTMF in the same way as <literal>Background</literal>.</para>
</description>
<see-also>
<ref type="application">SayDigits</ref>
<ref type="application">SayNumber</ref>
<ref type="application">SayPhonetic</ref>
<ref type="application">SayAlpha</ref>
<ref type="function">CHANNEL</ref>
</see-also>
</application>
<application name="SayDigits" language="en_US">
<synopsis>
Say Digits.
</synopsis>
<syntax>
<parameter name="digits" required="true" />
</syntax>
<description>
<para>This application will play the sounds that correspond to the digits of
the given number. This will use the language that is currently set for the channel.
If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
(case insensitive), then this application will react to DTMF in the same way as
<literal>Background</literal>.</para>
</description>
<see-also>
<ref type="application">SayAlpha</ref>
<ref type="application">SayNumber</ref>
<ref type="application">SayPhonetic</ref>
<ref type="function">CHANNEL</ref>
</see-also>
</application>
<application name="SayNumber" language="en_US">
<synopsis>
Say Number.
</synopsis>
<syntax>
<parameter name="digits" required="true" />
<parameter name="gender" />
</syntax>
<description>
<para>This application will play the sounds that correspond to the given
<replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
specified. This will use the language that is currently set for the channel. See the CHANNEL()
function for more information on setting the language for the channel. If the channel variable
<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
application will react to DTMF in the same way as <literal>Background</literal>.</para>
</description>
<see-also>
<ref type="application">SayAlpha</ref>
<ref type="application">SayDigits</ref>
<ref type="application">SayPhonetic</ref>
<ref type="function">CHANNEL</ref>
</see-also>
</application>
<application name="SayPhonetic" language="en_US">
<synopsis>
Say Phonetic.
</synopsis>
<syntax>
<parameter name="string" required="true" />
</syntax>
<description>
<para>This application will play the sounds from the phonetic alphabet that correspond to the
letters in the given <replaceable>string</replaceable>. If the channel variable
<variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
application will react to DTMF in the same way as <literal>Background</literal>.</para>
</description>
<see-also>
<ref type="application">SayAlpha</ref>
<ref type="application">SayDigits</ref>
<ref type="application">SayNumber</ref>
</see-also>
</application>
<application name="Set" language="en_US">
<synopsis>
Set channel variable or function value.
</synopsis>
<syntax argsep="=">
<parameter name="name" required="true" />
<parameter name="value" required="true" />
</syntax>
<description>
<para>This function can be used to set the value of channel variables or dialplan functions.
When setting variables, if the variable name is prefixed with <literal>_</literal>,
the variable will be inherited into channels created from the current channel.
If the variable name is prefixed with <literal>__</literal>, the variable will be
inherited into channels created from the current channel and all children channels.</para>
<note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
the behavior of this app changes, and strips surrounding quotes from the right hand side as
it did previously in 1.4.
The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
protect separators and quotes in various database access strings has been greatly
reduced by these changes.</para></note>
</description>
<see-also>
<ref type="application">MSet</ref>
<ref type="function">GLOBAL</ref>
<ref type="function">SET</ref>
<ref type="function">ENV</ref>
</see-also>
</application>
<application name="MSet" language="en_US">
<synopsis>
Set channel variable(s) or function value(s).
</synopsis>
<syntax>
<parameter name="set1" required="true" argsep="=">
<argument name="name1" required="true" />
<argument name="value1" required="true" />
</parameter>
<parameter name="set2" multiple="true" argsep="=">
<argument name="name2" required="true" />
<argument name="value2" required="true" />
</parameter>
</syntax>
<description>
<para>This function can be used to set the value of channel variables or dialplan functions.
When setting variables, if the variable name is prefixed with <literal>_</literal>,
the variable will be inherited into channels created from the current channel
If the variable name is prefixed with <literal>__</literal>, the variable will be
inherited into channels created from the current channel and all children channels.
MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
prone to doing things that you may not expect. For example, it strips surrounding
double-quotes from the right-hand side (value). If you need to put a separator
character (comma or vert-bar), you will need to escape them by inserting a backslash
before them. Avoid its use if possible.</para>
</description>
<see-also>
<ref type="application">Set</ref>
</see-also>
</application>
<application name="SetAMAFlags" language="en_US">
<synopsis>
Set the AMA Flags.
</synopsis>
<syntax>
<parameter name="flag" />
</syntax>
<description>
<para>This application will set the channel's AMA Flags for billing purposes.</para>
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
<warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
</description>
<see-also>
<ref type="function">CDR</ref>
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
<ref type="function">CHANNEL</ref>
</see-also>
</application>
<application name="Wait" language="en_US">
<synopsis>
Waits for some time.
</synopsis>
<syntax>
<parameter name="seconds" required="true">
<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
application to wait for 1.5 seconds.</para>
</parameter>
</syntax>
<description>
<para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
</description>
</application>
<application name="WaitExten" language="en_US">
<synopsis>
Waits for an extension to be entered.
</synopsis>
<syntax>
<parameter name="seconds">
<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
application to wait for 1.5 seconds.</para>
</parameter>
<parameter name="options">
<optionlist>
<option name="m">
<para>Provide music on hold to the caller while waiting for an extension.</para>
<argument name="x">
<para>Specify the class for music on hold. <emphasis>CHANNEL(musicclass) will
be used instead if set</emphasis></para>
</argument>
</option>
</optionlist>
</parameter>
</syntax>
<description>
<para>This application waits for the user to enter a new extension for a specified number
of <replaceable>seconds</replaceable>.</para>
<xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
</description>
<see-also>
<ref type="application">Background</ref>
<ref type="function">TIMEOUT</ref>
</see-also>
</application>
<function name="EXCEPTION" language="en_US">
<synopsis>
Retrieve the details of the current dialplan exception.
</synopsis>
<syntax>
<parameter name="field" required="true">
<para>The following fields are available for retrieval:</para>
<enumlist>
<enum name="reason">
<para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
value set by the RaiseException() application</para>
</enum>
<enum name="context">
<para>The context executing when the exception occurred.</para>
</enum>
<enum name="exten">
<para>The extension executing when the exception occurred.</para>
</enum>
<enum name="priority">
<para>The numeric priority executing when the exception occurred.</para>
</enum>
</enumlist>
</parameter>
</syntax>
<description>
<para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
</description>
<see-also>
<ref type="application">RaiseException</ref>
</see-also>
</function>
<function name="TESTTIME" language="en_US">
<synopsis>
Sets a time to be used with the channel to test logical conditions.
</synopsis>
<syntax>
<parameter name="date" required="true" argsep=" ">
<para>Date in ISO 8601 format</para>
</parameter>
<parameter name="time" required="true" argsep=" ">
<para>Time in HH:MM:SS format (24-hour time)</para>
</parameter>
<parameter name="zone" required="false">
<para>Timezone name</para>
</parameter>
</syntax>
<description>
<para>To test dialplan timing conditions at times other than the current time, use
this function to set an alternate date and time. For example, you may wish to evaluate
whether a location will correctly identify to callers that the area is closed on Christmas
Day, when Christmas would otherwise fall on a day when the office is normally open.</para>
</description>
<see-also>
<ref type="application">GotoIfTime</ref>
</see-also>
</function>
<manager name="ShowDialPlan" language="en_US">
<synopsis>
Show dialplan contexts and extensions
</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<parameter name="Extension">
<para>Show a specific extension.</para>
</parameter>
<parameter name="Context">
<para>Show a specific context.</para>
</parameter>
</syntax>
<description>
<para>Show dialplan contexts and extensions. Be aware that showing the full dialplan
may take a lot of capacity.</para>
</description>
</manager>
<manager name="ExtensionStateList" language="en_US">
<synopsis>
List the current known extension states.
</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
</syntax>
<description>
<para>This will list out all known extension states in a
sequence of <replaceable>ExtensionStatus</replaceable> events.
When finished, a <replaceable>ExtensionStateListComplete</replaceable> event
will be emitted.</para>
</description>
<see-also>
<ref type="manager">ExtensionState</ref>
<ref type="function">HINT</ref>
<ref type="function">EXTENSION_STATE</ref>
</see-also>
<responses>
<list-elements>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='ExtensionStatus'])" />
</list-elements>
<managerEvent name="ExtensionStateListComplete" language="en_US">
<managerEventInstance class="EVENT_FLAG_COMMAND">
<synopsis>
Indicates the end of the list the current known extension states.
</synopsis>
<syntax>
<parameter name="EventList">
<para>Conveys the status of the event list.</para>
</parameter>
<parameter name="ListItems">
<para>Conveys the number of statuses reported.</para>
</parameter>
</syntax>
</managerEventInstance>
</managerEvent>
</responses>
</manager>
***/
#ifdef LOW_MEMORY
#define EXT_DATA_SIZE 256
#else
#define EXT_DATA_SIZE 8192
#endif
#define SWITCH_DATA_LENGTH 256
#define VAR_BUF_SIZE 4096
#define VAR_NORMAL 1
#define VAR_SOFTTRAN 2
#define VAR_HARDTRAN 3
#define BACKGROUND_SKIP (1 << 0)
#define BACKGROUND_NOANSWER (1 << 1)
#define BACKGROUND_MATCHEXTEN (1 << 2)
#define BACKGROUND_PLAYBACK (1 << 3)
AST_APP_OPTIONS(background_opts, {
AST_APP_OPTION('s', BACKGROUND_SKIP),
AST_APP_OPTION('n', BACKGROUND_NOANSWER),
AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
});
#define WAITEXTEN_MOH (1 << 0)
#define WAITEXTEN_DIALTONE (1 << 1)
AST_APP_OPTIONS(waitexten_opts, {
AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
});
struct ast_context;
struct ast_app;
AST_THREADSTORAGE(switch_data);
AST_THREADSTORAGE(extensionstate_buf);
/*!
* \brief A thread local indicating whether the current thread can run
* 'dangerous' dialplan functions.
*/
AST_THREADSTORAGE(thread_inhibit_escalations_tl);
/*!
* \brief Set to true (non-zero) to globally allow all dangerous dialplan
* functions to run.
*/
static int live_dangerously;
/*!
\brief ast_exten: An extension
The dialplan is saved as a linked list with each context
having it's own linked list of extensions - one item per
priority.
*/
struct ast_exten {
char *exten; /*!< Extension name */
int matchcid; /*!< Match caller id ? */
const char *cidmatch; /*!< Caller id to match for this extension */
int priority; /*!< Priority */
const char *label; /*!< Label */
struct ast_context *parent; /*!< The context this extension belongs to */
const char *app; /*!< Application to execute */
struct ast_app *cached_app; /*!< Cached location of application */
void *data; /*!< Data to use (arguments) */
void (*datad)(void *); /*!< Data destructor */
struct ast_exten *peer; /*!< Next higher priority with our extension */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */
struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
const char *registrar; /*!< Registrar */
struct ast_exten *next; /*!< Extension with a greater ID */
char stuff[0];
};
/*! \brief ast_include: include= support in extensions.conf */
struct ast_include {
const char *name;
const char *rname; /*!< Context to include */
const char *registrar; /*!< Registrar */
int hastime; /*!< If time construct exists */
struct ast_timing timing; /*!< time construct */
struct ast_include *next; /*!< Link them together */
char stuff[0];
};
/*! \brief ast_sw: Switch statement in extensions.conf */
struct ast_sw {
char *name;
const char *registrar; /*!< Registrar */
char *data; /*!< Data load */
int eval;
AST_LIST_ENTRY(ast_sw) list;
char stuff[0];
};
/*! \brief ast_ignorepat: Ignore patterns in dial plan */
struct ast_ignorepat {
const char *registrar;
struct ast_ignorepat *next;
const char pattern[0];
};
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
struct match_char
{
int is_pattern; /* the pattern started with '_' */
int deleted; /* if this is set, then... don't return it */
int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
struct match_char *alt_char;
struct match_char *next_char;
struct ast_exten *exten; /* attached to last char of a pattern for exten */
char x[1]; /* the pattern itself-- matches a single char */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
};
struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
{
int total_specificity;
int total_length;
char last_char; /* set to ! or . if they are the end of the pattern */
int canmatch; /* if the string to match was just too short */
struct match_char *node;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct ast_exten *canmatch_exten;
struct ast_exten *exten;
};
/*! \brief ast_context: An extension context */
struct ast_context {
ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
struct ast_exten *root; /*!< The root of the list of extensions */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
struct ast_context *next; /*!< Link them together */
struct ast_include *includes; /*!< Include other contexts */
struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */
AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
char name[0]; /*!< Name of the context */
};
/*! \brief ast_app: A registered application */
struct ast_app {
int (*execute)(struct ast_channel *chan, const char *data);
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show applications' */
AST_STRING_FIELD(description); /*!< Description (help text) for 'show application &lt;name&gt;' */
AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show applications' */
AST_STRING_FIELD(arguments); /*!< Arguments description */
AST_STRING_FIELD(seealso); /*!< See also */
);
#ifdef AST_XML_DOCS
enum ast_doc_src docsrc; /*!< Where the documentation come from. */
#endif
AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
struct ast_module *module; /*!< Module this app belongs to */
char name[0]; /*!< Name of the application */
};
/*! \brief ast_state_cb: An extension state notify register item */
struct ast_state_cb {
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*! Watcher ID returned when registered. */
int id;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*! Arbitrary data passed for callbacks. */
void *data;
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
/*! Flag if this callback is an extended callback containing detailed device status */
int extended;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*! Callback when state changes. */
ast_state_cb_type change_cb;
/*! Callback when destroyed so any resources given by the registerer can be freed. */
ast_state_cb_destroy_type destroy_cb;
/*! \note Only used by ast_merge_contexts_and_delete */
AST_LIST_ENTRY(ast_state_cb) entry;
};
/*!
* \brief Structure for dial plan hints
*
* \note Hints are pointers from an extension in the dialplan to
* one or more devices (tech/name)
*
* See \ref AstExtState
*/
struct ast_hint {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \brief Hint extension
*
* \note
* Will never be NULL while the hint is in the hints container.
*/
struct ast_exten *exten;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
struct ao2_container *callbacks; /*!< Device state callback container for this extension */
/*! Dev state variables */
int laststate; /*!< Last known device state */
/*! Presence state variables */
int last_presence_state; /*!< Last known presence state */
char *last_presence_subtype; /*!< Last known presence subtype string */
char *last_presence_message; /*!< Last known presence message string */
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
};
#define HINTDEVICE_DATA_LENGTH 16
AST_THREADSTORAGE(hintdevice_data);
/* --- Hash tables of various objects --------*/
#ifdef LOW_MEMORY
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
#define HASH_EXTENHINT_SIZE 17
#else
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
#define HASH_EXTENHINT_SIZE 563
#endif
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*! \brief Container for hint devices */
static struct ao2_container *hintdevices;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \brief Structure for dial plan hint devices
* \note hintdevice is one device pointing to a hint.
*/
struct ast_hintdevice {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \brief Hint this hintdevice belongs to.
* \note Holds a reference to the hint object.
*/
struct ast_hint *hint;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*! Name of the hint device. */
char hintdevice[1];
};
/*!
* \note Using the device for hash
*/
static int hintdevice_hash_cb(const void *obj, const int flags)
{
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
const struct ast_hintdevice *ext;
const char *key;
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_KEY:
key = obj;
break;
case OBJ_SEARCH_OBJECT:
ext = obj;
key = ext->hintdevice;
break;
default:
ast_assert(0);
return 0;
}
return ast_str_case_hash(key);
}
/*!
* \note Devices on hints are not unique so no CMP_STOP is returned
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
* Dont use ao2_find against hintdevices container cause there always
* could be more than one result.
*/
static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
{
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
struct ast_hintdevice *left = obj;
struct ast_hintdevice *right = arg;
const char *right_key = arg;
int cmp;
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right->hintdevice;
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcasecmp(left->hintdevice, right_key);
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
break;
case OBJ_SEARCH_PARTIAL_KEY:
/*
* We could also use a partial key struct containing a length
* so strlen() does not get called for every comparison instead.
*/
cmp = strncmp(left->hintdevice, right_key, strlen(right_key));
break;
default:
ast_assert(0);
cmp = 0;
break;
}
return cmp ? 0 : CMP_MATCH;
}
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
/*! \internal \brief \c ao2_callback function to remove hintdevices */
static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
{
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
struct ast_hintdevice *candidate = obj;
char *device = arg;
struct ast_hint *hint = data;
if (!strcasecmp(candidate->hintdevice, device)
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
&& candidate->hint == hint) {
return CMP_MATCH;
}
return 0;
}
static int remove_hintdevice(struct ast_hint *hint)
{
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
while (AST_VECTOR_SIZE(&hint->devices) > 0) {
char *device = AST_VECTOR_GET(&hint->devices, 0);
ao2_t_callback_data(hintdevices, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA,
hintdevice_remove_cb, device, hint, "Remove device from container");
AST_VECTOR_REMOVE_UNORDERED(&hint->devices, 0);
ast_free(device);
}
return 0;
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
static char *parse_hint_device(struct ast_str *hint_args);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \internal
* \brief Destroy the given hintdevice object.
*
* \param obj Hint device to destroy.
*
* \return Nothing
*/
static void hintdevice_destroy(void *obj)
{
struct ast_hintdevice *doomed = obj;
if (doomed->hint) {
ao2_ref(doomed->hint, -1);
doomed->hint = NULL;
}
}
/*! \brief add hintdevice structure and link it into the container.
*/
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
{
struct ast_str *str;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
char *parse;
char *cur;
struct ast_hintdevice *device;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
int devicelength;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!hint || !devicelist) {
/* Trying to add garbage? Don't bother. */
return 0;
}
if (!(str = ast_str_thread_get(&hintdevice_data, 16))) {
return -1;
}
ast_str_set(&str, 0, "%s", devicelist);
parse = ast_str_buffer(str);
/* Spit on '&' and ',' to handle presence hints as well */
while ((cur = strsep(&parse, "&,"))) {
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
char *device_name;
devicelength = strlen(cur);
if (!devicelength) {
continue;
}
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
device_name = ast_strdup(cur);
if (!device_name) {
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
"allocating a hintdevice structure");
if (!device) {
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
ast_free(device_name);
return -1;
}
strcpy(device->hintdevice, cur);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_ref(hint, +1);
device->hint = hint;
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
ast_free(device_name);
ao2_ref(device, -1);
return -1;
}
ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
}
return 0;
}
static const struct cfextension_states {
int extension_state;
const char * const text;
} extension_states[] = {
{ AST_EXTENSION_NOT_INUSE, "Idle" },
{ AST_EXTENSION_INUSE, "InUse" },
{ AST_EXTENSION_BUSY, "Busy" },
{ AST_EXTENSION_UNAVAILABLE, "Unavailable" },
{ AST_EXTENSION_RINGING, "Ringing" },
{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
{ AST_EXTENSION_ONHOLD, "Hold" },
{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
};
struct pbx_exception {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(context); /*!< Context associated with this exception */
AST_STRING_FIELD(exten); /*!< Exten associated with this exception */
AST_STRING_FIELD(reason); /*!< The exception reason */
);
int priority; /*!< Priority associated with this exception */
};
static int pbx_builtin_answer(struct ast_channel *, const char *);
static int pbx_builtin_goto(struct ast_channel *, const char *);
static int pbx_builtin_hangup(struct ast_channel *, const char *);
static int pbx_builtin_background(struct ast_channel *, const char *);
static int pbx_builtin_wait(struct ast_channel *, const char *);
static int pbx_builtin_waitexten(struct ast_channel *, const char *);
static int pbx_builtin_incomplete(struct ast_channel *, const char *);
static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
static int pbx_builtin_ringing(struct ast_channel *, const char *);
static int pbx_builtin_proceeding(struct ast_channel *, const char *);
static int pbx_builtin_progress(struct ast_channel *, const char *);
static int pbx_builtin_congestion(struct ast_channel *, const char *);
static int pbx_builtin_busy(struct ast_channel *, const char *);
static int pbx_builtin_noop(struct ast_channel *, const char *);
static int pbx_builtin_gotoif(struct ast_channel *, const char *);
static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
static int pbx_builtin_execiftime(struct ast_channel *, const char *);
static int pbx_builtin_saynumber(struct ast_channel *, const char *);
static int pbx_builtin_saydigits(struct ast_channel *, const char *);
static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *);
static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
static int matchcid(const char *cidpattern, const char *callerid);
#ifdef NEED_DEBUG
static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
#endif
static int pbx_builtin_importvar(struct ast_channel *, const char *);
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
static void new_find_extension(const char *str, struct scoreboard *score,
struct match_char *tree, int length, int spec, const char *callerid,
const char *label, enum ext_match_t action);
static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
struct ast_exten *e1, int findonly);
static void create_match_char_tree(struct ast_context *con);
static struct ast_exten *get_canmatch_exten(struct match_char *node);
static void destroy_pattern_tree(struct match_char *pattern_tree);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
static unsigned int hashtab_hash_extens(const void *obj);
static unsigned int hashtab_hash_priority(const void *obj);
static unsigned int hashtab_hash_labels(const void *obj);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
static void __ast_internal_context_destroy( struct ast_context *con);
static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *), const char *registrar);
static int ast_add_extension2_lockopt(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
const char *registrar, int lock_context);
static struct ast_context *find_context_locked(const char *context);
static struct ast_context *find_context(const char *context);
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
static void get_device_state_causing_channels(struct ao2_container *c);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/*!
* \internal
* \brief Character array comparison function for qsort.
*
* \param a Left side object.
* \param b Right side object.
*
* \retval <0 if a < b
* \retval =0 if a = b
* \retval >0 if a > b
*/
static int compare_char(const void *a, const void *b)
{
const unsigned char *ac = a;
const unsigned char *bc = b;
return *ac - *bc;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/* labels, contexts are case sensitive priority numbers are ints */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
const struct ast_context *ac = ah_a;
const struct ast_context *bc = ah_b;
if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
return 1;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/* assume context names are registered in a string table! */
return strcmp(ac->name, bc->name);
}
static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
{
const struct ast_exten *ac = ah_a;
const struct ast_exten *bc = ah_b;
int x = strcmp(ac->exten, bc->exten);
if (x) { /* if exten names are diff, then return */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return x;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/* but if they are the same, do the cidmatch values match? */
/* not sure which side may be using ast_ext_matchcid_types, so check both */
if (ac->matchcid == AST_EXT_MATCHCID_ANY || bc->matchcid == AST_EXT_MATCHCID_ANY) {
return 0;
}
if (ac->matchcid == AST_EXT_MATCHCID_OFF && bc->matchcid == AST_EXT_MATCHCID_OFF) {
return 0;
}
if (ac->matchcid != bc->matchcid) {
return 1;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
/* all other cases already disposed of, match now required on callerid string (cidmatch) */
/* although ast_add_extension2_lockopt() enforces non-zero ptr, caller may not have */
if (ast_strlen_zero(ac->cidmatch) && ast_strlen_zero(bc->cidmatch)) {
return 0;
}
return strcmp(ac->cidmatch, bc->cidmatch);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
{
const struct ast_exten *ac = ah_a;
const struct ast_exten *bc = ah_b;
return ac->priority != bc->priority;
}
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
{
const struct ast_exten *ac = ah_a;
const struct ast_exten *bc = ah_b;
return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
unsigned int ast_hashtab_hash_contexts(const void *obj)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
const struct ast_context *ac = obj;
return ast_hashtab_hash_string(ac->name);
}
static unsigned int hashtab_hash_extens(const void *obj)
{
const struct ast_exten *ac = obj;
unsigned int x = ast_hashtab_hash_string(ac->exten);
unsigned int y = 0;
if (ac->matchcid == AST_EXT_MATCHCID_ON)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
y = ast_hashtab_hash_string(ac->cidmatch);
return x+y;
}
static unsigned int hashtab_hash_priority(const void *obj)
{
const struct ast_exten *ac = obj;
return ast_hashtab_hash_int(ac->priority);
}
static unsigned int hashtab_hash_labels(const void *obj)
{
const struct ast_exten *ac = obj;
return ast_hashtab_hash_string(S_OR(ac->label, ""));
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
AST_RWLOCK_DEFINE_STATIC(globalslock);
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
static int autofallthrough = 1;
static int extenpatternmatchnew = 0;
static char *overrideswitch = NULL;
/*! \brief Subscription for device state change events */
static struct stasis_subscription *device_state_sub;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
/*! \brief Subscription for presence state change events */
static struct stasis_subscription *presence_state_sub;
AST_MUTEX_DEFINE_STATIC(maxcalllock);
static int countcalls;
static int totalcalls;
/*!
* \brief Registered functions container.
*
* It is sorted by function name.
*/
static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
/*! \brief Declaration of builtin applications */
static struct pbx_builtin {
char name[AST_MAX_APP];
int (*execute)(struct ast_channel *chan, const char *data);
} builtins[] =
{
/* These applications are built into the PBX core and do not
need separate modules */
{ "Answer", pbx_builtin_answer },
{ "BackGround", pbx_builtin_background },
{ "Busy", pbx_builtin_busy },
{ "Congestion", pbx_builtin_congestion },
{ "ExecIfTime", pbx_builtin_execiftime },
{ "Goto", pbx_builtin_goto },
{ "GotoIf", pbx_builtin_gotoif },
{ "GotoIfTime", pbx_builtin_gotoiftime },
{ "ImportVar", pbx_builtin_importvar },
{ "Hangup", pbx_builtin_hangup },
{ "Incomplete", pbx_builtin_incomplete },
{ "NoOp", pbx_builtin_noop },
{ "Proceeding", pbx_builtin_proceeding },
{ "Progress", pbx_builtin_progress },
{ "RaiseException", pbx_builtin_raise_exception },
{ "Ringing", pbx_builtin_ringing },
{ "SayAlpha", pbx_builtin_saycharacters },
{ "SayAlphaCase", pbx_builtin_saycharacters_case },
{ "SayDigits", pbx_builtin_saydigits },
{ "SayNumber", pbx_builtin_saynumber },
{ "SayPhonetic", pbx_builtin_sayphonetic },
{ "Set", pbx_builtin_setvar },
{ "MSet", pbx_builtin_setvar_multiple },
{ "SetAMAFlags", pbx_builtin_setamaflags },
{ "Wait", pbx_builtin_wait },
{ "WaitExten", pbx_builtin_waitexten }
};
static struct ast_context *contexts;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
static struct ast_hashtab *contexts_table = NULL;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/*!
* \brief Lock for the ast_context list
* \note
* This lock MUST be recursive, or a deadlock on reload may result. See
* https://issues.asterisk.org/view.php?id=17643
*/
AST_MUTEX_DEFINE_STATIC(conlock);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \brief Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
*/
AST_MUTEX_DEFINE_STATIC(context_merge_lock);
/*!
* \brief Registered applications container.
*
* It is sorted by application name.
*/
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
static int stateid = 1;
/*!
* \note When holding this container's lock, do _not_ do
* anything that will cause conlock to be taken, unless you
* _already_ hold it. The ast_merge_contexts_and_delete function
* will take the locks in conlock/hints order, so any other
* paths that require both locks must also take them in that
* order.
*/
static struct ao2_container *hints;
static struct ao2_container *statecbs;
#ifdef CONTEXT_DEBUG
/* these routines are provided for doing run-time checks
on the extension structures, in case you are having
problems, this routine might help you localize where
the problem is occurring. It's kinda like a debug memory
allocator's arena checker... It'll eat up your cpu cycles!
but you'll see, if you call it in the right places,
right where your problems began...
*/
/* you can break on the check_contexts_trouble()
routine in your debugger to stop at the moment
there's a problem */
void check_contexts_trouble(void);
void check_contexts_trouble(void)
{
int x = 1;
x = 2;
}
int check_contexts(char *, int);
int check_contexts(char *file, int line )
{
struct ast_hashtab_iter *t1;
struct ast_context *c1, *c2;
int found = 0;
struct ast_exten *e1, *e2, *e3;
struct ast_exten ex;
/* try to find inconsistencies */
/* is every context in the context table in the context list and vice-versa ? */
if (!contexts_table) {
ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
usleep(500000);
}
t1 = ast_hashtab_start_traversal(contexts_table);
while( (c1 = ast_hashtab_next(t1))) {
for(c2=contexts;c2;c2=c2->next) {
if (!strcmp(c1->name, c2->name)) {
found = 1;
break;
}
}
if (!found) {
ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
check_contexts_trouble();
}
}
ast_hashtab_end_traversal(t1);
for(c2=contexts;c2;c2=c2->next) {
c1 = find_context_locked(c2->name);
if (!c1) {
ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
check_contexts_trouble();
} else
ast_unlock_contexts();
}
/* loop thru all contexts, and verify the exten structure compares to the
hashtab structure */
for(c2=contexts;c2;c2=c2->next) {
c1 = find_context_locked(c2->name);
if (c1) {
ast_unlock_contexts();
/* is every entry in the root list also in the root_table? */
for(e1 = c1->root; e1; e1=e1->next)
{
char dummy_name[1024];
ex.exten = dummy_name;
ex.matchcid = e1->matchcid;
ex.cidmatch = e1->cidmatch;
ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
e2 = ast_hashtab_lookup(c1->root_table, &ex);
if (!e2) {
if (e1->matchcid == AST_EXT_MATCHCID_ON) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
} else {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
}
check_contexts_trouble();
}
}
/* is every entry in the root_table also in the root list? */
if (!c2->root_table) {
if (c2->root) {
ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
usleep(500000);
}
} else {
t1 = ast_hashtab_start_traversal(c2->root_table);
while( (e2 = ast_hashtab_next(t1)) ) {
for(e1=c2->root;e1;e1=e1->next) {
if (!strcmp(e1->exten, e2->exten)) {
found = 1;
break;
}
}
if (!found) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
check_contexts_trouble();
}
}
ast_hashtab_end_traversal(t1);
}
}
/* is every priority reflected in the peer_table at the head of the list? */
/* is every entry in the root list also in the root_table? */
/* are the per-extension peer_tables in the right place? */
for(e1 = c2->root; e1; e1 = e1->next) {
for(e2=e1;e2;e2=e2->peer) {
ex.priority = e2->priority;
if (e2 != e1 && e2->peer_table) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
if (e2 != e1 && e2->peer_label_table) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
if (e2 == e1 && !e2->peer_table){
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
if (e2 == e1 && !e2->peer_label_table) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
e3 = ast_hashtab_lookup(e1->peer_table, &ex);
if (!e3) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
}
if (!e1->peer_table){
ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
usleep(500000);
}
/* is every entry in the peer_table also in the peer list? */
t1 = ast_hashtab_start_traversal(e1->peer_table);
while( (e2 = ast_hashtab_next(t1)) ) {
for(e3=e1;e3;e3=e3->peer) {
if (e3->priority == e2->priority) {
found = 1;
break;
}
}
if (!found) {
ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
check_contexts_trouble();
}
}
ast_hashtab_end_traversal(t1);
}
}
return 0;
}
#endif
/*
\note This function is special. It saves the stack so that no matter
how many times it is called, it returns to the same place */
int pbx_exec(struct ast_channel *c, /*!< Channel */
struct ast_app *app, /*!< Application */
const char *data) /*!< Data for execution */
{
int res;
struct ast_module_user *u = NULL;
const char *saved_c_appl;
const char *saved_c_data;
/* save channel values */
saved_c_appl= ast_channel_appl(c);
saved_c_data= ast_channel_data(c);
ast_channel_lock(c);
ast_channel_appl_set(c, app->name);
ast_channel_data_set(c, data);
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_channel_publish_snapshot(c);
ast_channel_unlock(c);
if (app->module)
u = __ast_module_user_add(app->module, c);
res = app->execute(c, S_OR(data, ""));
if (app->module && u)
__ast_module_user_remove(app->module, u);
/* restore channel values */
ast_channel_appl_set(c, saved_c_appl);
ast_channel_data_set(c, saved_c_data);
return res;
}
static struct ast_app *pbx_findapp_nolock(const char *name)
{
struct ast_app *cur;
int cmp;
AST_RWLIST_TRAVERSE(&apps, cur, list) {
cmp = strcasecmp(name, cur->name);
if (cmp > 0) {
continue;
}
if (!cmp) {
/* Found it. */
break;
}
/* Not in container. */
cur = NULL;
break;
}
return cur;
}
struct ast_app *pbx_findapp(const char *app)
{
struct ast_app *ret;
AST_RWLIST_RDLOCK(&apps);
ret = pbx_findapp_nolock(app);
AST_RWLIST_UNLOCK(&apps);
return ret;
}
static struct ast_switch *pbx_findswitch(const char *sw)
{
struct ast_switch *asw;
AST_RWLIST_RDLOCK(&switches);
AST_RWLIST_TRAVERSE(&switches, asw, list) {
if (!strcasecmp(asw->name, sw))
break;
}
AST_RWLIST_UNLOCK(&switches);
return asw;
}
static inline int include_valid(struct ast_include *i)
{
if (!i->hastime)
return 1;
return ast_check_timing(&(i->timing));
}
static void pbx_destroy(struct ast_pbx *p)
{
ast_free(p);
}
/* form a tree that fully describes all the patterns in a context's extensions
* in this tree, a "node" represents an individual character or character set
* meant to match the corresponding character in a dial string. The tree
* consists of a series of match_char structs linked in a chain
* via the alt_char pointers. More than one pattern can share the same parts of the
* tree as other extensions with the same pattern to that point.
* My first attempt to duplicate the finding of the 'best' pattern was flawed in that
* I misunderstood the general algorithm. I thought that the 'best' pattern
* was the one with lowest total score. This was not true. Thus, if you have
* patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
* the "best" match because it has fewer X's, and is therefore more specific,
* but this is not how the old algorithm works. It sorts matching patterns
* in a similar collating sequence as sorting alphabetic strings, from left to
* right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
* because "1" is more specific than "X".
* So, to accomodate this philosophy, I sort the tree branches along the alt_char
* line so they are lowest to highest in specificity numbers. This way, as soon
* as we encounter our first complete match, we automatically have the "best"
* match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
* If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
* they are welcome to revert pbx to before 1 Apr 2008.
* As an example, consider these 4 extensions:
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* (a) NXXNXXXXXX
* (b) 307754XXXX
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* (c) fax
* (d) NXXXXXXXXX
*
* In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
* most numbers. For all numbers beginning with 307754, (b) should always win.
*
* These pattern should form a (sorted) tree that looks like this:
* { "3" } --next--> { "0" } --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
* |
* |alt
* |
* { "f" } --next--> { "a" } --next--> { "x" exten_match: (c) }
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* { "N" } --next--> { "X" } --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
* | |
* | |alt
* |alt |
* | { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
* |
* NULL
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
* In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
* fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
* traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern, it calls itself
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
* We pass a pointer to a scoreboard down through, also.
* The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
* The first complete match ends the traversal, which should make this version of the pattern matcher faster
* the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
* these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
* according to the sort criteria.
* Hope the limit on stack depth won't be a problem... this routine should
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
*
* In the above example, with the number "3077549999" as the pattern, the traversor could match extensions a, b and d. All are
* of length 10; they have total specificities of 24580, 10246, and 25090, respectively, not that this matters
* at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
* left the specificity totals in the code as an artifact; at some point, I will strip it out.
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
* Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
* because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
* can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
* more times faster in extreme cases.
*
* MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
* can have patterns in your CID field as well.
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*
* */
static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
/* if this extension is marked as deleted, then skip this -- if it never shows
on the scoreboard, it will never be found, nor will halt the traversal. */
if (deleted)
return;
board->total_specificity = spec;
board->total_length = length;
board->exten = exten;
board->last_char = last;
board->node = node;
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
#endif
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
#ifdef NEED_DEBUG
static void log_match_char_tree(struct match_char *node, char *prefix)
{
char extenstr[40];
struct ast_str *my_prefix = ast_str_alloca(1024);
extenstr[0] = '\0';
if (node && node->exten)
snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
if (strlen(node->x) > 1) {
ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
node->exten ? node->exten->exten : "", extenstr);
} else {
ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
node->exten ? node->exten->exten : "", extenstr);
}
ast_str_set(&my_prefix, 0, "%s+ ", prefix);
if (node->next_char)
log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
if (node->alt_char)
log_match_char_tree(node->alt_char, prefix);
}
#endif
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
{
char extenstr[40];
struct ast_str *my_prefix = ast_str_alloca(1024);
extenstr[0] = '\0';
if (node->exten) {
snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
}
if (strlen(node->x) > 1) {
ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
node->exten ? node->exten->exten : "", extenstr);
} else {
ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
node->exten ? node->exten->exten : "", extenstr);
}
ast_str_set(&my_prefix, 0, "%s+ ", prefix);
if (node->next_char)
cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
if (node->alt_char)
cli_match_char_tree(node->alt_char, prefix, fd);
}
static struct ast_exten *get_canmatch_exten(struct match_char *node)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
/* find the exten at the end of the rope */
struct match_char *node2 = node;
for (node2 = node; node2; node2 = node2->next_char) {
if (node2->exten) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
#endif
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return node2->exten;
}
}
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
#endif
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return 0;
}
static struct ast_exten *trie_find_next_match(struct match_char *node)
{
struct match_char *m3;
struct match_char *m4;
struct ast_exten *e3;
if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
return node->exten;
}
if (node && node->x[0] == '!' && !node->x[1]) {
return node->exten;
}
if (!node || !node->next_char) {
return NULL;
}
m3 = node->next_char;
if (m3->exten) {
return m3->exten;
}
for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
if (m4->exten) {
return m4->exten;
}
}
for (m4 = m3; m4; m4 = m4->alt_char) {
e3 = trie_find_next_match(m3);
if (e3) {
return e3;
}
}
return NULL;
}
#ifdef DEBUG_THIS
static char *action2str(enum ext_match_t action)
{
switch (action) {
case E_MATCH:
return "MATCH";
case E_CANMATCH:
return "CANMATCH";
case E_MATCHMORE:
return "MATCHMORE";
case E_FINDLABEL:
return "FINDLABEL";
case E_SPAWN:
return "SPAWN";
default:
return "?ACTION?";
}
}
#endif
static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
struct match_char *p; /* note minimal stack storage requirements */
struct ast_exten pattern = { .label = label };
#ifdef DEBUG_THIS
if (tree)
ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
else
ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
#endif
for (p = tree; p; p = p->alt_char) {
if (p->is_pattern) {
if (p->x[0] == 'N') {
if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
#define NEW_MATCHER_CHK_MATCH \
if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */ \
if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */ \
update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
if (!p->deleted) { \
if (action == E_FINDLABEL) { \
if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
ast_debug(4, "Found label in preferred extension\n"); \
return; \
} \
} else { \
ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \
return; /* the first match, by definition, will be the best, because of the sorted tree */ \
} \
} \
} \
}
#define NEW_MATCHER_RECURSE \
if (p->next_char && (*(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
|| p->next_char->x[0] == '!')) { \
if (*(str + 1) || p->next_char->x[0] == '!') { \
new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
if (score->exten) { \
ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \
return; /* the first match is all we need */ \
} \
} else { \
new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
"NULL"); \
return; /* the first match is all we need */ \
} \
} \
} else if ((p->next_char || action == E_CANMATCH) && !*(str + 1)) { \
score->canmatch = 1; \
score->canmatch_exten = get_canmatch_exten(p); \
if (action == E_CANMATCH || action == E_MATCHMORE) { \
ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
return; \
} \
}
NEW_MATCHER_CHK_MATCH;
NEW_MATCHER_RECURSE;
}
} else if (p->x[0] == 'Z') {
if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
NEW_MATCHER_CHK_MATCH;
NEW_MATCHER_RECURSE;
}
} else if (p->x[0] == 'X') {
if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
NEW_MATCHER_CHK_MATCH;
NEW_MATCHER_RECURSE;
}
} else if (p->x[0] == '.' && p->x[1] == 0) {
/* how many chars will the . match against? */
int i = 0;
const char *str2 = str;
while (*str2 && *str2 != '/') {
str2++;
i++;
}
if (p->exten && *str2 != '/') {
update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
if (score->exten) {
ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
return; /* the first match is all we need */
}
}
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
return; /* the first match is all we need */
}
}
} else if (p->x[0] == '!' && p->x[1] == 0) {
/* how many chars will the . match against? */
int i = 1;
const char *str2 = str;
while (*str2 && *str2 != '/') {
str2++;
i++;
}
if (p->exten && *str2 != '/') {
update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
if (score->exten) {
ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
return; /* the first match is all we need */
}
}
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
return; /* the first match is all we need */
}
}
} else if (p->x[0] == '/' && p->x[1] == 0) {
/* the pattern in the tree includes the cid match! */
if (p->next_char && callerid && *callerid) {
new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
return; /* the first match is all we need */
}
}
} else if (strchr(p->x, *str)) {
ast_debug(4, "Nothing strange about this match\n");
NEW_MATCHER_CHK_MATCH;
NEW_MATCHER_RECURSE;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
} else if (strchr(p->x, *str)) {
ast_debug(4, "Nothing strange about this match\n");
NEW_MATCHER_CHK_MATCH;
NEW_MATCHER_RECURSE;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
}
ast_debug(4, "return at end of func\n");
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
/* the algorithm for forming the extension pattern tree is also a bit simple; you
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* traverse all the extensions in a context, and for each char of the extension,
* you see if it exists in the tree; if it doesn't, you add it at the appropriate
* spot. What more can I say? At the end of each exten, you cap it off by adding the
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* address of the extension involved. Duplicate patterns will be complained about.
*
* Ideally, this would be done for each context after it is created and fully
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
* filled. It could be done as a finishing step after extensions.conf or .ael is
* loaded, or it could be done when the first search is encountered. It should only
* have to be done once, until the next unload or reload.
*
* I guess forming this pattern tree would be analogous to compiling a regex. Except
* that a regex only handles 1 pattern, really. This trie holds any number
* of patterns. Well, really, it **could** be considered a single pattern,
* where the "|" (or) operator is allowed, I guess, in a way, sort of...
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*/
static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
struct match_char *t;
if (!current) {
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return 0;
}
for (t = current; t; t = t->alt_char) {
if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return t;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return 0;
}
/* The first arg is the location of the tree ptr, or the
address of the next_char ptr in the node, so we can mess
with it, if we need to insert at the beginning of the list */
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
{
struct match_char *curr, *lcurr;
/* insert node into the tree at "current", so the alt_char list from current is
sorted in increasing value as you go to the leaves */
if (!(*parent_ptr)) {
*parent_ptr = node;
return;
}
if ((*parent_ptr)->specificity > node->specificity) {
/* insert at head */
node->alt_char = (*parent_ptr);
*parent_ptr = node;
return;
}
lcurr = *parent_ptr;
for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
if (curr->specificity > node->specificity) {
node->alt_char = curr;
lcurr->alt_char = node;
break;
}
lcurr = curr;
}
if (!curr) {
lcurr->alt_char = node;
}
}
struct pattern_node {
/*! Pattern node specificity */
int specif;
/*! Pattern node match characters. */
char buf[256];
};
static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
struct match_char *m;
if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
return NULL;
}
/* strcpy is safe here since we know its size and have allocated
* just enough space for when we allocated m
*/
strcpy(m->x, pattern->buf);
/* the specificity scores are the same as used in the old
pattern matcher. */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
m->is_pattern = is_pattern;
if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
m->specificity = 0x0832;
} else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
m->specificity = 0x0931;
} else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
m->specificity = 0x0a30;
} else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
m->specificity = 0x18000;
} else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
m->specificity = 0x28000;
} else {
m->specificity = pattern->specif;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (!con->pattern_tree) {
insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
if (already) { /* switch to the new regime (traversing vs appending)*/
insert_in_next_chars_alt_char_list(nextcharptr, m);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
insert_in_next_chars_alt_char_list(&current->next_char, m);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return m;
}
/*!
* \internal
* \brief Extract the next exten pattern node.
*
* \param node Pattern node to fill.
* \param src Next source character to read.
* \param pattern TRUE if the exten is a pattern.
* \param extenbuf Original exten buffer to use in diagnostic messages.
*
* \retval Ptr to next extenbuf pos to read.
*/
static const char *get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
#define INC_DST_OVERFLOW_CHECK \
do { \
if (dst - node->buf < sizeof(node->buf) - 1) { \
++dst; \
} else { \
overflow = 1; \
} \
} while (0)
node->specif = 0;
node->buf[0] = '\0';
while (*src) {
if (*src == '[' && pattern) {
char *dst = node->buf;
const char *src_next;
int length;
int overflow = 0;
/* get past the '[' */
++src;
for (;;) {
if (*src == '\\') {
/* Escaped character. */
++src;
if (*src == '[' || *src == '\\' || *src == '-' || *src == ']') {
*dst = *src++;
INC_DST_OVERFLOW_CHECK;
}
} else if (*src == '-') {
unsigned char first;
unsigned char last;
src_next = src;
first = *(src_next - 1);
last = *++src_next;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (last == '\\') {
/* Escaped character. */
last = *++src_next;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
/* Possible char range. */
if (node->buf[0] && last) {
/* Expand the char range. */
while (++first <= last) {
*dst = first;
INC_DST_OVERFLOW_CHECK;
}
src = src_next + 1;
} else {
/*
* There was no left or right char for the range.
* It is just a '-'.
*/
*dst = *src++;
INC_DST_OVERFLOW_CHECK;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
} else if (*src == '\0') {
ast_log(LOG_WARNING,
"A matching ']' was not found for '[' in exten pattern '%s'\n",
extenbuf);
break;
} else if (*src == ']') {
++src;
break;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
*dst = *src++;
INC_DST_OVERFLOW_CHECK;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
}
/* null terminate the exploded range */
*dst = '\0';
if (overflow) {
ast_log(LOG_ERROR,
"Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
extenbuf);
node->buf[0] = '\0';
continue;
}
/* Sort the characters in character set. */
length = strlen(node->buf);
if (!length) {
ast_log(LOG_WARNING, "Empty character set in exten pattern '%s'. Ignoring.\n",
extenbuf);
node->buf[0] = '\0';
continue;
}
qsort(node->buf, length, 1, compare_char);
/* Remove duplicate characters from character set. */
dst = node->buf;
src_next = node->buf;
while (*src_next++) {
if (*dst != *src_next) {
*++dst = *src_next;
}
}
length = strlen(node->buf);
length <<= 8;
node->specif = length | (unsigned char) node->buf[0];
break;
} else if (*src == '-') {
/* Skip dashes in all extensions. */
++src;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
if (*src == '\\') {
/*
* XXX The escape character here does not remove any special
* meaning to characters except the '[', '\\', and '-'
* characters since they are special only in this function.
*/
node->buf[0] = *++src;
if (!node->buf[0]) {
break;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
node->buf[0] = *src;
if (pattern) {
/* make sure n,x,z patterns are canonicalized to N,X,Z */
if (node->buf[0] == 'n') {
node->buf[0] = 'N';
} else if (node->buf[0] == 'x') {
node->buf[0] = 'X';
} else if (node->buf[0] == 'z') {
node->buf[0] = 'Z';
}
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
node->buf[1] = '\0';
node->specif = 1;
++src;
break;
}
}
return src;
#undef INC_DST_OVERFLOW_CHECK
}
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
{
struct match_char *m1 = NULL;
struct match_char *m2 = NULL;
struct match_char **m0;
const char *pos;
int already;
int pattern = 0;
int idx_cur;
int idx_next;
char extenbuf[512];
struct pattern_node pat_node[2];
if (e1->matchcid) {
if (sizeof(extenbuf) < strlen(e1->exten) + strlen(e1->cidmatch) + 2) {
ast_log(LOG_ERROR,
"The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
e1->exten, e1->cidmatch);
return NULL;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);/* Safe. We just checked. */
} else {
ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
}
#ifdef NEED_DEBUG
ast_debug(1, "Adding exten %s to tree\n", extenbuf);
#endif
m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
m0 = &con->pattern_tree;
already = 1;
pos = extenbuf;
if (*pos == '_') {
pattern = 1;
++pos;
}
idx_cur = 0;
pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
/* See about adding node to tree. */
m2 = NULL;
if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
&& m2->next_char) {
if (!pat_node[idx_next].buf[0]) {
/*
* This is the end of the pattern, but not the end of the tree.
* Mark this node with the exten... a shorter pattern might win
* if the longer one doesn't match.
*/
if (findonly) {
return m2;
}
if (m2->exten) {
ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
}
m2->exten = e1;
m2->deleted = 0;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
m1 = m2->next_char; /* m1 points to the node to compare against */
m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
} else { /* not already OR not m2 OR nor m2->next_char */
if (m2) {
if (findonly) {
return m2;
}
m1 = m2; /* while m0 stays the same */
} else {
if (findonly) {
return m1;
}
m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
if (!m1) { /* m1 is the node just added */
return NULL;
}
m0 = &m1->next_char;
}
if (!pat_node[idx_next].buf[0]) {
if (m2 && m2->exten) {
ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
}
m1->deleted = 0;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
m1->exten = e1;
}
/* The 'already' variable is a mini-optimization designed to make it so that we
* don't have to call already_in_tree when we know it will return false.
*/
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
already = 0;
}
}
return m1;
}
static void create_match_char_tree(struct ast_context *con)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
struct ast_hashtab_iter *t1;
struct ast_exten *e1;
#ifdef NEED_DEBUG
int biggest_bucket, resizes, numobjs, numbucks;
ast_debug(1, "Creating Extension Trie for context %s(%p)\n", con->name, con);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
ast_debug(1, "This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
numobjs, numbucks, biggest_bucket, resizes);
#endif
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
t1 = ast_hashtab_start_traversal(con->root_table);
while ((e1 = ast_hashtab_next(t1))) {
if (e1->exten) {
add_exten_to_pattern_tree(con, e1, 0);
} else {
ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
ast_hashtab_end_traversal(t1);
}
static void destroy_pattern_tree(struct match_char *pattern_tree) /* pattern tree is a simple binary tree, sort of, so the proper way to destroy it is... recursively! */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
/* destroy all the alternates */
if (pattern_tree->alt_char) {
destroy_pattern_tree(pattern_tree->alt_char);
pattern_tree->alt_char = 0;
}
/* destroy all the nexts */
if (pattern_tree->next_char) {
destroy_pattern_tree(pattern_tree->next_char);
pattern_tree->next_char = 0;
}
pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
ast_free(pattern_tree);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
/*!
* \internal
* \brief Get the length of the exten string.
*
* \param str Exten to get length.
*
* \retval strlen of exten.
*/
static int ext_cmp_exten_strlen(const char *str)
{
int len;
len = 0;
for (;;) {
/* Ignore '-' chars as eye candy fluff. */
while (*str == '-') {
++str;
}
if (!*str) {
break;
}
++str;
++len;
}
return len;
}
/*!
* \internal
* \brief Partial comparison of non-pattern extens.
*
* \param left Exten to compare.
* \param right Exten to compare. Also matches if this string ends first.
*
* \retval <0 if left < right
* \retval =0 if left == right
* \retval >0 if left > right
*/
static int ext_cmp_exten_partial(const char *left, const char *right)
{
int cmp;
for (;;) {
/* Ignore '-' chars as eye candy fluff. */
while (*left == '-') {
++left;
}
while (*right == '-') {
++right;
}
if (!*right) {
/*
* Right ended first for partial match or both ended at the same
* time for a match.
*/
cmp = 0;
break;
}
cmp = *left - *right;
if (cmp) {
break;
}
++left;
++right;
}
return cmp;
}
/*!
* \internal
* \brief Comparison of non-pattern extens.
*
* \param left Exten to compare.
* \param right Exten to compare.
*
* \retval <0 if left < right
* \retval =0 if left == right
* \retval >0 if left > right
*/
static int ext_cmp_exten(const char *left, const char *right)
{
int cmp;
for (;;) {
/* Ignore '-' chars as eye candy fluff. */
while (*left == '-') {
++left;
}
while (*right == '-') {
++right;
}
cmp = *left - *right;
if (cmp) {
break;
}
if (!*left) {
/*
* Get here only if both strings ended at the same time. cmp
* would be non-zero if only one string ended.
*/
break;
}
++left;
++right;
}
return cmp;
}
/*
* Special characters used in patterns:
* '_' underscore is the leading character of a pattern.
* In other position it is treated as a regular char.
* '-' The '-' is a separator and ignored. Why? So patterns like NXX-XXX-XXXX work.
* . one or more of any character. Only allowed at the end of
* a pattern.
* ! zero or more of anything. Also impacts the result of CANMATCH
* and MATCHMORE. Only allowed at the end of a pattern.
* In the core routine, ! causes a match with a return code of 2.
* In turn, depending on the search mode: (XXX check if it is implemented)
* - E_MATCH retuns 1 (does match)
* - E_MATCHMORE returns 0 (no match)
* - E_CANMATCH returns 1 (does match)
*
* / should not appear as it is considered the separator of the CID info.
* XXX at the moment we may stop on this char.
*
* X Z N match ranges 0-9, 1-9, 2-9 respectively.
* [ denotes the start of a set of character. Everything inside
* is considered literally. We can have ranges a-d and individual
* characters. A '[' and '-' can be considered literally if they
* are just before ']'.
* XXX currently there is no way to specify ']' in a range, nor \ is
* considered specially.
*
* When we compare a pattern with a specific extension, all characters in the extension
* itself are considered literally.
* XXX do we want to consider space as a separator as well ?
* XXX do we want to consider the separators in non-patterns as well ?
*/
/*!
* \brief helper functions to sort extension patterns in the desired way,
* so that more specific patterns appear first.
*
* \details
* The function compares individual characters (or sets of), returning
* an int where bits 0-7 are the ASCII code of the first char in the set,
* bits 8-15 are the number of characters in the set, and bits 16-20 are
* for special cases.
* This way more specific patterns (smaller character sets) appear first.
* Wildcards have a special value, so that we can directly compare them to
* sets by subtracting the two values. In particular:
* 0x001xx one character, character set starting with xx
* 0x0yyxx yy characters, character set starting with xx
* 0x18000 '.' (one or more of anything)
* 0x28000 '!' (zero or more of anything)
* 0x30000 NUL (end of string)
* 0x40000 error in set.
* The pointer to the string is advanced according to needs.
* NOTES:
* 1. the empty set is ignored.
* 2. given that a full set has always 0 as the first element,
* we could encode the special cases as 0xffXX where XX
* is 1, 2, 3, 4 as used above.
*/
static int ext_cmp_pattern_pos(const char **p, unsigned char *bitwise)
{
#define BITS_PER 8 /* Number of bits per unit (byte). */
unsigned char c;
unsigned char cmin;
int count;
const char *end;
do {
/* Get character and advance. (Ignore '-' chars as eye candy fluff.) */
do {
c = *(*p)++;
} while (c == '-');
/* always return unless we have a set of chars */
switch (c) {
default:
/* ordinary character */
bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
return 0x0100 | c;
case 'n':
case 'N':
/* 2..9 */
bitwise[6] = 0x3f;
bitwise[7] = 0xc0;
return 0x0800 | '2';
case 'x':
case 'X':
/* 0..9 */
bitwise[6] = 0xff;
bitwise[7] = 0xc0;
return 0x0A00 | '0';
case 'z':
case 'Z':
/* 1..9 */
bitwise[6] = 0x7f;
bitwise[7] = 0xc0;
return 0x0900 | '1';
case '.':
/* wildcard */
return 0x18000;
case '!':
/* earlymatch */
return 0x28000; /* less specific than '.' */
case '\0':
/* empty string */
*p = NULL;
return 0x30000;
case '[':
/* char set */
break;
}
/* locate end of set */
end = strchr(*p, ']');
if (!end) {
ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
return 0x40000; /* XXX make this entry go last... */
}
count = 0;
cmin = 0xFF;
for (; *p < end; ++*p) {
unsigned char c1; /* first char in range */
unsigned char c2; /* last char in range */
c1 = (*p)[0];
if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
c2 = (*p)[2];
*p += 2; /* skip a total of 3 chars */
} else { /* individual character */
c2 = c1;
}
if (c1 < cmin) {
cmin = c1;
}
for (; c1 <= c2; ++c1) {
unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
/*
* Note: If two character sets score the same, the one with the
* lowest ASCII values will compare as coming first. Must fill
* in most significant bits for lower ASCII values to accomplish
* the desired sort order.
*/
if (!(bitwise[c1 / BITS_PER] & mask)) {
/* Add the character to the set. */
bitwise[c1 / BITS_PER] |= mask;
count += 0x100;
}
}
}
++*p;
} while (!count);/* While the char set was empty. */
return count | cmin;
}
/*!
* \internal
* \brief Comparison of exten patterns.
*
* \param left Pattern to compare.
* \param right Pattern to compare.
*
* \retval <0 if left < right
* \retval =0 if left == right
* \retval >0 if left > right
*/
static int ext_cmp_pattern(const char *left, const char *right)
{
int cmp;
int left_pos;
int right_pos;
for (;;) {
unsigned char left_bitwise[32] = { 0, };
unsigned char right_bitwise[32] = { 0, };
left_pos = ext_cmp_pattern_pos(&left, left_bitwise);
right_pos = ext_cmp_pattern_pos(&right, right_bitwise);
cmp = left_pos - right_pos;
if (!cmp) {
/*
* Are the character sets different, even though they score the same?
*
* Note: Must swap left and right to get the sense of the
* comparison correct. Otherwise, we would need to multiply by
* -1 instead.
*/
cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
}
if (cmp) {
break;
}
if (!left) {
/*
* Get here only if both patterns ended at the same time. cmp
* would be non-zero if only one pattern ended.
*/
break;
}
}
return cmp;
}
/*!
* \internal
* \brief Comparison of dialplan extens for sorting purposes.
*
* \param left Exten/pattern to compare.
* \param right Exten/pattern to compare.
*
* \retval <0 if left < right
* \retval =0 if left == right
* \retval >0 if left > right
*/
static int ext_cmp(const char *left, const char *right)
{
/* Make sure non-pattern extens come first. */
if (left[0] != '_') {
if (right[0] == '_') {
return -1;
}
/* Compare two non-pattern extens. */
return ext_cmp_exten(left, right);
}
if (right[0] != '_') {
return 1;
}
/*
* OK, we need full pattern sorting routine.
*
* Skip past the underscores
*/
return ext_cmp_pattern(left + 1, right + 1);
}
int ast_extension_cmp(const char *a, const char *b)
{
int cmp;
cmp = ext_cmp(a, b);
if (cmp < 0) {
return -1;
}
if (cmp > 0) {
return 1;
}
return 0;
}
/*!
* \internal
* \brief used ast_extension_{match|close}
* mode is as follows:
* E_MATCH success only on exact match
* E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
* E_CANMATCH either of the above.
* \retval 0 on no-match
* \retval 1 on match
* \retval 2 on early match.
*/
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
{
mode &= E_MATCH_MASK; /* only consider the relevant bits */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
#endif
if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
int lp = ext_cmp_exten_strlen(pattern);
int ld = ext_cmp_exten_strlen(data);
if (lp < ld) { /* pattern too short, cannot match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
#endif
return 0;
}
/* depending on the mode, accept full or partial match or both */
if (mode == E_MATCH) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
#endif
return !ext_cmp_exten(pattern, data); /* 1 on match, 0 on fail */
}
if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) { /* partial or full match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
#endif
return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
} else {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
#endif
return 0;
}
}
if (mode == E_MATCH && data[0] == '_') {
/*
* XXX It is bad design that we don't know if we should be
* comparing data and pattern as patterns or comparing data if
* it conforms to pattern when the function is called. First,
* assume they are both patterns. If they don't match then try
* to see if data conforms to the given pattern.
*
* note: if this test is left out, then _x. will not match _x. !!!
*/
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
#endif
if (!ext_cmp_pattern(pattern + 1, data + 1)) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
#endif
return 1;
}
}
++pattern; /* skip leading _ */
/*
* XXX below we stop at '/' which is a separator for the CID info. However we should
* not store '/' in the pattern at all. When we insure it, we can remove the checks.
*/
for (;;) {
const char *end;
/* Ignore '-' chars as eye candy fluff. */
while (*data == '-') {
++data;
}
while (*pattern == '-') {
++pattern;
}
if (!*data || !*pattern || *pattern == '/') {
break;
}
switch (*pattern) {
case '[': /* a range */
++pattern;
end = strchr(pattern, ']'); /* XXX should deal with escapes ? */
if (!end) {
ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
return 0; /* unconditional failure */
}
if (pattern == end) {
/* Ignore empty character sets. */
++pattern;
continue;
}
for (; pattern < end; ++pattern) {
if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
if (*data >= pattern[0] && *data <= pattern[2])
break; /* match found */
else {
pattern += 2; /* skip a total of 3 chars */
continue;
}
} else if (*data == pattern[0])
break; /* match found */
}
if (pattern >= end) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) when pattern>=end\n");
#endif
return 0;
}
pattern = end; /* skip and continue */
break;
case 'n':
case 'N':
if (*data < '2' || *data > '9') {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) N is not matched\n");
#endif
return 0;
}
break;
case 'x':
case 'X':
if (*data < '0' || *data > '9') {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) X is not matched\n");
#endif
return 0;
}
break;
case 'z':
case 'Z':
if (*data < '1' || *data > '9') {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"return (0) Z is not matched\n");
#endif
return 0;
}
break;
case '.': /* Must match, even with more digits */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
#endif
return 1;
case '!': /* Early match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
#endif
return 2;
default:
if (*data != *pattern) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
#endif
return 0;
}
break;
}
++data;
++pattern;
}
if (*data) /* data longer than pattern, no match */ {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
#endif
return 0;
}
/*
* match so far, but ran off the end of data.
* Depending on what is next, determine match or not.
*/
if (*pattern == '\0' || *pattern == '/') { /* exact match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
#endif
return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
} else if (*pattern == '!') { /* early match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
#endif
return 2;
} else { /* partial match */
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
#endif
return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
}
}
/*
* Wrapper around _extension_match_core() to do performance measurement
* using the profiling code.
*/
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
{
int i;
static int prof_id = -2; /* marker for 'unallocated' id */
if (prof_id == -2) {
prof_id = ast_add_profile("ext_match", 0);
}
ast_mark(prof_id, 1);
i = _extension_match_core(ast_strlen_zero(pattern) ? "" : pattern, ast_strlen_zero(data) ? "" : data, mode);
ast_mark(prof_id, 0);
return i;
}
int ast_extension_match(const char *pattern, const char *data)
{
return extension_match_core(pattern, data, E_MATCH);
}
int ast_extension_close(const char *pattern, const char *data, int needmore)
{
if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
return extension_match_core(pattern, data, needmore);
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct fake_context /* this struct is purely for matching in the hashtab */
{
ast_rwlock_t lock;
struct ast_exten *root;
struct ast_hashtab *root_table;
struct match_char *pattern_tree;
struct ast_context *next;
struct ast_include *includes;
struct ast_ignorepat *ignorepats;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
const char *registrar;
int refcount;
AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
ast_mutex_t macrolock;
char name[256];
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
};
struct ast_context *ast_context_find(const char *name)
{
struct ast_context *tmp;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct fake_context item;
if (!name) {
return NULL;
}
ast_rdlock_contexts();
if (contexts_table) {
ast_copy_string(item.name, name, sizeof(item.name));
tmp = ast_hashtab_lookup(contexts_table, &item);
} else {
tmp = NULL;
while ((tmp = ast_walk_contexts(tmp))) {
if (!strcasecmp(name, tmp->name)) {
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
break;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
}
ast_unlock_contexts();
return tmp;
}
#define STATUS_NO_CONTEXT 1
#define STATUS_NO_EXTENSION 2
#define STATUS_NO_PRIORITY 3
#define STATUS_NO_LABEL 4
#define STATUS_SUCCESS 5
static int matchcid(const char *cidpattern, const char *callerid)
{
/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
failing to get a number should count as a match, otherwise not */
if (ast_strlen_zero(callerid)) {
return ast_strlen_zero(cidpattern) ? 1 : 0;
}
return ast_extension_match(cidpattern, callerid);
}
struct ast_exten *pbx_find_extension(struct ast_channel *chan,
struct ast_context *bypass, struct pbx_find_info *q,
const char *context, const char *exten, int priority,
const char *label, const char *callerid, enum ext_match_t action)
{
int x, res;
struct ast_context *tmp = NULL;
struct ast_exten *e = NULL, *eroot = NULL;
struct ast_include *i = NULL;
struct ast_sw *sw = NULL;
struct ast_exten pattern = {NULL, };
struct scoreboard score = {0, };
struct ast_str *tmpdata = NULL;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
pattern.label = label;
pattern.priority = priority;
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
#endif
/* Initialize status if appropriate */
if (q->stacklen == 0) {
q->status = STATUS_NO_CONTEXT;
q->swo = NULL;
q->data = NULL;
q->foundcontext = NULL;
} else if (q->stacklen >= AST_PBX_MAX_STACK) {
ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
return NULL;
}
/* Check first to see if we've already been checked */
for (x = 0; x < q->stacklen; x++) {
if (!strcasecmp(q->incstack[x], context))
return NULL;
}
if (bypass) { /* bypass means we only look there */
tmp = bypass;
} else { /* look in contexts */
tmp = find_context(context);
if (!tmp) {
return NULL;
}
}
if (q->status < STATUS_NO_EXTENSION)
q->status = STATUS_NO_EXTENSION;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
/* Do a search for matching extension */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
eroot = NULL;
score.total_specificity = 0;
score.exten = 0;
score.total_length = 0;
if (!tmp->pattern_tree && tmp->root_table) {
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
create_match_char_tree(tmp);
#ifdef NEED_DEBUG
ast_debug(1, "Tree Created in context %s:\n", context);
log_match_char_tree(tmp->pattern_tree," ");
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
#endif
}
#ifdef NEED_DEBUG
ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
log_match_char_tree(tmp->pattern_tree, ":: ");
#endif
do {
if (!ast_strlen_zero(overrideswitch)) {
char *osw = ast_strdupa(overrideswitch), *name;
struct ast_switch *asw;
ast_switch_f *aswf = NULL;
char *datap;
int eval = 0;
name = strsep(&osw, "/");
asw = pbx_findswitch(name);
if (!asw) {
ast_log(LOG_WARNING, "No such switch '%s'\n", name);
break;
}
if (osw && strchr(osw, '$')) {
eval = 1;
}
if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!\n");
break;
} else if (eval) {
/* Substitute variables now */
pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
datap = ast_str_buffer(tmpdata);
} else {
datap = osw;
}
/* equivalent of extension_match_core() at the switch level */
if (action == E_CANMATCH)
aswf = asw->canmatch;
else if (action == E_MATCHMORE)
aswf = asw->matchmore;
else /* action == E_MATCH */
aswf = asw->exists;
if (!aswf) {
res = 0;
} else {
if (chan) {
ast_autoservice_start(chan);
}
res = aswf(chan, context, exten, priority, callerid, datap);
if (chan) {
ast_autoservice_stop(chan);
}
}
if (res) { /* Got a match */
q->swo = asw;
q->data = datap;
q->foundcontext = context;
/* XXX keep status = STATUS_NO_CONTEXT ? */
return NULL;
}
}
} while (0);
if (extenpatternmatchnew) {
new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
eroot = score.exten;
if (score.last_char == '!' && action == E_MATCHMORE) {
/* We match an extension ending in '!'.
* The decision in this case is final and is NULL (no match).
*/
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
#endif
return NULL;
}
if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
q->status = STATUS_SUCCESS;
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
#endif
return score.canmatch_exten;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
if (score.node) {
struct ast_exten *z = trie_find_next_match(score.node);
if (z) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
#endif
} else {
if (score.canmatch_exten) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
#endif
return score.canmatch_exten;
} else {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
#endif
}
}
return z;
}
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
#endif
return NULL; /* according to the code, complete matches are null matches in MATCHMORE mode */
}
if (eroot) {
/* found entry, now look for the right priority */
if (q->status < STATUS_NO_PRIORITY)
q->status = STATUS_NO_PRIORITY;
e = NULL;
if (action == E_FINDLABEL && label ) {
if (q->status < STATUS_NO_LABEL)
q->status = STATUS_NO_LABEL;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
} else {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
e = ast_hashtab_lookup(eroot->peer_table, &pattern);
}
if (e) { /* found a valid match */
q->status = STATUS_SUCCESS;
q->foundcontext = context;
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
#endif
return e;
}
}
} else { /* the old/current default exten pattern match algorithm */
/* scan the list trying to match extension and CID */
eroot = NULL;
while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
int match = extension_match_core(eroot->exten, exten, action);
/* 0 on fail, 1 on match, 2 on earlymatch */
if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
continue; /* keep trying */
if (match == 2 && action == E_MATCHMORE) {
/* We match an extension ending in '!'.
* The decision in this case is final and is NULL (no match).
*/
return NULL;
}
/* found entry, now look for the right priority */
if (q->status < STATUS_NO_PRIORITY)
q->status = STATUS_NO_PRIORITY;
e = NULL;
if (action == E_FINDLABEL && label ) {
if (q->status < STATUS_NO_LABEL)
q->status = STATUS_NO_LABEL;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
} else {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
e = ast_hashtab_lookup(eroot->peer_table, &pattern);
}
if (e) { /* found a valid match */
q->status = STATUS_SUCCESS;
q->foundcontext = context;
return e;
}
}
}
/* Check alternative switches */
AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
struct ast_switch *asw = pbx_findswitch(sw->name);
ast_switch_f *aswf = NULL;
char *datap;
if (!asw) {
ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
continue;
}
/* Substitute variables now */
if (sw->eval) {
if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
continue;
}
pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
}
/* equivalent of extension_match_core() at the switch level */
if (action == E_CANMATCH)
aswf = asw->canmatch;
else if (action == E_MATCHMORE)
aswf = asw->matchmore;
else /* action == E_MATCH */
aswf = asw->exists;
datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
if (!aswf)
res = 0;
else {
if (chan)
ast_autoservice_start(chan);
res = aswf(chan, context, exten, priority, callerid, datap);
if (chan)
ast_autoservice_stop(chan);
}
if (res) { /* Got a match */
q->swo = asw;
q->data = datap;
q->foundcontext = context;
/* XXX keep status = STATUS_NO_CONTEXT ? */
return NULL;
}
}
q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
/* Now try any includes we have in this context */
for (i = tmp->includes; i; i = i->next) {
if (include_valid(i)) {
if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
#ifdef NEED_DEBUG_HERE
ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
#endif
return e;
}
if (q->swo)
return NULL;
}
}
return NULL;
}
/*!
* \brief extract offset:length from variable name.
* \return 1 if there is a offset:length part, which is
* trimmed off (values go into variables)
*/
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
{
int parens = 0;
*offset = 0;
*length = INT_MAX;
*isfunc = 0;
for (; *var; var++) {
if (*var == '(') {
(*isfunc)++;
parens++;
} else if (*var == ')') {
parens--;
} else if (*var == ':' && parens == 0) {
*var++ = '\0';
sscanf(var, "%30d:%30d", offset, length);
return 1; /* offset:length valid */
}
}
return 0;
}
/*!
*\brief takes a substring. It is ok to call with value == workspace.
* \param value
* \param offset < 0 means start from the end of the string and set the beginning
* to be that many characters back.
* \param length is the length of the substring, a value less than 0 means to leave
* that many off the end.
* \param workspace
* \param workspace_len
* Always return a copy in workspace.
*/
static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
{
char *ret = workspace;
int lr; /* length of the input string after the copy */
ast_copy_string(workspace, value, workspace_len); /* always make a copy */
lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
/* Quick check if no need to do anything */
if (offset == 0 && length >= lr) /* take the whole string */
return ret;
if (offset < 0) { /* translate negative offset into positive ones */
offset = lr + offset;
if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
offset = 0;
}
/* too large offset result in empty string so we know what to return */
if (offset >= lr)
return ret + lr; /* the final '\0' */
ret += offset; /* move to the start position */
if (length >= 0 && length < lr - offset) /* truncate if necessary */
ret[length] = '\0';
else if (length < 0) {
if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
ret[lr + length - offset] = '\0';
else
ret[0] = '\0';
}
return ret;
}
static const char *ast_str_substring(struct ast_str *value, int offset, int length)
{
int lr; /* length of the input string after the copy */
lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
/* Quick check if no need to do anything */
if (offset == 0 && length >= lr) /* take the whole string */
return ast_str_buffer(value);
if (offset < 0) { /* translate negative offset into positive ones */
offset = lr + offset;
if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
offset = 0;
}
/* too large offset result in empty string so we know what to return */
if (offset >= lr) {
ast_str_reset(value);
return ast_str_buffer(value);
}
if (offset > 0) {
/* Go ahead and chop off the beginning */
memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
lr -= offset;
}
if (length >= 0 && length < lr) { /* truncate if necessary */
char *tmp = ast_str_buffer(value);
tmp[length] = '\0';
ast_str_update(value);
} else if (length < 0) {
if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
char *tmp = ast_str_buffer(value);
tmp[lr + length] = '\0';
ast_str_update(value);
} else {
ast_str_reset(value);
}
} else {
/* Nothing to do, but update the buffer length */
ast_str_update(value);
}
return ast_str_buffer(value);
}
/*! \brief Support for Asterisk built-in variables in the dialplan
\note See also
- \ref AstVar Channel variables
- \ref AstCauses The HANGUPCAUSE variable
*/
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
{
struct ast_str *str = ast_str_create(16);
const char *cret;
cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
*ret = cret ? workspace : NULL;
ast_free(str);
}
const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
{
const char not_found = '\0';
char *tmpvar;
const char *ret;
const char *s; /* the result */
int offset, length;
int i, need_substring;
struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
char workspace[20];
if (c) {
ast_channel_lock(c);
places[0] = ast_channel_varshead(c);
}
/*
* Make a copy of var because parse_variable_name() modifies the string.
* Then if called directly, we might need to run substring() on the result;
* remember this for later in 'need_substring', 'offset' and 'length'
*/
tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
/*
* Look first into predefined variables, then into variable lists.
* Variable 's' points to the result, according to the following rules:
* s == &not_found (set at the beginning) means that we did not find a
* matching variable and need to look into more places.
* If s != &not_found, s is a valid result string as follows:
* s = NULL if the variable does not have a value;
* you typically do this when looking for an unset predefined variable.
* s = workspace if the result has been assembled there;
* typically done when the result is built e.g. with an snprintf(),
* so we don't need to do an additional copy.
* s != workspace in case we have a string, that needs to be copied
* (the ast_copy_string is done once for all at the end).
* Typically done when the result is already available in some string.
*/
s = &not_found; /* default value */
if (c) { /* This group requires a valid channel */
/* Names with common parts are looked up a piece at a time using strncmp. */
if (!strncmp(var, "CALL", 4)) {
if (!strncmp(var + 4, "ING", 3)) {
if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
ast_str_set(str, maxlen, "%d",
ast_party_id_presentation(&ast_channel_caller(c)->id));
s = ast_str_buffer(*str);
} else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
s = ast_str_buffer(*str);
} else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
s = ast_str_buffer(*str);
} else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
s = ast_str_buffer(*str);
}
}
} else if (!strcmp(var, "HINT")) {
s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
} else if (!strcmp(var, "HINTNAME")) {
s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
} else if (!strcmp(var, "EXTEN")) {
s = ast_channel_exten(c);
} else if (!strcmp(var, "CONTEXT")) {
s = ast_channel_context(c);
} else if (!strcmp(var, "PRIORITY")) {
ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
s = ast_str_buffer(*str);
} else if (!strcmp(var, "CHANNEL")) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
s = ast_channel_name(c);
} else if (!strcmp(var, "UNIQUEID")) {
s = ast_channel_uniqueid(c);
} else if (!strcmp(var, "HANGUPCAUSE")) {
ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
s = ast_str_buffer(*str);
}
}
if (s == &not_found) { /* look for more */
if (!strcmp(var, "EPOCH")) {
ast_str_set(str, maxlen, "%d", (int) time(NULL));
s = ast_str_buffer(*str);
} else if (!strcmp(var, "SYSTEMNAME")) {
s = ast_config_AST_SYSTEM_NAME;
} else if (!strcmp(var, "ASTETCDIR")) {
s = ast_config_AST_CONFIG_DIR;
} else if (!strcmp(var, "ASTMODDIR")) {
s = ast_config_AST_MODULE_DIR;
} else if (!strcmp(var, "ASTVARLIBDIR")) {
s = ast_config_AST_VAR_DIR;
} else if (!strcmp(var, "ASTDBDIR")) {
s = ast_config_AST_DB;
} else if (!strcmp(var, "ASTKEYDIR")) {
s = ast_config_AST_KEY_DIR;
} else if (!strcmp(var, "ASTDATADIR")) {
s = ast_config_AST_DATA_DIR;
} else if (!strcmp(var, "ASTAGIDIR")) {
s = ast_config_AST_AGI_DIR;
} else if (!strcmp(var, "ASTSPOOLDIR")) {
s = ast_config_AST_SPOOL_DIR;
} else if (!strcmp(var, "ASTRUNDIR")) {
s = ast_config_AST_RUN_DIR;
} else if (!strcmp(var, "ASTLOGDIR")) {
s = ast_config_AST_LOG_DIR;
} else if (!strcmp(var, "ENTITYID")) {
ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
s = workspace;
}
}
/* if not found, look into chanvars or global vars */
for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
struct ast_var_t *variables;
if (!places[i])
continue;
if (places[i] == &globals)
ast_rwlock_rdlock(&globalslock);
AST_LIST_TRAVERSE(places[i], variables, entries) {
if (!strcmp(ast_var_name(variables), var)) {
s = ast_var_value(variables);
break;
}
}
if (places[i] == &globals)
ast_rwlock_unlock(&globalslock);
}
if (s == &not_found || s == NULL) {
ast_debug(5, "Result of '%s' is NULL\n", var);
ret = NULL;
} else {
ast_debug(5, "Result of '%s' is '%s'\n", var, s);
if (s != ast_str_buffer(*str)) {
ast_str_set(str, maxlen, "%s", s);
}
ret = ast_str_buffer(*str);
if (need_substring) {
ret = ast_str_substring(*str, offset, length);
ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
}
}
if (c) {
ast_channel_unlock(c);
}
return ret;
}
static void exception_store_free(void *data)
{
struct pbx_exception *exception = data;
ast_string_field_free_memory(exception);
ast_free(exception);
}
static const struct ast_datastore_info exception_store_info = {
.type = "EXCEPTION",
.destroy = exception_store_free,
};
/*!
* \internal
* \brief Set the PBX to execute the exception extension.
*
* \param chan Channel to raise the exception on.
* \param reason Reason exception is raised.
* \param priority Dialplan priority to set.
*
* \retval 0 on success.
* \retval -1 on error.
*/
static int raise_exception(struct ast_channel *chan, const char *reason, int priority)
{
struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
struct pbx_exception *exception = NULL;
if (!ds) {
ds = ast_datastore_alloc(&exception_store_info, NULL);
if (!ds)
return -1;
if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) {
ast_datastore_free(ds);
return -1;
}
ds->data = exception;
ast_channel_datastore_add(chan, ds);
} else
exception = ds->data;
ast_string_field_set(exception, reason, reason);
ast_string_field_set(exception, context, ast_channel_context(chan));
ast_string_field_set(exception, exten, ast_channel_exten(chan));
exception->priority = ast_channel_priority(chan);
set_ext_pri(chan, "e", priority);
return 0;
}
int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
{
/* Priority will become 1, next time through the AUTOLOOP */
return raise_exception(chan, reason, 0);
}
static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
{
struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
struct pbx_exception *exception = NULL;
if (!ds || !ds->data)
return -1;
exception = ds->data;
if (!strcasecmp(data, "REASON"))
ast_copy_string(buf, exception->reason, buflen);
else if (!strcasecmp(data, "CONTEXT"))
ast_copy_string(buf, exception->context, buflen);
else if (!strncasecmp(data, "EXTEN", 5))
ast_copy_string(buf, exception->exten, buflen);
else if (!strcasecmp(data, "PRIORITY"))
snprintf(buf, buflen, "%d", exception->priority);
else
return -1;
return 0;
}
static struct ast_custom_function exception_function = {
.name = "EXCEPTION",
.read = acf_exception_read,
};
static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_custom_function *acf;
int count_acf = 0;
int like = 0;
switch (cmd) {
case CLI_INIT:
e->command = "core show functions [like]";
e->usage =
"Usage: core show functions [like <text>]\n"
" List builtin functions, optionally only those matching a given string\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
like = 1;
} else if (a->argc != 3) {
return CLI_SHOWUSAGE;
}
ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
AST_RWLIST_RDLOCK(&acf_root);
AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
if (!like || strstr(acf->name, a->argv[4])) {
count_acf++;
ast_cli(a->fd, "%-20.20s %-35.35s %s\n",
S_OR(acf->name, ""),
S_OR(acf->syntax, ""),
S_OR(acf->synopsis, ""));
}
}
AST_RWLIST_UNLOCK(&acf_root);
ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
return CLI_SUCCESS;
}
static char *complete_functions(const char *word, int pos, int state)
{
struct ast_custom_function *cur;
char *ret = NULL;
int which = 0;
int wordlen;
int cmp;
if (pos != 3) {
return NULL;
}
wordlen = strlen(word);
AST_RWLIST_RDLOCK(&acf_root);
AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
/*
* Do a case-insensitive search for convenience in this
* 'complete' function.
*
* We must search the entire container because the functions are
* sorted and normally found case sensitively.
*/
cmp = strncasecmp(word, cur->name, wordlen);
if (!cmp) {
/* Found match. */
if (++which <= state) {
/* Not enough matches. */
continue;
}
ret = ast_strdup(cur->name);
break;
}
}
AST_RWLIST_UNLOCK(&acf_root);
return ret;
}
static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_custom_function *acf;
/* Maximum number of characters added by terminal coloring is 22 */
char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
char stxtitle[40], *syntax = NULL, *arguments = NULL;
int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
switch (cmd) {
case CLI_INIT:
e->command = "core show function";
e->usage =
"Usage: core show function <function>\n"
" Describe a particular dialplan function.\n";
return NULL;
case CLI_GENERATE:
return complete_functions(a->word, a->pos, a->n);
}
if (a->argc != 4) {
return CLI_SHOWUSAGE;
}
if (!(acf = ast_custom_function_find(a->argv[3]))) {
ast_cli(a->fd, "No function by that name registered.\n");
return CLI_FAILURE;
}
syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
if (!(syntax = ast_malloc(syntax_size))) {
ast_cli(a->fd, "Memory allocation failure!\n");
return CLI_FAILURE;
}
snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name);
term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
#ifdef AST_XML_DOCS
if (acf->docsrc == AST_XML_DOC) {
arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
} else
#endif
{
synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
synopsis = ast_malloc(synopsis_size);
description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
description = ast_malloc(description_size);
arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
arguments = ast_malloc(arguments_size);
seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
seealso = ast_malloc(seealso_size);
/* check allocated memory. */
if (!synopsis || !description || !arguments || !seealso) {
ast_free(synopsis);
ast_free(description);
ast_free(arguments);
ast_free(seealso);
ast_free(syntax);
return CLI_FAILURE;
}
term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
}
ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
infotitle, syntitle, synopsis, destitle, description,
stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
ast_free(arguments);
ast_free(synopsis);
ast_free(description);
ast_free(seealso);
ast_free(syntax);
return CLI_SUCCESS;
}
static struct ast_custom_function *ast_custom_function_find_nolock(const char *name)
{
struct ast_custom_function *cur;
int cmp;
AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
cmp = strcmp(name, cur->name);
if (cmp > 0) {
continue;
}
if (!cmp) {
/* Found it. */
break;
}
/* Not in container. */
cur = NULL;
break;
}
return cur;
}
struct ast_custom_function *ast_custom_function_find(const char *name)
{
struct ast_custom_function *acf;
AST_RWLIST_RDLOCK(&acf_root);
acf = ast_custom_function_find_nolock(name);
AST_RWLIST_UNLOCK(&acf_root);
return acf;
}
int ast_custom_function_unregister(struct ast_custom_function *acf)
{
struct ast_custom_function *cur;
if (!acf) {
return -1;
}
AST_RWLIST_WRLOCK(&acf_root);
if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
#ifdef AST_XML_DOCS
if (cur->docsrc == AST_XML_DOC) {
ast_string_field_free_memory(acf);
}
#endif
ast_verb(2, "Unregistered custom function %s\n", cur->name);
}
AST_RWLIST_UNLOCK(&acf_root);
return cur ? 0 : -1;
}
/*!
* \brief Returns true if given custom function escalates privileges on read.
*
* \param acf Custom function to query.
* \return True (non-zero) if reads escalate privileges.
* \return False (zero) if reads just read.
*/
static int read_escalates(const struct ast_custom_function *acf) {
return acf->read_escalates;
}
/*!
* \brief Returns true if given custom function escalates privileges on write.
*
* \param acf Custom function to query.
* \return True (non-zero) if writes escalate privileges.
* \return False (zero) if writes just write.
*/
static int write_escalates(const struct ast_custom_function *acf) {
return acf->write_escalates;
}
/*! \internal
* \brief Retrieve the XML documentation of a specified ast_custom_function,
* and populate ast_custom_function string fields.
* \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
* but with a function 'name'.
* \retval -1 On error.
* \retval 0 On succes.
*/
static int acf_retrieve_docs(struct ast_custom_function *acf)
{
#ifdef AST_XML_DOCS
char *tmpxml;
/* Let's try to find it in the Documentation XML */
if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
return 0;
}
if (ast_string_field_init(acf, 128)) {
return -1;
}
/* load synopsis */
tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
ast_string_field_set(acf, synopsis, tmpxml);
ast_free(tmpxml);
/* load description */
tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
ast_string_field_set(acf, desc, tmpxml);
ast_free(tmpxml);
/* load syntax */
tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
ast_string_field_set(acf, syntax, tmpxml);
ast_free(tmpxml);
/* load arguments */
tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
ast_string_field_set(acf, arguments, tmpxml);
ast_free(tmpxml);
/* load seealso */
tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
ast_string_field_set(acf, seealso, tmpxml);
ast_free(tmpxml);
acf->docsrc = AST_XML_DOC;
#endif
return 0;
}
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
{
struct ast_custom_function *cur;
if (!acf) {
return -1;
}
acf->mod = mod;
#ifdef AST_XML_DOCS
acf->docsrc = AST_STATIC_DOC;
#endif
if (acf_retrieve_docs(acf)) {
return -1;
}
AST_RWLIST_WRLOCK(&acf_root);
cur = ast_custom_function_find_nolock(acf->name);
if (cur) {
ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
AST_RWLIST_UNLOCK(&acf_root);
return -1;
}
/* Store in alphabetical order */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
if (strcmp(acf->name, cur->name) < 0) {
AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
if (!cur) {
AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
}
AST_RWLIST_UNLOCK(&acf_root);
ast_verb(2, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
return 0;
}
int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
{
int res;
res = __ast_custom_function_register(acf, mod);
if (res != 0) {
return -1;
}
switch (escalation) {
case AST_CFE_NONE:
break;
case AST_CFE_READ:
acf->read_escalates = 1;
break;
case AST_CFE_WRITE:
acf->write_escalates = 1;
break;
case AST_CFE_BOTH:
acf->read_escalates = 1;
acf->write_escalates = 1;
break;
}
return 0;
}
/*! \brief return a pointer to the arguments of the function,
* and terminates the function name with '\\0'
*/
static char *func_args(char *function)
{
char *args = strchr(function, '(');
if (!args) {
ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
} else {
char *p;
*args++ = '\0';
if ((p = strrchr(args, ')'))) {
*p = '\0';
} else {
ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
}
}
return args;
}
void pbx_live_dangerously(int new_live_dangerously)
{
if (new_live_dangerously && !live_dangerously) {
ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
"See https://wiki.asterisk.org/wiki/x/1gKfAQ for more details.\n");
}
if (!new_live_dangerously && live_dangerously) {
ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
}
live_dangerously = new_live_dangerously;
}
int ast_thread_inhibit_escalations(void)
{
int *thread_inhibit_escalations;
thread_inhibit_escalations = ast_threadstorage_get(
&thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
if (thread_inhibit_escalations == NULL) {
ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
return -1;
}
*thread_inhibit_escalations = 1;
return 0;
}
/*!
* \brief Indicates whether the current thread inhibits the execution of
* dangerous functions.
*
* \return True (non-zero) if dangerous function execution is inhibited.
* \return False (zero) if dangerous function execution is allowed.
*/
static int thread_inhibits_escalations(void)
{
int *thread_inhibit_escalations;
thread_inhibit_escalations = ast_threadstorage_get(
&thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
if (thread_inhibit_escalations == NULL) {
ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
/* On error, assume that we are inhibiting */
return 1;
}
return *thread_inhibit_escalations;
}
/*!
* \brief Determines whether execution of a custom function's read function
* is allowed.
*
* \param acfptr Custom function to check
* \return True (non-zero) if reading is allowed.
* \return False (zero) if reading is not allowed.
*/
static int is_read_allowed(struct ast_custom_function *acfptr)
{
if (!acfptr) {
return 1;
}
if (!read_escalates(acfptr)) {
return 1;
}
if (!thread_inhibits_escalations()) {
return 1;
}
if (live_dangerously) {
/* Global setting overrides the thread's preference */
ast_debug(2, "Reading %s from a dangerous context\n",
acfptr->name);
return 1;
}
/* We have no reason to allow this function to execute */
return 0;
}
/*!
* \brief Determines whether execution of a custom function's write function
* is allowed.
*
* \param acfptr Custom function to check
* \return True (non-zero) if writing is allowed.
* \return False (zero) if writing is not allowed.
*/
static int is_write_allowed(struct ast_custom_function *acfptr)
{
if (!acfptr) {
return 1;
}
if (!write_escalates(acfptr)) {
return 1;
}
if (!thread_inhibits_escalations()) {
return 1;
}
if (live_dangerously) {
/* Global setting overrides the thread's preference */
ast_debug(2, "Writing %s from a dangerous context\n",
acfptr->name);
return 1;
}
/* We have no reason to allow this function to execute */
return 0;
}
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
{
char *copy = ast_strdupa(function);
char *args = func_args(copy);
struct ast_custom_function *acfptr = ast_custom_function_find(copy);
int res;
struct ast_module_user *u = NULL;
if (acfptr == NULL) {
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
} else if (!acfptr->read && !acfptr->read2) {
ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
} else if (!is_read_allowed(acfptr)) {
ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
} else if (acfptr->read) {
if (acfptr->mod) {
u = __ast_module_user_add(acfptr->mod, chan);
}
res = acfptr->read(chan, copy, args, workspace, len);
if (acfptr->mod && u) {
__ast_module_user_remove(acfptr->mod, u);
}
return res;
} else {
struct ast_str *str = ast_str_create(16);
if (acfptr->mod) {
u = __ast_module_user_add(acfptr->mod, chan);
}
res = acfptr->read2(chan, copy, args, &str, 0);
if (acfptr->mod && u) {
__ast_module_user_remove(acfptr->mod, u);
}
ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
ast_free(str);
return res;
}
return -1;
}
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
{
char *copy = ast_strdupa(function);
char *args = func_args(copy);
struct ast_custom_function *acfptr = ast_custom_function_find(copy);
int res;
struct ast_module_user *u = NULL;
if (acfptr == NULL) {
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
} else if (!acfptr->read && !acfptr->read2) {
ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
} else if (!is_read_allowed(acfptr)) {
ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
} else {
if (acfptr->mod) {
u = __ast_module_user_add(acfptr->mod, chan);
}
ast_str_reset(*str);
if (acfptr->read2) {
/* ast_str enabled */
res = acfptr->read2(chan, copy, args, str, maxlen);
} else {
/* Legacy function pointer, allocate buffer for result */
int maxsize = ast_str_size(*str);
if (maxlen > -1) {
if (maxlen == 0) {
if (acfptr->read_max) {
maxsize = acfptr->read_max;
} else {
maxsize = VAR_BUF_SIZE;
}
} else {
maxsize = maxlen;
}
ast_str_make_space(str, maxsize);
}
res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
}
if (acfptr->mod && u) {
__ast_module_user_remove(acfptr->mod, u);
}
return res;
}
return -1;
}
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
{
char *copy = ast_strdupa(function);
char *args = func_args(copy);
struct ast_custom_function *acfptr = ast_custom_function_find(copy);
if (acfptr == NULL) {
ast_log(LOG_ERROR, "Function %s not registered\n", copy);
} else if (!acfptr->write) {
ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
} else if (!is_write_allowed(acfptr)) {
ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
} else {
int res;
struct ast_module_user *u = NULL;
if (acfptr->mod)
u = __ast_module_user_add(acfptr->mod, chan);
res = acfptr->write(chan, copy, args, value);
if (acfptr->mod && u)
__ast_module_user_remove(acfptr->mod, u);
return res;
}
return -1;
}
void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
{
/* Substitutes variables into buf, based on string templ */
char *cp4 = NULL;
const char *whereweare;
int orig_size = 0;
int offset, offset2, isfunction;
const char *nextvar, *nextexp, *nextthing;
const char *vars, *vare;
char *finalvars;
int pos, brackets, needsub, len;
struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
ast_str_reset(*buf);
whereweare = templ;
while (!ast_strlen_zero(whereweare)) {
/* reset our buffer */
ast_str_reset(substr3);
/* Assume we're copying the whole remaining string */
pos = strlen(whereweare);
nextvar = NULL;
nextexp = NULL;
nextthing = strchr(whereweare, '$');
if (nextthing) {
switch (nextthing[1]) {
case '{':
nextvar = nextthing;
pos = nextvar - whereweare;
break;
case '[':
nextexp = nextthing;
pos = nextexp - whereweare;
break;
default:
pos = 1;
}
}
if (pos) {
/* Copy that many bytes */
ast_str_append_substr(buf, maxlen, whereweare, pos);
templ += pos;
whereweare += pos;
}
if (nextvar) {
/* We have a variable. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextvar + 2;
brackets = 1;
needsub = 0;
/* Find the end of it */
while (brackets && *vare) {
if ((vare[0] == '$') && (vare[1] == '{')) {
needsub++;
} else if (vare[0] == '{') {
brackets++;
} else if (vare[0] == '}') {
brackets--;
} else if ((vare[0] == '$') && (vare[1] == '['))
needsub++;
vare++;
}
if (brackets)
ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
len = vare - vars - 1;
/* Skip totally over variable string */
whereweare += (len + 3);
/* Store variable name (and truncate) */
ast_str_set_substr(&substr1, 0, vars, len);
ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
/* Substitute if necessary */
if (needsub) {
size_t my_used;
if (!substr2) {
substr2 = ast_str_create(16);
}
ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
finalvars = ast_str_buffer(substr2);
} else {
finalvars = ast_str_buffer(substr1);
}
parse_variable_name(finalvars, &offset, &offset2, &isfunction);
if (isfunction) {
/* Evaluate function */
if (c || !headp) {
cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
} else {
struct varshead old;
struct ast_channel *bogus = ast_dummy_channel_alloc();
if (bogus) {
memcpy(&old, ast_channel_varshead(bogus), sizeof(old));
memcpy(ast_channel_varshead(bogus), headp, sizeof(*ast_channel_varshead(bogus)));
cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
/* Don't deallocate the varshead that was passed in */
memcpy(ast_channel_varshead(bogus), &old, sizeof(*ast_channel_varshead(bogus)));
Merged revisions 337974 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500 (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011) | 30 lines Fix deadlock when using dummy channels. Dummy channels created by ast_dummy_channel_alloc() should be destoyed by ast_channel_unref(). Using ast_channel_release() needlessly grabs the channel container lock and can cause a deadlock as a result. * Analyzed use of ast_dummy_channel_alloc() and made use ast_channel_unref() when done with the dummy channel. (Primary reason for the reported deadlock.) * Made app_dial.c:dial_exec_full() not call ast_call() holding any channel locks. Chan_local could not perform deadlock avoidance correctly. (Potential deadlock exposed by this issue. Secondary reason for the reported deadlock since the held lock was part of the deadlock chain.) * Fixed some uses of ast_dummy_channel_alloc() not checking the returned channel pointer for failure. * Fixed some potential chan=NULL pointer usage in func_odbc.c. Protected by testing the bogus_chan value. * Fixed needlessly clearing a 1024 char auto array when setting the first char to zero is enough in manager.c:action_getvar(). (closes issue ASTERISK-18613) Reported by: Thomas Arimont Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: Thomas Arimont ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-26 19:40:12 +00:00
ast_channel_unref(bogus);
} else {
ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
}
}
Remove some spammy debug messages; improve clarity of others Debug messages aren't free. Even when the debug level is sufficiently low such that the messages are never evaluated, there is a cost to having to parse Asterisk logs that contain debug messages that (a) fail to convey sufficient information or (b) occur so frequently as to be next to meaningless. Based on having to stare at lots of DEBUG messages, this patch makes the following changes: * channel.c: When copying variables from a parent channel to a child channel, specify the channels involved. Do not log anything for a variable that is not inherited; the fact that it doesn't have an _ or __ already signifies that it won't be inherited. * pbx.c: Specify what function evaluation has occurred that created the result. * translate.c: Bump up the translator path messages to 10. I've never once had to use these debug messages, and for each format that is registered (on startup) and unregistered (on shutdown) the entire f^2 matrix is logged out. For short tests in the Asterisk Test Suite, this should make finding the actual test much easier. * xmldoc.c: The debug message that 'blah' is not found in the tree is expected. Often, description elements - which are not required - are not provided. This debug message adds no additional value, as it is not indicative of an error or helpful in debugging which element did not contain a 'blah' element as a child. If an element is supposed to contain a child element, then that XML tree should have failed validation in the first place. Review: https://reviewboard.asterisk.org/r/2966/ ........ Merged revisions 402150 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 402151 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 402154 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402155 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-10-29 12:57:35 +00:00
ast_debug(2, "Function %s result is '%s'\n", finalvars, cp4 ? cp4 : "(null)");
} else {
/* Retrieve variable value */
ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
cp4 = ast_str_buffer(substr3);
}
if (cp4) {
ast_str_substring(substr3, offset, offset2);
ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
}
} else if (nextexp) {
/* We have an expression. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextexp + 2;
brackets = 1;
needsub = 0;
/* Find the end of it */
while (brackets && *vare) {
if ((vare[0] == '$') && (vare[1] == '[')) {
needsub++;
brackets++;
vare++;
} else if (vare[0] == '[') {
brackets++;
} else if (vare[0] == ']') {
brackets--;
} else if ((vare[0] == '$') && (vare[1] == '{')) {
needsub++;
vare++;
}
vare++;
}
if (brackets)
ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
len = vare - vars - 1;
/* Skip totally over expression */
whereweare += (len + 3);
/* Store variable name (and truncate) */
ast_str_set_substr(&substr1, 0, vars, len);
/* Substitute if necessary */
if (needsub) {
size_t my_used;
if (!substr2) {
substr2 = ast_str_create(16);
}
ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
finalvars = ast_str_buffer(substr2);
} else {
finalvars = ast_str_buffer(substr1);
}
if (ast_str_expr(&substr3, 0, c, finalvars)) {
ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
}
ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
}
}
*used = ast_str_strlen(*buf) - orig_size;
ast_free(substr1);
ast_free(substr2);
ast_free(substr3);
}
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
{
size_t used;
ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
}
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
{
size_t used;
ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
}
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
{
/* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
char *cp4 = NULL;
const char *whereweare, *orig_cp2 = cp2;
int length, offset, offset2, isfunction;
char *workspace = NULL;
char *ltmp = NULL, *var = NULL;
char *nextvar, *nextexp, *nextthing;
char *vars, *vare;
int pos, brackets, needsub, len;
*cp2 = 0; /* just in case nothing ends up there */
whereweare = cp1;
while (!ast_strlen_zero(whereweare) && count) {
/* Assume we're copying the whole remaining string */
pos = strlen(whereweare);
nextvar = NULL;
nextexp = NULL;
nextthing = strchr(whereweare, '$');
if (nextthing) {
switch (nextthing[1]) {
case '{':
nextvar = nextthing;
pos = nextvar - whereweare;
break;
case '[':
nextexp = nextthing;
pos = nextexp - whereweare;
break;
default:
pos = 1;
}
}
if (pos) {
/* Can't copy more than 'count' bytes */
if (pos > count)
pos = count;
/* Copy that many bytes */
memcpy(cp2, whereweare, pos);
count -= pos;
cp2 += pos;
whereweare += pos;
*cp2 = 0;
}
if (nextvar) {
/* We have a variable. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextvar + 2;
brackets = 1;
needsub = 0;
/* Find the end of it */
while (brackets && *vare) {
if ((vare[0] == '$') && (vare[1] == '{')) {
needsub++;
} else if (vare[0] == '{') {
brackets++;
} else if (vare[0] == '}') {
brackets--;
} else if ((vare[0] == '$') && (vare[1] == '['))
needsub++;
vare++;
}
if (brackets)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
len = vare - vars - 1;
/* Skip totally over variable string */
whereweare += (len + 3);
if (!var)
var = ast_alloca(VAR_BUF_SIZE);
/* Store variable name (and truncate) */
ast_copy_string(var, vars, len + 1);
/* Substitute if necessary */
if (needsub) {
size_t my_used;
if (!ltmp) {
ltmp = ast_alloca(VAR_BUF_SIZE);
}
pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
vars = ltmp;
} else {
vars = var;
}
if (!workspace)
workspace = ast_alloca(VAR_BUF_SIZE);
workspace[0] = '\0';
parse_variable_name(vars, &offset, &offset2, &isfunction);
if (isfunction) {
/* Evaluate function */
if (c || !headp)
cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
else {
struct varshead old;
struct ast_channel *c = ast_dummy_channel_alloc();
if (c) {
memcpy(&old, ast_channel_varshead(c), sizeof(old));
memcpy(ast_channel_varshead(c), headp, sizeof(*ast_channel_varshead(c)));
cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
/* Don't deallocate the varshead that was passed in */
memcpy(ast_channel_varshead(c), &old, sizeof(*ast_channel_varshead(c)));
Merged revisions 337974 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500 (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011) | 30 lines Fix deadlock when using dummy channels. Dummy channels created by ast_dummy_channel_alloc() should be destoyed by ast_channel_unref(). Using ast_channel_release() needlessly grabs the channel container lock and can cause a deadlock as a result. * Analyzed use of ast_dummy_channel_alloc() and made use ast_channel_unref() when done with the dummy channel. (Primary reason for the reported deadlock.) * Made app_dial.c:dial_exec_full() not call ast_call() holding any channel locks. Chan_local could not perform deadlock avoidance correctly. (Potential deadlock exposed by this issue. Secondary reason for the reported deadlock since the held lock was part of the deadlock chain.) * Fixed some uses of ast_dummy_channel_alloc() not checking the returned channel pointer for failure. * Fixed some potential chan=NULL pointer usage in func_odbc.c. Protected by testing the bogus_chan value. * Fixed needlessly clearing a 1024 char auto array when setting the first char to zero is enough in manager.c:action_getvar(). (closes issue ASTERISK-18613) Reported by: Thomas Arimont Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: Thomas Arimont ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-26 19:40:12 +00:00
c = ast_channel_unref(c);
} else {
ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
}
}
Remove some spammy debug messages; improve clarity of others Debug messages aren't free. Even when the debug level is sufficiently low such that the messages are never evaluated, there is a cost to having to parse Asterisk logs that contain debug messages that (a) fail to convey sufficient information or (b) occur so frequently as to be next to meaningless. Based on having to stare at lots of DEBUG messages, this patch makes the following changes: * channel.c: When copying variables from a parent channel to a child channel, specify the channels involved. Do not log anything for a variable that is not inherited; the fact that it doesn't have an _ or __ already signifies that it won't be inherited. * pbx.c: Specify what function evaluation has occurred that created the result. * translate.c: Bump up the translator path messages to 10. I've never once had to use these debug messages, and for each format that is registered (on startup) and unregistered (on shutdown) the entire f^2 matrix is logged out. For short tests in the Asterisk Test Suite, this should make finding the actual test much easier. * xmldoc.c: The debug message that 'blah' is not found in the tree is expected. Often, description elements - which are not required - are not provided. This debug message adds no additional value, as it is not indicative of an error or helpful in debugging which element did not contain a 'blah' element as a child. If an element is supposed to contain a child element, then that XML tree should have failed validation in the first place. Review: https://reviewboard.asterisk.org/r/2966/ ........ Merged revisions 402150 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 402151 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 402154 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402155 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-10-29 12:57:35 +00:00
ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
} else {
/* Retrieve variable value */
pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
}
if (cp4) {
cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
length = strlen(cp4);
if (length > count)
length = count;
memcpy(cp2, cp4, length);
count -= length;
cp2 += length;
*cp2 = 0;
}
} else if (nextexp) {
/* We have an expression. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextexp + 2;
brackets = 1;
needsub = 0;
/* Find the end of it */
while (brackets && *vare) {
if ((vare[0] == '$') && (vare[1] == '[')) {
needsub++;
brackets++;
vare++;
} else if (vare[0] == '[') {
brackets++;
} else if (vare[0] == ']') {
brackets--;
} else if ((vare[0] == '$') && (vare[1] == '{')) {
needsub++;
vare++;
}
vare++;
}
if (brackets)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
len = vare - vars - 1;
/* Skip totally over expression */
whereweare += (len + 3);
if (!var)
var = ast_alloca(VAR_BUF_SIZE);
/* Store variable name (and truncate) */
ast_copy_string(var, vars, len + 1);
/* Substitute if necessary */
if (needsub) {
size_t my_used;
if (!ltmp) {
ltmp = ast_alloca(VAR_BUF_SIZE);
}
pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
vars = ltmp;
} else {
vars = var;
}
length = ast_expr(vars, cp2, count, c);
if (length) {
ast_debug(1, "Expression result is '%s'\n", cp2);
count -= length;
cp2 += length;
*cp2 = 0;
}
}
}
*used = cp2 - orig_cp2;
}
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
{
size_t used;
pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, &used);
}
void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
{
size_t used;
pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
}
/*!
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
* \brief The return value depends on the action:
*
* E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
* and return 0 on failure, -1 on match;
* E_FINDLABEL maps the label to a priority, and returns
* the priority on success, ... XXX
* E_SPAWN, spawn an application,
*
* \retval 0 on success.
* \retval -1 on failure.
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
*
* \note The channel is auto-serviced in this function, because doing an extension
* match may block for a long time. For example, if the lookup has to use a network
* dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
* auto-service code will queue up any important signalling frames to be processed
* after this is done.
*/
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
const char *context, const char *exten, int priority,
const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
{
struct ast_exten *e;
struct ast_app *app;
char *substitute = NULL;
int res;
struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
char passdata[EXT_DATA_SIZE];
int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
ast_rdlock_contexts();
if (found)
*found = 0;
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
if (e) {
if (found)
*found = 1;
if (matching_action) {
ast_unlock_contexts();
return -1; /* success, we found it */
} else if (action == E_FINDLABEL) { /* map the label to a priority */
res = e->priority;
ast_unlock_contexts();
return res; /* the priority we were looking for */
} else { /* spawn */
if (!e->cached_app)
e->cached_app = pbx_findapp(e->app);
app = e->cached_app;
if (ast_strlen_zero(e->data)) {
*passdata = '\0';
} else {
const char *tmp;
if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
/* no variables to substitute, copy on through */
ast_copy_string(passdata, e->data, sizeof(passdata));
} else {
/* save e->data on stack for later processing after lock released */
substitute = ast_strdupa(e->data);
}
}
ast_unlock_contexts();
if (!app) {
ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
return -1;
}
if (ast_channel_context(c) != context)
ast_channel_context_set(c, context);
if (ast_channel_exten(c) != exten)
ast_channel_exten_set(c, exten);
ast_channel_priority_set(c, priority);
if (substitute) {
pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
}
ast_debug(1, "Launching '%s'\n", app->name);
verbosity: Fix performance of console verbose messages. The per console verbose level feature as previously implemented caused a large performance penalty. The fix required some minor incompatibilities if the new rasterisk is used to connect to an earlier version. If the new rasterisk connects to an older Asterisk version then the root console verbose level is always affected by the "core set verbose" command of the remote console even though it may appear to only affect the current console. If an older version of rasterisk connects to the new version then the "core set verbose" command will have no effect. * Fixed the verbose performance by not generating a verbose message if nothing is going to use it and then filtered any generated verbose messages before actually sending them to the remote consoles. * Split the "core set debug" and "core set verbose" CLI commands to remove the per module verbose support that cannot work with the per console verbose level. * Added a silent option to the "core set verbose" command. * Fixed "core set debug off" tab completion. * Made "core show settings" list the current console verbosity in addition to the root console verbosity. * Changed the default verbose level of the 'verbose' setting in the logger.conf [logfiles] section. The default is now to once again follow the current root console level. As a result, using the AMI Command action with "core set verbose" could again set the root console verbose level and affect the verbose level logged. (closes issue AST-1252) Reported by: Guenther Kelleter Review: https://reviewboard.asterisk.org/r/3114/ ........ Merged revisions 405431 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 405432 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@405436 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-01-14 18:14:02 +00:00
if (VERBOSITY_ATLEAST(3)) {
ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
exten, context, priority,
COLORIZE(COLOR_BRCYAN, 0, app->name),
COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(c)),
COLORIZE(COLOR_BRMAGENTA, 0, passdata),
"in new stack");
}
return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
}
} else if (q.swo) { /* not found here, but in another switch */
if (found)
*found = 1;
ast_unlock_contexts();
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
if (matching_action) {
return -1;
Merged revisions 89790 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r89790 | russell | 2007-11-27 15:45:51 -0600 (Tue, 27 Nov 2007) | 41 lines Merge changes from team/russell/autoservice_1.4 This set of changes fixes an issue that was reported to me on IRC yesterday. The user, d1mas, was using chan_zap for incoming calls and was having DTMF recognition issues in some situations. Specifically, he noticed that the problem occurred when using DISA or WaitExten. He also noticed that when using Read, the problem did not occur. His system also used DUNDi for dialplan lookups. So, he theorized that if the DUNDi lookups blocked for some period of time, that audio from the zap channel could get lost. If the audio got lost, then it wouldn't be run through the DTMF detector, and digits could get lost. He was correct, and the following set of changes fixes the problem. However, the changes go a little bit further than what was necessary to fix this exact problem. 1) I updated pbx_extension_helper() to autoservice the associated channel to handle cases where extension lookups may take a long time. This would normally be a dialplan switch that does some lookup over the network, such as the DUNDi or IAX2 switches. This ensures that even while a DUNDi lookup is blocking, the channel will be continuously serviced. 2) I made a change to the autoservice code. This is actually something that has bothered me for a long time. When a channel is in autoservice, _all_ frames get thrown away. However, some frames really shouldn't be thrown away. The most notable examples are signalling (CONTROL) frames, and DTMF. So, this patch queues up important frames while a channel is in autoservice. When autoservice is stopped on the channel, the queued up frames get stuck back on the channel so that they can get processed instead of thrown away. 3) I made another change to the autoservice code to handle the case where autoservice is started on channels recursively. Previously, you could call ast_autoservice_start() multiple times on a channel, and it would stop the first time ast_autoservice_stop() gets called. Now, it will ensure that autoservice doesn't actually stop until the final call to ast_autoservice_stop(). ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-27 22:05:36 +00:00
} else {
if (!q.swo->exec) {
ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
res = -1;
}
return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
}
} else { /* not found anywhere, see what happened */
ast_unlock_contexts();
/* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
switch (q.status) {
case STATUS_NO_CONTEXT:
if (!matching_action && !combined_find_spawn)
ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
break;
case STATUS_NO_EXTENSION:
if (!matching_action && !combined_find_spawn)
ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
break;
case STATUS_NO_PRIORITY:
if (!matching_action && !combined_find_spawn)
ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
break;
case STATUS_NO_LABEL:
if (context && !combined_find_spawn)
ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
break;
default:
ast_debug(1, "Shouldn't happen!\n");
}
return (matching_action) ? 0 : -1;
}
}
/*! \brief Find hint for given extension in context */
static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
{
struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
}
static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e;
ast_rdlock_contexts();
e = ast_hint_extension_nolock(c, context, exten);
ast_unlock_contexts();
return e;
}
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
{
switch (devstate) {
case AST_DEVICE_ONHOLD:
return AST_EXTENSION_ONHOLD;
case AST_DEVICE_BUSY:
return AST_EXTENSION_BUSY;
case AST_DEVICE_UNKNOWN:
return AST_EXTENSION_NOT_INUSE;
case AST_DEVICE_UNAVAILABLE:
case AST_DEVICE_INVALID:
return AST_EXTENSION_UNAVAILABLE;
case AST_DEVICE_RINGINUSE:
return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
case AST_DEVICE_RINGING:
return AST_EXTENSION_RINGING;
case AST_DEVICE_INUSE:
return AST_EXTENSION_INUSE;
case AST_DEVICE_NOT_INUSE:
return AST_EXTENSION_NOT_INUSE;
case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
break;
}
return AST_EXTENSION_NOT_INUSE;
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
/*!
* \internal
* \brief Parse out the presence portion of the hint string
*/
static char *parse_hint_presence(struct ast_str *hint_args)
{
char *copy = ast_strdupa(ast_str_buffer(hint_args));
char *tmp = "";
if ((tmp = strrchr(copy, ','))) {
*tmp = '\0';
tmp++;
} else {
return NULL;
}
ast_str_set(&hint_args, 0, "%s", tmp);
return ast_str_buffer(hint_args);
}
/*!
* \internal
* \brief Parse out the device portion of the hint string
*/
static char *parse_hint_device(struct ast_str *hint_args)
{
char *copy = ast_strdupa(ast_str_buffer(hint_args));
char *tmp;
if ((tmp = strrchr(copy, ','))) {
*tmp = '\0';
}
ast_str_set(&hint_args, 0, "%s", copy);
return ast_str_buffer(hint_args);
}
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
static void device_state_info_dt(void *obj)
{
struct ast_device_state_info *info = obj;
ao2_cleanup(info->causing_channel);
}
static struct ao2_container *alloc_device_state_info(void)
{
return ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
}
static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
{
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
char *cur;
char *rest;
struct ast_devstate_aggregate agg;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* One or more devices separated with a & character */
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
rest = parse_hint_device(hint_app);
ast_devstate_aggregate_init(&agg);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
while ((cur = strsep(&rest, "&"))) {
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
enum ast_device_state state = ast_device_state(cur);
ast_devstate_aggregate_add(&agg, state);
if (device_state_info) {
struct ast_device_state_info *obj;
obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
/* if failed we cannot add this device */
if (obj) {
obj->device_state = state;
strcpy(obj->device_name, cur);
ao2_link(device_state_info, obj);
ao2_ref(obj, -1);
}
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*! \brief Check state of extension by using hints */
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
{
struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!e || !hint_app) {
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
return ast_extension_state3(hint_app, device_state_info);
}
/*! \brief Return extension_state as string */
const char *ast_extension_state2str(int extension_state)
{
int i;
for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
if (extension_states[i].extension_state == extension_state)
return extension_states[i].text;
}
return "Unknown";
}
/*!
* \internal
* \brief Check extension state for an extension by using hint
*/
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
struct ao2_container *device_state_info)
{
struct ast_exten *e;
if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
return -1; /* No hint, return -1 */
}
if (e->exten[0] == '_') {
/* Create this hint on-the-fly */
ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
e->registrar);
if (!(e = ast_hint_extension(c, context, exten))) {
/* Improbable, but not impossible */
return -1;
}
}
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
return ast_extension_state2(e, device_state_info); /* Check all devices in the hint */
}
/*! \brief Check extension state for an extension by using hint */
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
{
return internal_extension_state_extended(c, context, exten, NULL);
}
/*! \brief Check extended extension state for an extension by using hint */
int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
struct ao2_container **device_state_info)
{
struct ao2_container *container = NULL;
int ret;
if (device_state_info) {
container = alloc_device_state_info();
}
ret = internal_extension_state_extended(c, context, exten, container);
if (ret < 0 && container) {
ao2_ref(container, -1);
container = NULL;
}
if (device_state_info) {
get_device_state_causing_channels(container);
*device_state_info = container;
}
return ret;
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
{
struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
char *presence_provider;
const char *app;
if (!e || !hint_app) {
return -1;
}
app = ast_get_extension_app(e);
if (ast_strlen_zero(app)) {
return -1;
}
ast_str_set(&hint_app, 0, "%s", app);
presence_provider = parse_hint_presence(hint_app);
if (ast_strlen_zero(presence_provider)) {
/* No presence string in the hint */
return 0;
}
return ast_presence_state(presence_provider, subtype, message);
}
int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
{
struct ast_exten *e;
if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
return -1; /* No hint, return -1 */
}
if (e->exten[0] == '_') {
/* Create this hint on-the-fly */
ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
e->registrar);
if (!(e = ast_hint_extension(c, context, exten))) {
/* Improbable, but not impossible */
return -1;
}
}
return extension_presence_state_helper(e, subtype, message);
}
static int execute_state_callback(ast_state_cb_type cb,
const char *context,
const char *exten,
void *data,
enum ast_state_cb_update_reason reason,
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
struct ast_hint *hint,
struct ao2_container *device_state_info)
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
{
int res = 0;
struct ast_state_cb_info info = { 0, };
info.reason = reason;
/* Copy over current hint data */
if (hint) {
ao2_lock(hint);
info.exten_state = hint->laststate;
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
info.device_state_info = device_state_info;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
info.presence_state = hint->last_presence_state;
if (!(ast_strlen_zero(hint->last_presence_subtype))) {
info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
} else {
info.presence_subtype = "";
}
if (!(ast_strlen_zero(hint->last_presence_message))) {
info.presence_message = ast_strdupa(hint->last_presence_message);
} else {
info.presence_message = "";
}
ao2_unlock(hint);
} else {
info.exten_state = AST_EXTENSION_REMOVED;
}
/* NOTE: The casts will not be needed for v10 and later */
res = cb((char *) context, (char *) exten, &info, data);
return res;
}
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
/*!
* /internal
* /brief Identify a channel for every device which is supposedly responsible for the device state.
*
* Especially when the device is ringing, the oldest ringing channel is chosen.
* For all other cases the first encountered channel in the specific state is chosen.
*/
static void get_device_state_causing_channels(struct ao2_container *c)
{
struct ao2_iterator iter;
struct ast_device_state_info *info;
struct ast_channel *chan;
if (!c || !ao2_container_count(c)) {
return;
}
iter = ao2_iterator_init(c, 0);
for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
enum ast_channel_state search_state = 0; /* prevent false uninit warning */
char match[AST_CHANNEL_NAME];
struct ast_channel_iterator *chan_iter;
struct timeval chantime = {0, }; /* prevent false uninit warning */
switch (info->device_state) {
case AST_DEVICE_RINGING:
case AST_DEVICE_RINGINUSE:
/* find ringing channel */
search_state = AST_STATE_RINGING;
break;
case AST_DEVICE_BUSY:
/* find busy channel */
search_state = AST_STATE_BUSY;
break;
case AST_DEVICE_ONHOLD:
case AST_DEVICE_INUSE:
/* find up channel */
search_state = AST_STATE_UP;
break;
case AST_DEVICE_UNKNOWN:
case AST_DEVICE_NOT_INUSE:
case AST_DEVICE_INVALID:
case AST_DEVICE_UNAVAILABLE:
case AST_DEVICE_TOTAL /* not a state */:
/* no channels are of interest */
continue;
}
/* iterate over all channels of the device */
snprintf(match, sizeof(match), "%s-", info->device_name);
chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
ast_channel_lock(chan);
/* this channel's state doesn't match */
if (search_state != ast_channel_state(chan)) {
ast_channel_unlock(chan);
continue;
}
/* any non-ringing channel will fit */
if (search_state != AST_STATE_RINGING) {
ast_channel_unlock(chan);
info->causing_channel = chan; /* is kept ref'd! */
break;
}
/* but we need the oldest ringing channel of the device to match with undirected pickup */
if (!info->causing_channel) {
chantime = ast_channel_creationtime(chan);
ast_channel_ref(chan); /* must ref it! */
info->causing_channel = chan;
} else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
chantime = ast_channel_creationtime(chan);
ast_channel_unref(info->causing_channel);
ast_channel_ref(chan); /* must ref it! */
info->causing_channel = chan;
}
ast_channel_unlock(chan);
}
ast_channel_iterator_destroy(chan_iter);
}
ao2_iterator_destroy(&iter);
}
Multiple revisions 399887,400138,400178,400180-400181 ........ r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line Minor performance bump by not allocate manager variable struct if we don't need it ........ r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines Stasis performance improvements This patch addresses several performance problems that were found in the initial performance testing of Asterisk 12. The Stasis dispatch object was allocated as an AO2 object, even though it has a very confined lifecycle. This was replaced with a straight ast_malloc(). The Stasis message router was spending an inordinate amount of time searching hash tables. In this case, most of our routers had 6 or fewer routes in them to begin with. This was replaced with an array that's searched linearly for the route. We more heavily rely on AO2 objects in Asterisk 12, and the memset() in ao2_ref() actually became noticeable on the profile. This was #ifdef'ed to only run when AO2_DEBUG was enabled. After being misled by an erroneous comment in taskprocessor.c during profiling, the wrong comment was removed. Review: https://reviewboard.asterisk.org/r/2873/ ........ r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines Taskprocessor optimization; switch Stasis to use taskprocessors This patch optimizes taskprocessor to use a semaphore for signaling, which the OS can do a better job at managing contention and waiting that we can with a mutex and condition. The taskprocessor execution was also slightly optimized to reduce the number of locks taken. The only observable difference in the taskprocessor implementation is that when the final reference to the taskprocessor goes away, it will execute all tasks to completion instead of discarding the unexecuted tasks. For systems where unnamed semaphores are not supported, a really simple semaphore implementation is provided. (Which gives identical performance as the original taskprocessor implementation). The way we ended up implementing Stasis caused the threadpool to be a burden instead of a boost to performance. This was switched to just use taskprocessors directly for subscriptions. Review: https://reviewboard.asterisk.org/r/2881/ ........ r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines Optimize how Stasis forwards are dispatched This patch optimizes how forwards are dispatched in Stasis. Originally, forwards were dispatched as subscriptions that are invoked on the publishing thread. This did not account for the vast number of forwards we would end up having in the system, and the amount of work it would take to walk though the forward subscriptions. This patch modifies Stasis so that rather than walking the tree of forwards on every dispatch, when forwards and subscriptions are changed, the subscriber list for every topic in the tree is changed. This has a couple of benefits. First, this reduces the workload of dispatching messages. It also reduces contention when dispatching to different topics that happen to forward to the same aggregation topic (as happens with all of the channel, bridge and endpoint topics). Since forwards are no longer subscriptions, the bulk of this patch is simply changing stasis_subscription objects to stasis_forward objects (which, admittedly, I should have done in the first place.) Since this required me to yet again put in a growing array, I finally abstracted that out into a set of ast_vector macros in asterisk/vector.h. Review: https://reviewboard.asterisk.org/r/2883/ ........ r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines Remove dispatch object allocation from Stasis publishing While looking for areas for performance improvement, I realized that an unused feature in Stasis was negatively impacting performance. When a message is sent to a subscriber, a dispatch object is allocated for the dispatch, containing the topic the message was published to, the subscriber the message is being sent to, and the message itself. The topic is actually unused by any subscriber in Asterisk today. And the subscriber is associated with the taskprocessor the message is being dispatched to. First, this patch removes the unused topic parameter from Stasis subscription callbacks. Second, this patch introduces the concept of taskprocessor local data, data that may be set on a taskprocessor and provided along with the data pointer when a task is pushed using the ast_taskprocessor_push_local() call. This allows the task to have both data specific to that taskprocessor, in addition to data specific to that invocation. With those two changes, the dispatch object can be removed completely, and the message is simply refcounted and sent directly to the taskprocessor. Review: https://reviewboard.asterisk.org/r/2884/ ........ Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
{
struct ast_device_state_message *dev_state;
struct ast_hint *hint;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
struct ast_str *hint_app;
struct ast_hintdevice *device;
struct ast_hintdevice *cmpdevice;
struct ao2_iterator *dev_iter;
struct ao2_iterator cb_iter;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
char context_name[AST_MAX_CONTEXT];
char exten_name[AST_MAX_EXTENSION];
if (ast_device_state_message_type() != stasis_message_type(msg)) {
return;
}
dev_state = stasis_message_data(msg);
if (dev_state->eid) {
/* ignore non-aggregate states */
return;
}
if (ao2_container_count(hintdevices) == 0) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* There are no hints monitoring devices. */
return;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
hint_app = ast_str_create(1024);
if (!hint_app) {
return;
}
cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
strcpy(cmpdevice->hintdevice, dev_state->device);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
dev_iter = ao2_t_callback(hintdevices,
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
OBJ_SEARCH_OBJECT | OBJ_MULTIPLE,
hintdevice_cmp_multiple,
cmpdevice,
"find devices in container");
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!dev_iter) {
ast_mutex_unlock(&context_merge_lock);
ast_free(hint_app);
return;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
}
for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
struct ast_state_cb *state_cb;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
int state;
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
int same_state;
struct ao2_container *device_state_info;
int first_extended_cb_call = 1;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!device->hint) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Should never happen. */
continue;
}
hint = device->hint;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_lock(hint);
if (!hint->exten) {
/* The extension has already been destroyed */
ao2_unlock(hint);
continue;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*
* Save off strings in case the hint extension gets destroyed
* while we are notifying the watchers.
*/
ast_copy_string(context_name,
ast_get_context_name(ast_get_extension_context(hint->exten)),
sizeof(context_name));
ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
sizeof(exten_name));
ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
ao2_unlock(hint);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*
* Get device state for this hint.
*
* NOTE: We cannot hold any locks while determining the hint
* device state or notifying the watchers without causing a
* deadlock. (conlock, hints, and hint)
*/
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
/* Make a container so state3 can fill it if we wish.
* If that failed we simply do not provide the extended state info.
*/
device_state_info = alloc_device_state_info();
state = ast_extension_state3(hint_app, device_state_info);
if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) {
ao2_cleanup(device_state_info);
continue;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Device state changed since last check - notify the watchers. */
hint->laststate = state; /* record we saw the change */
/* For general callbacks */
cb_iter = ao2_iterator_init(statecbs, 0);
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
execute_state_callback(state_cb->change_cb,
context_name,
exten_name,
state_cb->data,
AST_HINT_UPDATE_DEVICE,
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
hint,
NULL);
}
ao2_iterator_destroy(&cb_iter);
/* For extension callbacks */
/* extended callbacks are called when the state changed or when AST_STATE_RINGING is
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
* included. Normal callbacks are only called when the state changed.
*/
cb_iter = ao2_iterator_init(hint->callbacks, 0);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
if (state_cb->extended && first_extended_cb_call) {
/* Fill detailed device_state_info now that we know it is used by extd. callback */
first_extended_cb_call = 0;
get_device_state_causing_channels(device_state_info);
}
if (state_cb->extended || !same_state) {
execute_state_callback(state_cb->change_cb,
context_name,
exten_name,
state_cb->data,
AST_HINT_UPDATE_DEVICE,
hint,
state_cb->extended ? device_state_info : NULL);
}
}
ao2_iterator_destroy(&cb_iter);
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
ao2_cleanup(device_state_info);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_mutex_unlock(&context_merge_lock);
ao2_iterator_destroy(dev_iter);
ast_free(hint_app);
return;
}
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*!
* \internal
* \brief Destroy the given state callback object.
*
* \param doomed State callback to destroy.
*
* \return Nothing
*/
static void destroy_state_cb(void *doomed)
{
struct ast_state_cb *state_cb = doomed;
if (state_cb->destroy_cb) {
state_cb->destroy_cb(state_cb->id, state_cb->data);
}
}
/*!
* \internal
* \brief Add watcher for extension states with destructor
*/
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
static int extension_state_add_destroy(const char *context, const char *exten,
ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
{
struct ast_hint *hint;
struct ast_state_cb *state_cb;
struct ast_exten *e;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
int id;
/* If there's no context and extension: add callback to statecbs list */
if (!context && !exten) {
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/* Prevent multiple adds from adding the same change_cb at the same time. */
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_lock(statecbs);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/* Remove any existing change_cb. */
ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/* Now insert the change_cb */
if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(statecbs);
return -1;
}
state_cb->id = 0;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
state_cb->change_cb = change_cb;
state_cb->destroy_cb = destroy_cb;
state_cb->data = data;
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
state_cb->extended = extended;
ao2_link(statecbs, state_cb);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_ref(state_cb, -1);
ao2_unlock(statecbs);
return 0;
}
if (!context || !exten)
return -1;
/* This callback type is for only one hint, so get the hint */
e = ast_hint_extension(NULL, context, exten);
if (!e) {
return -1;
}
/* If this is a pattern, dynamically create a new extension for this
* particular match. Note that this will only happen once for each
* individual extension, because the pattern will no longer match first.
*/
if (e->exten[0] == '_') {
ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
e->registrar);
e = ast_hint_extension(NULL, context, exten);
if (!e || e->exten[0] == '_') {
return -1;
}
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Find the hint in the hints container */
ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
hint = ao2_find(hints, e, 0);
if (!hint) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
return -1;
}
/* Now insert the callback in the callback list */
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
ao2_ref(hint, -1);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
return -1;
}
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
do {
id = stateid++; /* Unique ID for this callback */
/* Do not allow id to ever be -1 or 0. */
} while (id == -1 || id == 0);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
state_cb->id = id;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
state_cb->change_cb = change_cb; /* Pointer to callback routine */
state_cb->destroy_cb = destroy_cb;
state_cb->data = data; /* Data for the callback */
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
state_cb->extended = extended;
ao2_link(hint->callbacks, state_cb);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_ref(state_cb, -1);
ao2_ref(hint, -1);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
return id;
}
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
/*! \brief Add watcher for extension states with destructor */
int ast_extension_state_add_destroy(const char *context, const char *exten,
ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
{
return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
}
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*! \brief Add watcher for extension states */
int ast_extension_state_add(const char *context, const char *exten,
ast_state_cb_type change_cb, void *data)
{
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
}
/*! \brief Add watcher for extended extension states with destructor */
int ast_extension_state_add_destroy_extended(const char *context, const char *exten,
ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
{
return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
}
/*! \brief Add watcher for extended extension states */
int ast_extension_state_add_extended(const char *context, const char *exten,
ast_state_cb_type change_cb, void *data)
{
return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
}
/*! \brief Find Hint by callback id */
static int find_hint_by_cb_id(void *obj, void *arg, int flags)
{
struct ast_state_cb *state_cb;
const struct ast_hint *hint = obj;
int *id = arg;
if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
ao2_ref(state_cb, -1);
return CMP_MATCH | CMP_STOP;
}
return 0;
}
/*! \brief ast_extension_state_del: Remove a watcher from the callback list */
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
{
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
struct ast_state_cb *p_cur;
int ret = -1;
if (!id) { /* id == 0 is a callback without extension */
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
if (!change_cb) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
return ret;
}
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
p_cur = ao2_find(statecbs, change_cb, OBJ_UNLINK);
if (p_cur) {
ret = 0;
ao2_ref(p_cur, -1);
}
} else { /* callback with extension, find the callback based on ID */
struct ast_hint *hint;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
if (hint) {
p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
if (p_cur) {
ret = 0;
ao2_ref(p_cur, -1);
}
ao2_ref(hint, -1);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
}
return ret;
}
static int hint_id_cmp(void *obj, void *arg, int flags)
{
const struct ast_state_cb *cb = obj;
int *id = arg;
return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*!
* \internal
* \brief Destroy the given hint object.
*
* \param obj Hint to destroy.
*
* \return Nothing
*/
static void destroy_hint(void *obj)
{
struct ast_hint *hint = obj;
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
int i;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (hint->callbacks) {
struct ast_state_cb *state_cb;
const char *context_name;
const char *exten_name;
if (hint->exten) {
context_name = ast_get_context_name(ast_get_extension_context(hint->exten));
exten_name = ast_get_extension_name(hint->exten);
hint->exten = NULL;
} else {
/* The extension has already been destroyed */
context_name = hint->context_name;
exten_name = hint->exten_name;
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
hint->laststate = AST_EXTENSION_DEACTIVATED;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
/* Notify with -1 and remove all callbacks */
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
execute_state_callback(state_cb->change_cb,
context_name,
exten_name,
state_cb->data,
AST_HINT_UPDATE_DEVICE,
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
hint,
NULL);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_ref(state_cb, -1);
}
ao2_ref(hint->callbacks, -1);
}
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
char *device = AST_VECTOR_GET(&hint->devices, i);
ast_free(device);
}
AST_VECTOR_FREE(&hint->devices);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
ast_free(hint->last_presence_subtype);
ast_free(hint->last_presence_message);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
}
/*! \brief Remove hint from extension */
static int ast_remove_hint(struct ast_exten *e)
{
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Cleanup the Notifys if hint is removed */
struct ast_hint *hint;
if (!e) {
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
hint = ao2_find(hints, e, OBJ_UNLINK);
if (!hint) {
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
remove_hintdevice(hint);
/*
* The extension is being destroyed so we must save some
* information to notify that the extension is deactivated.
*/
ao2_lock(hint);
ast_copy_string(hint->context_name,
ast_get_context_name(ast_get_extension_context(hint->exten)),
sizeof(hint->context_name));
ast_copy_string(hint->exten_name, ast_get_extension_name(hint->exten),
sizeof(hint->exten_name));
hint->exten = NULL;
ao2_unlock(hint);
ao2_ref(hint, -1);
return 0;
}
/*! \brief Add hint to hint list, check initial extension state */
static int ast_add_hint(struct ast_exten *e)
{
struct ast_hint *hint_new;
struct ast_hint *hint_found;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
char *message = NULL;
char *subtype = NULL;
int presence_state;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!e) {
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*
* We must create the hint we wish to add before determining if
* it is already in the hints container to avoid possible
* deadlock when getting the current extension state.
*/
hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
if (!hint_new) {
return -1;
}
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
AST_VECTOR_INIT(&hint_new->devices, 8);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Initialize new hint. */
hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
if (!hint_new->callbacks) {
ao2_ref(hint_new, -1);
return -1;
}
hint_new->exten = e;
if (strstr(e->app, "${") && e->exten[0] == '_') {
/* The hint is dynamic and hasn't been evaluted yet */
hint_new->laststate = AST_DEVICE_INVALID;
hint_new->last_presence_state = AST_PRESENCE_INVALID;
} else {
hint_new->laststate = ast_extension_state2(e, NULL);
if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
hint_new->last_presence_state = presence_state;
hint_new->last_presence_subtype = subtype;
hint_new->last_presence_message = message;
message = subtype = NULL;
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Prevent multiple add hints from adding the same hint at the same time. */
ao2_lock(hints);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Search if hint exists, do nothing */
hint_found = ao2_find(hints, e, 0);
if (hint_found) {
ao2_ref(hint_found, -1);
ao2_unlock(hints);
ao2_ref(hint_new, -1);
ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
ast_get_extension_name(e), ast_get_extension_app(e));
return -1;
}
/* Add new hint to the hints container */
ast_debug(2, "HINTS: Adding hint %s: %s\n",
ast_get_extension_name(e), ast_get_extension_app(e));
ao2_link(hints, hint_new);
if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
ast_get_extension_name(e),
ast_get_context_name(ast_get_extension_context(e)));
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* if not dynamic */
if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
struct ast_state_cb *state_cb;
struct ao2_iterator cb_iter;
/* For general callbacks */
cb_iter = ao2_iterator_init(statecbs, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
execute_state_callback(state_cb->change_cb,
ast_get_context_name(ast_get_extension_context(e)),
ast_get_extension_name(e),
state_cb->data,
AST_HINT_UPDATE_DEVICE,
hint_new,
NULL);
}
ao2_iterator_destroy(&cb_iter);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
ao2_ref(hint_new, -1);
return 0;
}
/*! \brief Change hint for an extension */
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
{
struct ast_hint *hint;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!oe || !ne) {
return -1;
}
ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*
* Unlink the hint from the hints container as the extension
* name (which is the hash value) could change.
*/
hint = ao2_find(hints, oe, OBJ_UNLINK);
if (!hint) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
return -1;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
remove_hintdevice(hint);
/* Update the hint and put it back in the hints container. */
ao2_lock(hint);
hint->exten = ne;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hint);
ao2_link(hints, hint);
if (add_hintdevice(hint, ast_get_extension_app(ne))) {
ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
ast_get_extension_name(ne),
ast_get_context_name(ast_get_extension_context(ne)));
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hints);
ao2_ref(hint, -1);
return 0;
}
/*! \brief Get hint for channel */
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e = ast_hint_extension(c, context, exten);
if (e) {
if (hint)
ast_copy_string(hint, ast_get_extension_app(e), hintsize);
if (name) {
const char *tmp = ast_get_extension_app_data(e);
if (tmp)
ast_copy_string(name, tmp, namesize);
}
return -1;
}
return 0;
}
/*! \brief Get hint for channel */
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e = ast_hint_extension(c, context, exten);
if (!e) {
return 0;
}
if (hint) {
ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
}
if (name) {
const char *tmp = ast_get_extension_app_data(e);
if (tmp) {
ast_str_set(name, namesize, "%s", tmp);
}
}
return -1;
}
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
}
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
}
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
{
return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
}
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
}
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
}
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
}
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
{
int autoloopflag;
int found;
int spawn_error;
ast_channel_lock(chan);
CDRs: fix a variety of dial status problems, h/hangup handler creating CDRs This patch fixes a number of small-ish problems that were noticed when witnessing the records that the FreePBX dialplan produces: (1) Mid-call events (as well as privacy options) have the ability to change the overall state of the Dial operation after the called party answers. This means that publishing the DialEnd event when the called party is premature; we have to wait for the execution of these subroutines to complete before we can signal the overall status of the DialEnd. This patch moves that publication and adds handlers for the mid-call events. (2) The AST_FLAG_OUTGOING channel flag is cleared if an after bridge goto datastore is detected. This flag was preventing CDRs from being recorded for all outbound channels that had a 'continue' option enabled on them by the Dial application. (3) The CDR engine now locks the 'Dial' application as being the CDR application if it detects that the current CDR has entered that app. This is similar to the logic that is done for Parking. In general, if we entered into Dial, then we want that CDR to record the application as such - this prevents pre-dial handlers, mid-call handlers, and other shenaniganry from changing the application value. (4) The CDR engine now checks for the AST_SOFTHANGUP_HANGUP_EXEC in more places to determine if the channel is in hangup logic or dead. In either case, we don't want to record changes in the channel. (5) The default option for "endbeforehexten" has been changed to "yes". In general, you don't want to see CDRs in the 'h' exten or in hangup logic. Since the semantics of that option changed in 12, it made sense to update the default value as well. (6) Finally, because we now have the ability to synchronize on the messages published to the CDR topic, on shutdown the CDR engine will now synchronize to the messages currently in flight. This helps to ensure that all in-flight CDRs are written before shutting down. (closes issue ASTERISK-23164) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3154 ........ Merged revisions 407084 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@407085 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-01-31 23:40:51 +00:00
/*
* Make sure that the channel is marked as hungup since we are
* going to run the h exten on it.
*/
ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);
/* Set h exten location */
if (context != ast_channel_context(chan)) {
ast_channel_context_set(chan, context);
}
ast_channel_exten_set(chan, "h");
ast_channel_priority_set(chan, 1);
/* Save autoloop flag */
autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
ast_channel_unlock(chan);
for (;;) {
spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
ast_channel_exten(chan), ast_channel_priority(chan),
S_COR(ast_channel_caller(chan)->id.number.valid,
ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
ast_channel_lock(chan);
if (spawn_error) {
/* The code after the loop needs the channel locked. */
break;
}
ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
ast_channel_unlock(chan);
}
if (found && spawn_error) {
/* Something bad happened, or a hangup has been requested. */
ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
ast_channel_context(chan), ast_channel_exten(chan),
ast_channel_priority(chan), ast_channel_name(chan));
ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
ast_channel_context(chan), ast_channel_exten(chan),
ast_channel_priority(chan), ast_channel_name(chan));
}
/* An "h" exten has been run, so indicate that one has been run. */
ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
/* Restore autoloop flag */
ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
ast_channel_unlock(chan);
}
/*!
* \internal
* \brief Publish a hangup handler related message to \ref stasis
*/
static void publish_hangup_handler_message(const char *action, struct ast_channel *chan, const char *handler)
{
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
blob = ast_json_pack("{s: s, s: s}",
"type", action,
"handler", S_OR(handler, ""));
if (!blob) {
return;
}
ast_channel_publish_blob(chan, ast_channel_hangup_handler_type(), blob);
}
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
struct ast_hangup_handler *h_handler;
ast_channel_lock(chan);
handlers = ast_channel_hangup_handlers(chan);
if (AST_LIST_EMPTY(handlers)) {
ast_channel_unlock(chan);
return 0;
}
/*
* Make sure that the channel is marked as hungup since we are
* going to run the hangup handlers on it.
*/
ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);
for (;;) {
handlers = ast_channel_hangup_handlers(chan);
h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
if (!h_handler) {
break;
}
publish_hangup_handler_message("run", chan, h_handler->args);
ast_channel_unlock(chan);
ast_app_exec_sub(NULL, chan, h_handler->args, 1);
ast_free(h_handler);
ast_channel_lock(chan);
}
ast_channel_unlock(chan);
return 1;
}
void ast_pbx_hangup_handler_init(struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
handlers = ast_channel_hangup_handlers(chan);
AST_LIST_HEAD_INIT_NOLOCK(handlers);
}
void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
struct ast_hangup_handler *h_handler;
ast_channel_lock(chan);
/* Get rid of each of the hangup handlers on the channel */
handlers = ast_channel_hangup_handlers(chan);
while ((h_handler = AST_LIST_REMOVE_HEAD(handlers, node))) {
ast_free(h_handler);
}
ast_channel_unlock(chan);
}
int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
struct ast_hangup_handler *h_handler;
ast_channel_lock(chan);
handlers = ast_channel_hangup_handlers(chan);
h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
if (h_handler) {
publish_hangup_handler_message("pop", chan, h_handler->args);
}
ast_channel_unlock(chan);
if (h_handler) {
ast_free(h_handler);
return 1;
}
return 0;
}
void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
{
struct ast_hangup_handler_list *handlers;
struct ast_hangup_handler *h_handler;
const char *expanded_handler;
if (ast_strlen_zero(handler)) {
return;
}
expanded_handler = ast_app_expand_sub_args(chan, handler);
if (!expanded_handler) {
return;
}
h_handler = ast_malloc(sizeof(*h_handler) + 1 + strlen(expanded_handler));
if (!h_handler) {
ast_free((char *) expanded_handler);
return;
}
strcpy(h_handler->args, expanded_handler);/* Safe */
ast_free((char *) expanded_handler);
ast_channel_lock(chan);
handlers = ast_channel_hangup_handlers(chan);
AST_LIST_INSERT_HEAD(handlers, h_handler, node);
publish_hangup_handler_message("push", chan, h_handler->args);
ast_channel_unlock(chan);
}
#define HANDLER_FORMAT "%-30s %s\n"
/*!
* \internal
* \brief CLI output the hangup handler headers.
* \since 11.0
*
* \param fd CLI file descriptor to use.
*
* \return Nothing
*/
static void ast_pbx_hangup_handler_headers(int fd)
{
ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
}
/*!
* \internal
* \brief CLI output the channel hangup handlers.
* \since 11.0
*
* \param fd CLI file descriptor to use.
* \param chan Channel to show hangup handlers.
*
* \return Nothing
*/
static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
{
struct ast_hangup_handler_list *handlers;
struct ast_hangup_handler *h_handler;
int first = 1;
ast_channel_lock(chan);
handlers = ast_channel_hangup_handlers(chan);
AST_LIST_TRAVERSE(handlers, h_handler, node) {
ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
first = 0;
}
ast_channel_unlock(chan);
}
/*
* \brief 'show hanguphandlers <channel>' CLI command implementation function...
*/
static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel *chan;
switch (cmd) {
case CLI_INIT:
e->command = "core show hanguphandlers";
e->usage =
"Usage: core show hanguphandlers <channel>\n"
" Show hangup handlers of a specified channel.\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
}
if (a->argc < 4) {
return CLI_SHOWUSAGE;
}
chan = ast_channel_get_by_name(a->argv[3]);
if (!chan) {
ast_cli(a->fd, "Channel does not exist.\n");
return CLI_FAILURE;
}
ast_pbx_hangup_handler_headers(a->fd);
ast_pbx_hangup_handler_show(a->fd, chan);
ast_channel_unref(chan);
return CLI_SUCCESS;
}
/*
* \brief 'show hanguphandlers all' CLI command implementation function...
*/
static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel_iterator *iter;
struct ast_channel *chan;
switch (cmd) {
case CLI_INIT:
e->command = "core show hanguphandlers all";
e->usage =
"Usage: core show hanguphandlers all\n"
" Show hangup handlers for all channels.\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
}
if (a->argc < 4) {
return CLI_SHOWUSAGE;
}
iter = ast_channel_iterator_all_new();
if (!iter) {
return CLI_FAILURE;
}
ast_pbx_hangup_handler_headers(a->fd);
for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
ast_pbx_hangup_handler_show(a->fd, chan);
}
ast_channel_iterator_destroy(iter);
return CLI_SUCCESS;
}
/*! helper function to set extension and priority */
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
{
ast_channel_lock(c);
ast_channel_exten_set(c, exten);
ast_channel_priority_set(c, pri);
ast_channel_unlock(c);
}
/*!
* \brief collect digits from the channel into the buffer.
* \param c, buf, buflen, pos
* \param waittime is in milliseconds
* \retval 0 on timeout or done.
* \retval -1 on error.
*/
static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
{
int digit;
buf[pos] = '\0'; /* make sure it is properly terminated */
while (ast_matchmore_extension(c, ast_channel_context(c), buf, 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
/* As long as we're willing to wait, and as long as it's not defined,
keep reading digits until we can't possibly get a right answer anymore. */
digit = ast_waitfordigit(c, waittime);
if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
Merged revisions 303549 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r303549 | russell | 2011-01-24 14:51:37 -0600 (Mon, 24 Jan 2011) | 45 lines Merged revisions 303548 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r303548 | russell | 2011-01-24 14:49:53 -0600 (Mon, 24 Jan 2011) | 38 lines Merged revisions 303546 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r303546 | russell | 2011-01-24 14:32:21 -0600 (Mon, 24 Jan 2011) | 31 lines Fix channel redirect out of MeetMe() and other issues with channel softhangup. Mantis issue #18585 reports that a channel redirect out of MeetMe() stopped working properly. This issue includes a patch that resolves the issue by removing a call to ast_check_hangup() from app_meetme.c. I left that in my patch, as it doesn't need to be there. However, the rest of the patch fixes this problem with or without the change to app_meetme. The key difference between what happens before and after this patch is the effect of the END_OF_Q control frame. After END_OF_Q is hit in ast_read(), ast_read() will return NULL. With the ast_check_hangup() removed, app_meetme sees this which causes it to exit as intended. Checking ast_check_hangup() caused app_meetme to exit earlier in the process, and the target of the redirect saw the condition where ast_read() returned NULL. Removing ast_check_hangup() works around the issue in app_meetme, but doesn't solve the issue if another application did the same thing. There are also other edge cases where if an application finishes at the same time that a redirect happens, the target of the redirect will think that the channel hung up. So, I made some changes in pbx.c to resolve it at a deeper level. There are already places that unset the SOFTHANGUP_ASYNCGOTO flag in an attempt to abort the hangup process. My patch extends this to remove the END_OF_Q frame from the channel's read queue, making the "abort hangup" more complete. This same technique was used in every place where a softhangup flag was cleared. (closes issue #18585) Reported by: oej Tested by: oej, wedhorn, russell Review: https://reviewboard.asterisk.org/r/1082/ ........ ................ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@303551 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-01-24 20:57:28 +00:00
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
} else {
if (!digit) /* No entry */
break;
if (digit < 0) /* Error, maybe a hangup */
return -1;
if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
buf[pos++] = digit;
buf[pos] = '\0';
}
waittime = ast_channel_pbx(c)->dtimeoutms;
}
}
return 0;
}
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
struct ast_pbx_args *args)
{
int found = 0; /* set if we find at least one match */
int res = 0;
int autoloopflag;
int error = 0; /* set an error conditions */
struct ast_pbx *pbx;
ast_callid callid;
/* A little initial setup here */
if (ast_channel_pbx(c)) {
ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
/* XXX and now what ? */
ast_free(ast_channel_pbx(c));
}
if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
return AST_PBX_FAILED;
}
callid = ast_read_threadstorage_callid();
/* If the thread isn't already associated with a callid, we should create that association. */
if (!callid) {
/* Associate new PBX thread with the channel call id if it is availble.
* If not, create a new one instead.
*/
callid = ast_channel_callid(c);
if (!callid) {
callid = ast_create_callid();
if (callid) {
ast_channel_lock(c);
ast_channel_callid_set(c, callid);
ast_channel_unlock(c);
}
}
ast_callid_threadassoc_add(callid);
callid = 0;
}
ast_channel_pbx_set(c, pbx);
/* Set reasonable defaults */
ast_channel_pbx(c)->rtimeoutms = 10000;
ast_channel_pbx(c)->dtimeoutms = 5000;
autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
if (ast_strlen_zero(ast_channel_exten(c))) {
/* If not successful fall back to 's' - but only if there is no given exten */
ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
/* XXX the original code used the existing priority in the call to
* ast_exists_extension(), and reset it to 1 afterwards.
* I believe the correct thing is to set it to 1 immediately.
*/
set_ext_pri(c, "s", 1);
}
for (;;) {
char dst_exten[256]; /* buffer to accumulate digits */
int pos = 0; /* XXX should check bounds */
int digit = 0;
int invalid = 0;
int timeout = 0;
/* No digits pressed yet */
dst_exten[pos] = '\0';
/* loop on priorities in this context/exten */
while (!(res = ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
&found, 1))) {
if (!ast_check_hangup(c)) {
ast_channel_priority_set(c, ast_channel_priority(c) + 1);
continue;
}
/* Check softhangup flags. */
if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
Merged revisions 303549 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r303549 | russell | 2011-01-24 14:51:37 -0600 (Mon, 24 Jan 2011) | 45 lines Merged revisions 303548 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r303548 | russell | 2011-01-24 14:49:53 -0600 (Mon, 24 Jan 2011) | 38 lines Merged revisions 303546 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r303546 | russell | 2011-01-24 14:32:21 -0600 (Mon, 24 Jan 2011) | 31 lines Fix channel redirect out of MeetMe() and other issues with channel softhangup. Mantis issue #18585 reports that a channel redirect out of MeetMe() stopped working properly. This issue includes a patch that resolves the issue by removing a call to ast_check_hangup() from app_meetme.c. I left that in my patch, as it doesn't need to be there. However, the rest of the patch fixes this problem with or without the change to app_meetme. The key difference between what happens before and after this patch is the effect of the END_OF_Q control frame. After END_OF_Q is hit in ast_read(), ast_read() will return NULL. With the ast_check_hangup() removed, app_meetme sees this which causes it to exit as intended. Checking ast_check_hangup() caused app_meetme to exit earlier in the process, and the target of the redirect saw the condition where ast_read() returned NULL. Removing ast_check_hangup() works around the issue in app_meetme, but doesn't solve the issue if another application did the same thing. There are also other edge cases where if an application finishes at the same time that a redirect happens, the target of the redirect will think that the channel hung up. So, I made some changes in pbx.c to resolve it at a deeper level. There are already places that unset the SOFTHANGUP_ASYNCGOTO flag in an attempt to abort the hangup process. My patch extends this to remove the END_OF_Q frame from the channel's read queue, making the "abort hangup" more complete. This same technique was used in every place where a softhangup flag was cleared. (closes issue #18585) Reported by: oej Tested by: oej, wedhorn, russell Review: https://reviewboard.asterisk.org/r/1082/ ........ ................ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@303551 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-01-24 20:57:28 +00:00
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
continue;
}
if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
set_ext_pri(c, "T", 1);
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
continue;
} else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
raise_exception(c, "ABSOLUTETIMEOUT", 1);
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
continue;
}
/* Call timed out with no special extension to jump to. */
error = 1;
break;
}
ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
ast_channel_exten(c), ast_channel_priority(c));
error = 1;
break;
} /* end while - from here on we can use 'break' to go out */
if (found && res) {
/* Something bad happened, or a hangup has been requested. */
if (strchr("0123456789ABCDEF*#", res)) {
ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
pos = 0;
dst_exten[pos++] = digit = res;
dst_exten[pos] = '\0';
} else if (res == AST_PBX_INCOMPLETE) {
ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
/* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
if (!ast_matchmore_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
invalid = 1;
} else {
ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
digit = 1;
pos = strlen(dst_exten);
}
} else {
ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
if ((res == AST_PBX_ERROR)
&& ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
/* if we are already on the 'e' exten, don't jump to it again */
if (!strcmp(ast_channel_exten(c), "e")) {
ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
error = 1;
} else {
raise_exception(c, "ERROR", 1);
continue;
}
}
if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
Merged revisions 303549 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r303549 | russell | 2011-01-24 14:51:37 -0600 (Mon, 24 Jan 2011) | 45 lines Merged revisions 303548 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r303548 | russell | 2011-01-24 14:49:53 -0600 (Mon, 24 Jan 2011) | 38 lines Merged revisions 303546 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r303546 | russell | 2011-01-24 14:32:21 -0600 (Mon, 24 Jan 2011) | 31 lines Fix channel redirect out of MeetMe() and other issues with channel softhangup. Mantis issue #18585 reports that a channel redirect out of MeetMe() stopped working properly. This issue includes a patch that resolves the issue by removing a call to ast_check_hangup() from app_meetme.c. I left that in my patch, as it doesn't need to be there. However, the rest of the patch fixes this problem with or without the change to app_meetme. The key difference between what happens before and after this patch is the effect of the END_OF_Q control frame. After END_OF_Q is hit in ast_read(), ast_read() will return NULL. With the ast_check_hangup() removed, app_meetme sees this which causes it to exit as intended. Checking ast_check_hangup() caused app_meetme to exit earlier in the process, and the target of the redirect saw the condition where ast_read() returned NULL. Removing ast_check_hangup() works around the issue in app_meetme, but doesn't solve the issue if another application did the same thing. There are also other edge cases where if an application finishes at the same time that a redirect happens, the target of the redirect will think that the channel hung up. So, I made some changes in pbx.c to resolve it at a deeper level. There are already places that unset the SOFTHANGUP_ASYNCGOTO flag in an attempt to abort the hangup process. My patch extends this to remove the END_OF_Q frame from the channel's read queue, making the "abort hangup" more complete. This same technique was used in every place where a softhangup flag was cleared. (closes issue #18585) Reported by: oej Tested by: oej, wedhorn, russell Review: https://reviewboard.asterisk.org/r/1082/ ........ ................ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@303551 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-01-24 20:57:28 +00:00
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
continue;
}
if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
set_ext_pri(c, "T", 1);
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
continue;
} else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
raise_exception(c, "ABSOLUTETIMEOUT", 1);
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
continue;
}
/* Call timed out with no special extension to jump to. */
}
error = 1;
break;
}
}
if (error)
break;
/*!\note
* We get here on a failure of some kind: non-existing extension or
* hangup. We have options, here. We can either catch the failure
* and continue, or we can drop out entirely. */
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
if (invalid
|| (ast_strlen_zero(dst_exten) &&
!ast_exists_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
/*!\note
* If there is no match at priority 1, it is not a valid extension anymore.
* Try to continue at "i" (for invalid) or "e" (for exception) or exit if
* neither exist.
*/
if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
set_ext_pri(c, "i", 1);
} else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
raise_exception(c, "INVALID", 1);
} else {
ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
error = 1; /* we know what to do with it */
break;
}
} else if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
/* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
Merged revisions 303549 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r303549 | russell | 2011-01-24 14:51:37 -0600 (Mon, 24 Jan 2011) | 45 lines Merged revisions 303548 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r303548 | russell | 2011-01-24 14:49:53 -0600 (Mon, 24 Jan 2011) | 38 lines Merged revisions 303546 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r303546 | russell | 2011-01-24 14:32:21 -0600 (Mon, 24 Jan 2011) | 31 lines Fix channel redirect out of MeetMe() and other issues with channel softhangup. Mantis issue #18585 reports that a channel redirect out of MeetMe() stopped working properly. This issue includes a patch that resolves the issue by removing a call to ast_check_hangup() from app_meetme.c. I left that in my patch, as it doesn't need to be there. However, the rest of the patch fixes this problem with or without the change to app_meetme. The key difference between what happens before and after this patch is the effect of the END_OF_Q control frame. After END_OF_Q is hit in ast_read(), ast_read() will return NULL. With the ast_check_hangup() removed, app_meetme sees this which causes it to exit as intended. Checking ast_check_hangup() caused app_meetme to exit earlier in the process, and the target of the redirect saw the condition where ast_read() returned NULL. Removing ast_check_hangup() works around the issue in app_meetme, but doesn't solve the issue if another application did the same thing. There are also other edge cases where if an application finishes at the same time that a redirect happens, the target of the redirect will think that the channel hung up. So, I made some changes in pbx.c to resolve it at a deeper level. There are already places that unset the SOFTHANGUP_ASYNCGOTO flag in an attempt to abort the hangup process. My patch extends this to remove the END_OF_Q frame from the channel's read queue, making the "abort hangup" more complete. This same technique was used in every place where a softhangup flag was cleared. (closes issue #18585) Reported by: oej Tested by: oej, wedhorn, russell Review: https://reviewboard.asterisk.org/r/1082/ ........ ................ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@303551 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-01-24 20:57:28 +00:00
ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
} else { /* keypress received, get more digits for a full extension */
int waittime = 0;
if (digit)
waittime = ast_channel_pbx(c)->dtimeoutms;
else if (!autofallthrough)
waittime = ast_channel_pbx(c)->rtimeoutms;
if (!waittime) {
const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
if (!status)
status = "UNKNOWN";
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
if (!strcasecmp(status, "CONGESTION"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "CHANUNAVAIL"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "BUSY"))
res = pbx_builtin_busy(c, "10");
error = 1; /* XXX disable message */
break; /* exit from the 'for' loop */
}
if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
break;
if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
timeout = 1;
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
if (!timeout
&& ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
set_ext_pri(c, dst_exten, 1);
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
} else {
/* No such extension */
if (!timeout && !ast_strlen_zero(dst_exten)) {
/* An invalid extension */
if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
set_ext_pri(c, "i", 1);
} else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
raise_exception(c, "INVALID", 1);
} else {
ast_log(LOG_WARNING,
"Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
dst_exten, ast_channel_context(c));
found = 1; /* XXX disable message */
break;
}
} else {
/* A simple timeout */
if (ast_exists_extension(c, ast_channel_context(c), "t", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
set_ext_pri(c, "t", 1);
} else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
raise_exception(c, "RESPONSETIMEOUT", 1);
} else {
ast_log(LOG_WARNING,
"Timeout, but no rule 't' or 'e' in context '%s'\n",
ast_channel_context(c));
found = 1; /* XXX disable message */
break;
}
}
}
}
}
if (!found && !error) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
}
if (!args || !args->no_hangup_chan) {
ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
if (!ast_test_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN)
&& ast_exists_extension(c, ast_channel_context(c), "h", 1,
S_COR(ast_channel_caller(c)->id.number.valid,
ast_channel_caller(c)->id.number.str, NULL))) {
ast_pbx_h_exten_run(c, ast_channel_context(c));
}
ast_pbx_hangup_handler_run(c);
}
ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
pbx_destroy(ast_channel_pbx(c));
ast_channel_pbx_set(c, NULL);
if (!args || !args->no_hangup_chan) {
ast_hangup(c);
}
return AST_PBX_SUCCESS;
}
/*!
* \brief Increase call count for channel
* \retval 0 on success
* \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached
*/
static int increase_call_count(const struct ast_channel *c)
{
int failed = 0;
double curloadavg;
#if defined(HAVE_SYSINFO)
long curfreemem;
struct sysinfo sys_info;
#endif
ast_mutex_lock(&maxcalllock);
if (ast_option_maxcalls) {
if (countcalls >= ast_option_maxcalls) {
ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", ast_option_maxcalls, ast_channel_name(c));
failed = -1;
}
}
if (ast_option_maxload) {
getloadavg(&curloadavg, 1);
if (curloadavg >= ast_option_maxload) {
ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", ast_option_maxload, ast_channel_name(c), curloadavg);
failed = -1;
}
}
#if defined(HAVE_SYSINFO)
if (option_minmemfree) {
if (!sysinfo(&sys_info)) {
/* make sure that the free system memory is above the configured low watermark
* convert the amount of freeram from mem_units to MB */
curfreemem = sys_info.freeram * sys_info.mem_unit;
curfreemem /= 1024 * 1024;
if (curfreemem < option_minmemfree) {
ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
failed = -1;
}
}
}
#endif
if (!failed) {
countcalls++;
totalcalls++;
}
ast_mutex_unlock(&maxcalllock);
return failed;
}
static void decrease_call_count(void)
{
ast_mutex_lock(&maxcalllock);
if (countcalls > 0)
countcalls--;
ast_mutex_unlock(&maxcalllock);
}
static void destroy_exten(struct ast_exten *e)
{
if (e->priority == PRIORITY_HINT)
ast_remove_hint(e);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (e->peer_table)
ast_hashtab_destroy(e->peer_table,0);
if (e->peer_label_table)
ast_hashtab_destroy(e->peer_label_table, 0);
if (e->datad)
e->datad(e->data);
ast_free(e);
}
static void *pbx_thread(void *data)
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
answer this channel and get it going.
*/
/* NOTE:
The launcher of this function _MUST_ increment 'countcalls'
before invoking the function; it will be decremented when the
PBX has finished running on the channel
*/
struct ast_channel *c = data;
__ast_pbx_run(c, NULL);
decrease_call_count();
pthread_exit(NULL);
return NULL;
}
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
{
pthread_t t;
if (!c) {
ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
return AST_PBX_FAILED;
}
if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
return AST_PBX_FAILED;
}
if (increase_call_count(c))
return AST_PBX_CALL_LIMIT;
/* Start a new thread, and get something handling this channel. */
if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
ast_log(LOG_WARNING, "Failed to create new channel thread\n");
decrease_call_count();
return AST_PBX_FAILED;
}
return AST_PBX_SUCCESS;
}
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
{
enum ast_pbx_result res = AST_PBX_SUCCESS;
if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
return AST_PBX_FAILED;
}
if (increase_call_count(c)) {
return AST_PBX_CALL_LIMIT;
}
res = __ast_pbx_run(c, args);
decrease_call_count();
return res;
}
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
{
return ast_pbx_run_args(c, NULL);
}
int ast_active_calls(void)
{
return countcalls;
}
int ast_processed_calls(void)
{
return totalcalls;
}
int pbx_set_autofallthrough(int newval)
{
int oldval = autofallthrough;
autofallthrough = newval;
return oldval;
}
int pbx_set_extenpatternmatchnew(int newval)
{
int oldval = extenpatternmatchnew;
extenpatternmatchnew = newval;
return oldval;
}
void pbx_set_overrideswitch(const char *newval)
{
if (overrideswitch) {
ast_free(overrideswitch);
}
if (!ast_strlen_zero(newval)) {
overrideswitch = ast_strdup(newval);
} else {
overrideswitch = NULL;
}
}
/*!
* \brief lookup for a context with a given name,
* \retval found context or NULL if not found.
*/
static struct ast_context *find_context(const char *context)
{
struct fake_context item;
ast_copy_string(item.name, context, sizeof(item.name));
return ast_hashtab_lookup(contexts_table, &item);
}
/*!
* \brief lookup for a context with a given name,
* \retval with conlock held if found.
* \retval NULL if not found.
*/
static struct ast_context *find_context_locked(const char *context)
{
struct ast_context *c;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct fake_context item;
ast_copy_string(item.name, context, sizeof(item.name));
ast_rdlock_contexts();
c = ast_hashtab_lookup(contexts_table, &item);
if (!c) {
ast_unlock_contexts();
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return c;
}
/*!
* \brief Remove included contexts.
* This function locks contexts list by &conlist, search for the right context
* structure, leave context list locked and call ast_context_remove_include2
* which removes include, unlock contexts list and return ...
*/
int ast_context_remove_include(const char *context, const char *include, const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) {
/* found, remove include from this context ... */
ret = ast_context_remove_include2(c, include, registrar);
ast_unlock_contexts();
}
return ret;
}
/*!
* \brief Locks context, remove included contexts, unlocks context.
* When we call this function, &conlock lock must be locked, because when
* we giving *con argument, some process can remove/change this context
* and after that there can be segfault.
*
* \retval 0 on success.
* \retval -1 on failure.
*/
int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
{
struct ast_include *i, *pi = NULL;
int ret = -1;
ast_wrlock_context(con);
/* find our include */
for (i = con->includes; i; pi = i, i = i->next) {
if (!strcmp(i->name, include) &&
(!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */
ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
if (pi)
pi->next = i->next;
else
con->includes = i->next;
/* free include and return */
ast_destroy_timing(&(i->timing));
ast_free(i);
ret = 0;
break;
}
}
ast_unlock_context(con);
return ret;
}
/*!
* \note This function locks contexts list by &conlist, search for the rigt context
* structure, leave context list locked and call ast_context_remove_switch2
* which removes switch, unlock contexts list and return ...
*/
int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
{
int ret = -1; /* default error return */
struct ast_context *c;
c = find_context_locked(context);
if (c) {
/* remove switch from this context ... */
ret = ast_context_remove_switch2(c, sw, data, registrar);
ast_unlock_contexts();
}
return ret;
}
/*!
* \brief This function locks given context, removes switch, unlock context and
* return.
* \note When we call this function, &conlock lock must be locked, because when
* we giving *con argument, some process can remove/change this context
* and after that there can be segfault.
*
*/
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
{
struct ast_sw *i;
int ret = -1;
ast_wrlock_context(con);
/* walk switches */
AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
(!registrar || !strcmp(i->registrar, registrar))) {
/* found, remove from list */
ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
AST_LIST_REMOVE_CURRENT(list);
ast_free(i); /* free switch and return */
ret = 0;
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
ast_unlock_context(con);
return ret;
}
/*! \note This function will lock conlock. */
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
{
return ast_context_remove_extension_callerid(context, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar);
}
int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
{
int ret = -1; /* default error return */
struct ast_context *c;
c = find_context_locked(context);
if (c) { /* ... remove extension ... */
ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid,
matchcallerid, registrar, 0);
ast_unlock_contexts();
}
return ret;
}
/*!
* \brief This functionc locks given context, search for the right extension and
* fires out all peer in this extensions with given priority. If priority
* is set to 0, all peers are removed. After that, unlock context and
* return.
* \note When do you want to call this function, make sure that &conlock is locked,
* because some process can handle with your *con context before you lock
* it.
*
*/
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
{
return ast_context_remove_extension_callerid2(con, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar, already_locked);
}
int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
{
struct ast_exten *exten, *prev_exten = NULL;
struct ast_exten *peer;
struct ast_exten ex, *exten2, *exten3;
char dummy_name[1024];
struct ast_exten *previous_peer = NULL;
struct ast_exten *next_peer = NULL;
int found = 0;
if (!already_locked)
ast_wrlock_context(con);
#ifdef NEED_DEBUG
ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
#endif
#ifdef CONTEXT_DEBUG
check_contexts(__FILE__, __LINE__);
#endif
/* find this particular extension */
ex.exten = dummy_name;
ex.matchcid = matchcallerid;
ex.cidmatch = callerid;
ast_copy_string(dummy_name, extension, sizeof(dummy_name));
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten = ast_hashtab_lookup(con->root_table, &ex);
if (exten) {
if (priority == 0) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
if (!exten2)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
x->exten = 0; /* get rid of what will become a bad pointer */
} else {
ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
}
}
} else {
ex.priority = priority;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
if (exten2) {
if (exten2->label) { /* if this exten has a label, remove that, too */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
if (!exten3)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
if (!exten3)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
if (exten2 == exten && exten2->peer) {
exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
ast_hashtab_insert_immediate(con->root_table, exten2->peer);
}
if (ast_hashtab_size(exten->peer_table) == 0) {
/* well, if the last priority of an exten is to be removed,
then, the extension is removed, too! */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
if (!exten3)
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
x->exten = 0; /* get rid of what will become a bad pointer */
}
}
}
} else {
ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
priority, exten->exten, con->name);
}
}
} else {
/* hmmm? this exten is not in this pattern tree? */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
extension, con->name);
}
#ifdef NEED_DEBUG
if (con->pattern_tree) {
ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
log_match_char_tree(con->pattern_tree, " ");
}
#endif
/* scan the extension list to find first matching extension-registrar */
for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
if (!strcmp(exten->exten, extension) &&
(!registrar || !strcmp(exten->registrar, registrar)) &&
(!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
break;
}
if (!exten) {
/* we can't find right extension */
if (!already_locked)
ast_unlock_context(con);
return -1;
}
/* scan the priority list to remove extension with exten->priority == priority */
for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
peer && !strcmp(peer->exten, extension) &&
(!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, callerid))) ;
peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
if ((priority == 0 || peer->priority == priority) &&
(!registrar || !strcmp(peer->registrar, registrar) )) {
found = 1;
/* we are first priority extension? */
if (!previous_peer) {
/*
* We are first in the priority chain, so must update the extension chain.
* The next node is either the next priority or the next extension
*/
struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
if (peer->peer) {
/* move the peer_table and peer_label_table down to the next peer, if
it is there */
peer->peer->peer_table = peer->peer_table;
peer->peer->peer_label_table = peer->peer_label_table;
peer->peer_table = NULL;
peer->peer_label_table = NULL;
}
if (!prev_exten) { /* change the root... */
con->root = next_node;
} else {
prev_exten->next = next_node; /* unlink */
}
if (peer->peer) { /* update the new head of the pri list */
peer->peer->next = peer->next;
}
} else { /* easy, we are not first priority in extension */
previous_peer->peer = peer->peer;
}
/* now, free whole priority extension */
destroy_exten(peer);
} else {
previous_peer = peer;
}
}
if (!already_locked)
ast_unlock_context(con);
return found ? 0 : -1;
}
/*!
* \note This function locks contexts list by &conlist, searches for the right context
* structure, and locks the macrolock mutex in that context.
* macrolock is used to limit a macro to be executed by one call at a time.
* \param context The context
*/
int ast_context_lockmacro(const char *context)
{
struct ast_context *c;
int ret = -1;
c = find_context_locked(context);
if (c) {
ast_unlock_contexts();
/* if we found context, lock macrolock */
ret = ast_mutex_lock(&c->macrolock);
}
return ret;
}
/*!
* \note This function locks contexts list by &conlist, searches for the right context
* structure, and unlocks the macrolock mutex in that context.
* macrolock is used to limit a macro to be executed by one call at a time.
* \param context The context
*/
int ast_context_unlockmacro(const char *context)
{
struct ast_context *c;
int ret = -1;
c = find_context_locked(context);
if (c) {
ast_unlock_contexts();
/* if we found context, unlock macrolock */
ret = ast_mutex_unlock(&c->macrolock);
}
return ret;
}
/*! \brief Dynamically register a new dial plan application */
int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
{
struct ast_app *tmp;
struct ast_app *cur;
int length;
#ifdef AST_XML_DOCS
char *tmpxml;
#endif
AST_RWLIST_WRLOCK(&apps);
cur = pbx_findapp_nolock(app);
if (cur) {
ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
AST_RWLIST_UNLOCK(&apps);
return -1;
}
length = sizeof(*tmp) + strlen(app) + 1;
if (!(tmp = ast_calloc(1, length))) {
AST_RWLIST_UNLOCK(&apps);
return -1;
}
if (ast_string_field_init(tmp, 128)) {
AST_RWLIST_UNLOCK(&apps);
ast_free(tmp);
return -1;
}
strcpy(tmp->name, app);
tmp->execute = execute;
tmp->module = mod;
#ifdef AST_XML_DOCS
/* Try to lookup the docs in our XML documentation database */
if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
/* load synopsis */
tmpxml = ast_xmldoc_build_synopsis("application", app, ast_module_name(tmp->module));
ast_string_field_set(tmp, synopsis, tmpxml);
ast_free(tmpxml);
/* load description */
tmpxml = ast_xmldoc_build_description("application", app, ast_module_name(tmp->module));
ast_string_field_set(tmp, description, tmpxml);
ast_free(tmpxml);
/* load syntax */
tmpxml = ast_xmldoc_build_syntax("application", app, ast_module_name(tmp->module));
ast_string_field_set(tmp, syntax, tmpxml);
ast_free(tmpxml);
/* load arguments */
tmpxml = ast_xmldoc_build_arguments("application", app, ast_module_name(tmp->module));
ast_string_field_set(tmp, arguments, tmpxml);
ast_free(tmpxml);
/* load seealso */
tmpxml = ast_xmldoc_build_seealso("application", app, ast_module_name(tmp->module));
ast_string_field_set(tmp, seealso, tmpxml);
ast_free(tmpxml);
tmp->docsrc = AST_XML_DOC;
} else {
#endif
ast_string_field_set(tmp, synopsis, synopsis);
ast_string_field_set(tmp, description, description);
#ifdef AST_XML_DOCS
tmp->docsrc = AST_STATIC_DOC;
}
#endif
/* Store in alphabetical order */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
if (strcasecmp(tmp->name, cur->name) < 0) {
AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
if (!cur)
AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
ast_verb(2, "Registered application '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, tmp->name));
AST_RWLIST_UNLOCK(&apps);
return 0;
}
/*
* Append to the list. We don't have a tail pointer because we need
* to scan the list anyways to check for duplicates during insertion.
*/
int ast_register_switch(struct ast_switch *sw)
{
struct ast_switch *tmp;
AST_RWLIST_WRLOCK(&switches);
AST_RWLIST_TRAVERSE(&switches, tmp, list) {
if (!strcasecmp(tmp->name, sw->name)) {
AST_RWLIST_UNLOCK(&switches);
ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
return -1;
}
}
AST_RWLIST_INSERT_TAIL(&switches, sw, list);
AST_RWLIST_UNLOCK(&switches);
return 0;
}
void ast_unregister_switch(struct ast_switch *sw)
{
AST_RWLIST_WRLOCK(&switches);
AST_RWLIST_REMOVE(&switches, sw, list);
AST_RWLIST_UNLOCK(&switches);
}
/*
* Help for CLI commands ...
*/
static void print_app_docs(struct ast_app *aa, int fd)
{
#ifdef AST_XML_DOCS
char *synopsis = NULL, *description = NULL, *arguments = NULL, *seealso = NULL;
if (aa->docsrc == AST_XML_DOC) {
synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
if (!synopsis || !description || !arguments || !seealso) {
goto free_docs;
}
ast_cli(fd, "\n"
"%s -= Info about application '%s' =- %s\n\n"
COLORIZE_FMT "\n"
"%s\n\n"
COLORIZE_FMT "\n"
"%s\n\n"
COLORIZE_FMT "\n"
"%s%s%s\n\n"
COLORIZE_FMT "\n"
"%s\n\n"
COLORIZE_FMT "\n"
"%s\n",
ast_term_color(COLOR_MAGENTA, 0), aa->name, ast_term_reset(),
COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"),
ast_term_color(COLOR_CYAN, 0), S_OR(aa->syntax, "Not available"), ast_term_reset(),
COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso);
free_docs:
ast_free(synopsis);
ast_free(description);
ast_free(arguments);
ast_free(seealso);
} else
#endif
{
ast_cli(fd, "\n"
"%s -= Info about application '%s' =- %s\n\n"
COLORIZE_FMT "\n"
COLORIZE_FMT "\n\n"
COLORIZE_FMT "\n"
COLORIZE_FMT "\n\n"
COLORIZE_FMT "\n"
COLORIZE_FMT "\n\n"
COLORIZE_FMT "\n"
COLORIZE_FMT "\n\n"
COLORIZE_FMT "\n"
COLORIZE_FMT "\n",
ast_term_color(COLOR_MAGENTA, 0), aa->name, ast_term_reset(),
COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"),
COLORIZE(COLOR_CYAN, 0, S_OR(aa->synopsis, "Not available")),
COLORIZE(COLOR_MAGENTA, 0, "[Description]"),
COLORIZE(COLOR_CYAN, 0, S_OR(aa->description, "Not available")),
COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"),
COLORIZE(COLOR_CYAN, 0, S_OR(aa->syntax, "Not available")),
COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"),
COLORIZE(COLOR_CYAN, 0, S_OR(aa->arguments, "Not available")),
COLORIZE(COLOR_MAGENTA, 0, "[See Also]"),
COLORIZE(COLOR_CYAN, 0, S_OR(aa->seealso, "Not available")));
}
}
/*
* \brief 'show application' CLI command implementation function...
*/
static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_app *aa;
int app, no_registered_app = 1;
switch (cmd) {
case CLI_INIT:
e->command = "core show application";
e->usage =
"Usage: core show application <application> [<application> [<application> [...]]]\n"
" Describes a particular application.\n";
return NULL;
case CLI_GENERATE:
/*
* There is a possibility to show informations about more than one
* application at one time. You can type 'show application Dial Echo' and
* you will see informations about these two applications ...
*/
return ast_complete_applications(a->line, a->word, a->n);
}
if (a->argc < 4) {
return CLI_SHOWUSAGE;
}
AST_RWLIST_RDLOCK(&apps);
AST_RWLIST_TRAVERSE(&apps, aa, list) {
/* Check for each app that was supplied as an argument */
for (app = 3; app < a->argc; app++) {
if (strcasecmp(aa->name, a->argv[app])) {
continue;
}
/* We found it! */
no_registered_app = 0;
print_app_docs(aa, a->fd);
}
}
AST_RWLIST_UNLOCK(&apps);
/* we found at least one app? no? */
if (no_registered_app) {
ast_cli(a->fd, "Your application(s) is (are) not registered\n");
return CLI_FAILURE;
}
return CLI_SUCCESS;
}
/*! \brief handle_show_hints: CLI support for listing registered dial plan hints */
static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_hint *hint;
int num = 0;
int watchers;
struct ao2_iterator i;
char buf[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2];
switch (cmd) {
case CLI_INIT:
e->command = "core show hints";
e->usage =
"Usage: core show hints\n"
" List registered hints.\n"
" Hint details are shown in five columns. In order from left to right, they are:\n"
" 1. Hint extension URI.\n"
" 2. List of mapped device or presence state identifiers.\n"
" 3. Current extension state. The aggregate of mapped device states.\n"
" 4. Current presence state for the mapped presence state provider.\n"
" 5. Watchers - number of subscriptions and other entities watching this hint.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (ao2_container_count(hints) == 0) {
ast_cli(a->fd, "There are no registered dialplan hints\n");
return CLI_SUCCESS;
}
/* ... we have hints ... */
ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
i = ao2_iterator_init(hints, 0);
for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_lock(hint);
if (!hint->exten) {
/* The extension has already been destroyed */
ao2_unlock(hint);
continue;
}
watchers = ao2_container_count(hint->callbacks);
sprintf(buf, "%s@%s",
ast_get_extension_name(hint->exten),
ast_get_context_name(ast_get_extension_context(hint->exten)));
ast_cli(a->fd, "%-20.20s: %-20.20s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
buf,
ast_get_extension_app(hint->exten),
ast_extension_state2str(hint->laststate),
ast_presence_state2str(hint->last_presence_state),
watchers);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hint);
num++;
}
ao2_iterator_destroy(&i);
ast_cli(a->fd, "----------------\n");
ast_cli(a->fd, "- %d hints registered\n", num);
return CLI_SUCCESS;
}
/*! \brief autocomplete for CLI command 'core show hint' */
static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
{
struct ast_hint *hint;
char *ret = NULL;
int which = 0;
int wordlen;
struct ao2_iterator i;
if (pos != 3)
return NULL;
wordlen = strlen(word);
/* walk through all hints */
i = ao2_iterator_init(hints, 0);
for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
ao2_lock(hint);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!hint->exten) {
/* The extension has already been destroyed */
ao2_unlock(hint);
continue;
}
if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
ret = ast_strdup(ast_get_extension_name(hint->exten));
ao2_unlock(hint);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_ref(hint, -1);
break;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hint);
}
ao2_iterator_destroy(&i);
return ret;
}
/*! \brief handle_show_hint: CLI support for listing registered dial plan hint */
static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_hint *hint;
int watchers;
int num = 0, extenlen;
struct ao2_iterator i;
char buf[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2];
switch (cmd) {
case CLI_INIT:
e->command = "core show hint";
e->usage =
"Usage: core show hint <exten>\n"
" List registered hint.\n"
" Hint details are shown in five columns. In order from left to right, they are:\n"
" 1. Hint extension URI.\n"
" 2. List of mapped device or presence state identifiers.\n"
" 3. Current extension state. The aggregate of mapped device states.\n"
" 4. Current presence state for the mapped presence state provider.\n"
" 5. Watchers - number of subscriptions and other entities watching this hint.\n";
return NULL;
case CLI_GENERATE:
return complete_core_show_hint(a->line, a->word, a->pos, a->n);
}
if (a->argc < 4)
return CLI_SHOWUSAGE;
if (ao2_container_count(hints) == 0) {
ast_cli(a->fd, "There are no registered dialplan hints\n");
return CLI_SUCCESS;
}
extenlen = strlen(a->argv[3]);
i = ao2_iterator_init(hints, 0);
for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
ao2_lock(hint);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
if (!hint->exten) {
/* The extension has already been destroyed */
ao2_unlock(hint);
continue;
}
if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
watchers = ao2_container_count(hint->callbacks);
sprintf(buf, "%s@%s",
ast_get_extension_name(hint->exten),
ast_get_context_name(ast_get_extension_context(hint->exten)));
ast_cli(a->fd, "%-20.20s: %-20.20s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
buf,
ast_get_extension_app(hint->exten),
ast_extension_state2str(hint->laststate),
ast_presence_state2str(hint->last_presence_state),
watchers);
num++;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_unlock(hint);
}
ao2_iterator_destroy(&i);
if (!num)
ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
else
ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
return CLI_SUCCESS;
}
/*! \brief handle_show_switches: CLI support for listing registered dial plan switches */
static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_switch *sw;
switch (cmd) {
case CLI_INIT:
e->command = "core show switches";
e->usage =
"Usage: core show switches\n"
" List registered switches\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
AST_RWLIST_RDLOCK(&switches);
if (AST_RWLIST_EMPTY(&switches)) {
AST_RWLIST_UNLOCK(&switches);
ast_cli(a->fd, "There are no registered alternative switches\n");
return CLI_SUCCESS;
}
ast_cli(a->fd, "\n -= Registered Asterisk Alternative Switches =-\n");
AST_RWLIST_TRAVERSE(&switches, sw, list)
ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
AST_RWLIST_UNLOCK(&switches);
return CLI_SUCCESS;
}
#if 0
/* This code can be used to test if the system survives running out of memory.
* It might be an idea to put this in only if ENABLE_AUTODESTRUCT_TESTS is enabled.
*
* If you want to test this, these Linux sysctl flags might be appropriate:
* vm.overcommit_memory = 2
* vm.swappiness = 0
*
* <@Corydon76-home> I envision 'core eat disk space' and 'core eat file descriptors' now
* <@mjordan> egads
* <@mjordan> it's literally the 'big red' auto-destruct button
* <@mjordan> if you were wondering who even builds such a thing.... well, now you know
* ...
* <@Corydon76-home> What about if they lived only if you defined TEST_FRAMEWORK? Shouldn't have those on production machines
* <@mjordan> I think accompanied with an update to one of our README files that "no, really, TEST_FRAMEWORK isn't for you", I'd be fine
*/
static char *handle_eat_memory(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
void **blocks;
int blocks_pos = 0;
const int blocks_max = 50000;
long long int allocated = 0;
int sizes[] = {
100 * 1024 * 1024,
100 * 1024,
2 * 1024,
400,
0
};
int i;
switch (cmd) {
case CLI_INIT:
/* To do: add method to free memory again? 5 minutes? */
e->command = "core eat memory";
e->usage =
"Usage: core eat memory\n"
" Eats all available memory so you can test if the system survives\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
blocks = ast_malloc(sizeof(void*) * blocks_max);
if (!blocks) {
ast_log(LOG_ERROR, "Already out of mem?\n");
return CLI_SUCCESS;
}
for (i = 0; sizes[i]; ++i) {
int alloc_size = sizes[i];
ast_log(LOG_WARNING, "Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
while (1) {
void *block;
if (blocks_pos >= blocks_max) {
ast_log(LOG_ERROR, "Memory buffer too small? Run me again :)\n");
break;
}
block = ast_malloc(alloc_size);
if (!block) {
break;
}
blocks[blocks_pos++] = block;
allocated += alloc_size;
}
}
/* No freeing of the mem! */
ast_log(LOG_WARNING, "Allocated %lld bytes total!\n", allocated);
return CLI_SUCCESS;
}
#endif
static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_app *aa;
int like = 0, describing = 0;
int total_match = 0; /* Number of matches in like clause */
int total_apps = 0; /* Number of apps registered */
static const char * const choices[] = { "like", "describing", NULL };
switch (cmd) {
case CLI_INIT:
e->command = "core show applications [like|describing]";
e->usage =
"Usage: core show applications [{like|describing} <text>]\n"
" List applications which are currently available.\n"
" If 'like', <text> will be a substring of the app name\n"
" If 'describing', <text> will be a substring of the description\n";
return NULL;
case CLI_GENERATE:
return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
}
AST_RWLIST_RDLOCK(&apps);
if (AST_RWLIST_EMPTY(&apps)) {
ast_cli(a->fd, "There are no registered applications\n");
AST_RWLIST_UNLOCK(&apps);
return CLI_SUCCESS;
}
/* core list applications like <keyword> */
if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
like = 1;
} else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
describing = 1;
}
/* core list applications describing <keyword1> [<keyword2>] [...] */
if ((!like) && (!describing)) {
ast_cli(a->fd, " -= Registered Asterisk Applications =-\n");
} else {
ast_cli(a->fd, " -= Matching Asterisk Applications =-\n");
}
AST_RWLIST_TRAVERSE(&apps, aa, list) {
int printapp = 0;
total_apps++;
if (like) {
if (strcasestr(aa->name, a->argv[4])) {
printapp = 1;
total_match++;
}
} else if (describing) {
if (aa->description) {
/* Match all words on command line */
int i;
printapp = 1;
for (i = 4; i < a->argc; i++) {
if (!strcasestr(aa->description, a->argv[i])) {
printapp = 0;
} else {
total_match++;
}
}
}
} else {
printapp = 1;
}
if (printapp) {
ast_cli(a->fd," %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
}
}
if ((!like) && (!describing)) {
ast_cli(a->fd, " -= %d Applications Registered =-\n",total_apps);
} else {
ast_cli(a->fd, " -= %d Applications Matching =-\n",total_match);
}
AST_RWLIST_UNLOCK(&apps);
return CLI_SUCCESS;
}
/*
* 'show dialplan' CLI command implementation functions ...
*/
static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
int state)
{
struct ast_context *c = NULL;
char *ret = NULL;
int which = 0;
int wordlen;
/* we are do completion of [exten@]context on second position only */
if (pos != 2)
return NULL;
ast_rdlock_contexts();
wordlen = strlen(word);
/* walk through all contexts and return the n-th match */
while ( (c = ast_walk_contexts(c)) ) {
if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
ret = ast_strdup(ast_get_context_name(c));
break;
}
}
ast_unlock_contexts();
return ret;
}
/*! \brief Counters for the show dialplan manager command */
struct dialplan_counters {
int total_items;
int total_context;
int total_exten;
int total_prio;
int context_existence;
int extension_existence;
};
/*! \brief helper function to print an extension */
static void print_ext(struct ast_exten *e, char * buf, int buflen)
{
int prio = ast_get_extension_priority(e);
if (prio == PRIORITY_HINT) {
snprintf(buf, buflen, "hint: %s",
ast_get_extension_app(e));
} else {
snprintf(buf, buflen, "%d. %s(%s)",
prio, ast_get_extension_app(e),
(!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
}
}
/* XXX not verified */
static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
{
struct ast_context *c = NULL;
int res = 0, old_total_exten = dpc->total_exten;
ast_rdlock_contexts();
/* walk all contexts ... */
while ( (c = ast_walk_contexts(c)) ) {
struct ast_exten *e;
struct ast_include *i;
struct ast_ignorepat *ip;
#ifndef LOW_MEMORY
char buf[1024], buf2[1024];
#else
char buf[256], buf2[256];
#endif
int context_info_printed = 0;
if (context && strcmp(ast_get_context_name(c), context))
continue; /* skip this one, name doesn't match */
dpc->context_existence = 1;
ast_rdlock_context(c);
/* are we looking for exten too? if yes, we print context
* only if we find our extension.
* Otherwise print context even if empty ?
* XXX i am not sure how the rinclude is handled.
* I think it ought to go inside.
*/
if (!exten) {
dpc->total_context++;
ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
ast_get_context_name(c), ast_get_context_registrar(c));
context_info_printed = 1;
}
/* walk extensions ... */
e = NULL;
while ( (e = ast_walk_context_extensions(c, e)) ) {
struct ast_exten *p;
if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
continue; /* skip, extension match failed */
dpc->extension_existence = 1;
/* may we print context info? */
if (!context_info_printed) {
dpc->total_context++;
if (rinclude) { /* TODO Print more info about rinclude */
ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
ast_get_context_name(c), ast_get_context_registrar(c));
} else {
ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
ast_get_context_name(c), ast_get_context_registrar(c));
}
context_info_printed = 1;
}
dpc->total_prio++;
/* write extension name and first peer */
if (e->matchcid == AST_EXT_MATCHCID_ON)
snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
else
snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
print_ext(e, buf2, sizeof(buf2));
ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
ast_get_extension_registrar(e));
dpc->total_exten++;
/* walk next extension peers */
p = e; /* skip the first one, we already got it */
while ( (p = ast_walk_extension_priorities(e, p)) ) {
const char *el = ast_get_extension_label(p);
dpc->total_prio++;
if (el)
snprintf(buf, sizeof(buf), " [%s]", el);
else
buf[0] = '\0';
print_ext(p, buf2, sizeof(buf2));
ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
ast_get_extension_registrar(p));
}
}
/* walk included and write info ... */
i = NULL;
while ( (i = ast_walk_context_includes(c, i)) ) {
snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
if (exten) {
/* Check all includes for the requested extension */
if (includecount >= AST_PBX_MAX_STACK) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
} else {
int dupe = 0;
int x;
for (x = 0; x < includecount; x++) {
if (!strcasecmp(includes[x], ast_get_include_name(i))) {
dupe++;
break;
}
}
if (!dupe) {
includes[includecount] = ast_get_include_name(i);
show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
} else {
ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
}
}
} else {
ast_cli(fd, " Include => %-45s [%s]\n",
buf, ast_get_include_registrar(i));
}
}
/* walk ignore patterns and write info ... */
ip = NULL;
while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
const char *ipname = ast_get_ignorepat_name(ip);
char ignorepat[AST_MAX_EXTENSION];
snprintf(buf, sizeof(buf), "'%s'", ipname);
snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
if (!exten || ast_extension_match(ignorepat, exten)) {
ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
buf, ast_get_ignorepat_registrar(ip));
}
}
if (!rinclude) {
struct ast_sw *sw = NULL;
while ( (sw = ast_walk_context_switches(c, sw)) ) {
snprintf(buf, sizeof(buf), "'%s/%s'",
ast_get_switch_name(sw),
ast_get_switch_data(sw));
ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
buf, ast_get_switch_registrar(sw));
}
}
ast_unlock_context(c);
/* if we print something in context, make an empty line */
if (context_info_printed)
ast_cli(fd, "\n");
}
ast_unlock_contexts();
return (dpc->total_exten == old_total_exten) ? -1 : res;
}
static int show_debug_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
{
struct ast_context *c = NULL;
int res = 0, old_total_exten = dpc->total_exten;
ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
ast_rdlock_contexts();
/* walk all contexts ... */
while ( (c = ast_walk_contexts(c)) ) {
int context_info_printed = 0;
if (context && strcmp(ast_get_context_name(c), context))
continue; /* skip this one, name doesn't match */
dpc->context_existence = 1;
if (!c->pattern_tree) {
/* Ignore check_return warning from Coverity for ast_exists_extension below */
ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
}
ast_rdlock_context(c);
dpc->total_context++;
ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
ast_get_context_name(c), ast_get_context_registrar(c));
context_info_printed = 1;
if (c->pattern_tree)
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
{
cli_match_char_tree(c->pattern_tree, " ", fd);
} else {
ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
ast_unlock_context(c);
/* if we print something in context, make an empty line */
if (context_info_printed)
ast_cli(fd, "\n");
}
ast_unlock_contexts();
return (dpc->total_exten == old_total_exten) ? -1 : res;
}
static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
char *exten = NULL, *context = NULL;
/* Variables used for different counters */
struct dialplan_counters counters;
const char *incstack[AST_PBX_MAX_STACK];
switch (cmd) {
case CLI_INIT:
e->command = "dialplan show";
e->usage =
"Usage: dialplan show [[exten@]context]\n"
" Show dialplan\n";
return NULL;
case CLI_GENERATE:
return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
}
memset(&counters, 0, sizeof(counters));
if (a->argc != 2 && a->argc != 3)
return CLI_SHOWUSAGE;
/* we obtain [exten@]context? if yes, split them ... */
if (a->argc == 3) {
if (strchr(a->argv[2], '@')) { /* split into exten & context */
context = ast_strdupa(a->argv[2]);
exten = strsep(&context, "@");
/* change empty strings to NULL */
if (ast_strlen_zero(exten))
exten = NULL;
} else { /* no '@' char, only context given */
context = ast_strdupa(a->argv[2]);
}
if (ast_strlen_zero(context))
context = NULL;
}
/* else Show complete dial plan, context and exten are NULL */
show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
/* check for input failure and throw some error messages */
if (context && !counters.context_existence) {
ast_cli(a->fd, "There is no existence of '%s' context\n", context);
return CLI_FAILURE;
}
if (exten && !counters.extension_existence) {
if (context)
ast_cli(a->fd, "There is no existence of %s@%s extension\n",
exten, context);
else
ast_cli(a->fd,
"There is no existence of '%s' extension in all contexts\n",
exten);
return CLI_FAILURE;
}
ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
counters.total_context, counters.total_context == 1 ? "context" : "contexts");
/* everything ok */
return CLI_SUCCESS;
}
/*! \brief Send ack once */
static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
char *exten = NULL, *context = NULL;
/* Variables used for different counters */
struct dialplan_counters counters;
const char *incstack[AST_PBX_MAX_STACK];
switch (cmd) {
case CLI_INIT:
e->command = "dialplan debug";
e->usage =
"Usage: dialplan debug [context]\n"
" Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
return NULL;
case CLI_GENERATE:
return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
}
memset(&counters, 0, sizeof(counters));
if (a->argc != 2 && a->argc != 3)
return CLI_SHOWUSAGE;
/* we obtain [exten@]context? if yes, split them ... */
/* note: we ignore the exten totally here .... */
if (a->argc == 3) {
if (strchr(a->argv[2], '@')) { /* split into exten & context */
context = ast_strdupa(a->argv[2]);
exten = strsep(&context, "@");
/* change empty strings to NULL */
if (ast_strlen_zero(exten))
exten = NULL;
} else { /* no '@' char, only context given */
context = ast_strdupa(a->argv[2]);
}
if (ast_strlen_zero(context))
context = NULL;
}
/* else Show complete dial plan, context and exten are NULL */
show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
/* check for input failure and throw some error messages */
if (context && !counters.context_existence) {
ast_cli(a->fd, "There is no existence of '%s' context\n", context);
return CLI_FAILURE;
}
ast_cli(a->fd,"-= %d %s. =-\n",
counters.total_context, counters.total_context == 1 ? "context" : "contexts");
/* everything ok */
return CLI_SUCCESS;
}
/*! \brief Send ack once */
static void manager_dpsendack(struct mansession *s, const struct message *m)
{
astman_send_listack(s, m, "DialPlan list will follow", "start");
}
/*! \brief Show dialplan extensions
* XXX this function is similar but not exactly the same as the CLI's
* show dialplan. Must check whether the difference is intentional or not.
*/
static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
const char *actionidtext, const char *context,
const char *exten, struct dialplan_counters *dpc,
struct ast_include *rinclude)
{
struct ast_context *c;
int res = 0, old_total_exten = dpc->total_exten;
if (ast_strlen_zero(exten))
exten = NULL;
if (ast_strlen_zero(context))
context = NULL;
ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
/* try to lock contexts */
if (ast_rdlock_contexts()) {
astman_send_error(s, m, "Failed to lock contexts");
ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
return -1;
}
c = NULL; /* walk all contexts ... */
while ( (c = ast_walk_contexts(c)) ) {
struct ast_exten *e;
struct ast_include *i;
struct ast_ignorepat *ip;
if (context && strcmp(ast_get_context_name(c), context) != 0)
continue; /* not the name we want */
dpc->context_existence = 1;
dpc->total_context++;
ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
if (ast_rdlock_context(c)) { /* failed to lock */
ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
continue;
}
/* XXX note- an empty context is not printed */
e = NULL; /* walk extensions in context */
while ( (e = ast_walk_context_extensions(c, e)) ) {
struct ast_exten *p;
/* looking for extension? is this our extension? */
if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
/* not the one we are looking for, continue */
ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
continue;
}
ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
dpc->extension_existence = 1;
dpc->total_exten++;
p = NULL; /* walk next extension peers */
while ( (p = ast_walk_extension_priorities(e, p)) ) {
int prio = ast_get_extension_priority(p);
dpc->total_prio++;
if (!dpc->total_items++)
manager_dpsendack(s, m);
astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
/* XXX maybe make this conditional, if p != e ? */
if (ast_get_extension_label(p))
astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
if (prio == PRIORITY_HINT) {
astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
} else {
astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
}
astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
}
}
i = NULL; /* walk included and write info ... */
while ( (i = ast_walk_context_includes(c, i)) ) {
if (exten) {
/* Check all includes for the requested extension */
manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
} else {
if (!dpc->total_items++)
manager_dpsendack(s, m);
astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
astman_append(s, "\r\n");
ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
}
}
ip = NULL; /* walk ignore patterns and write info ... */
while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
const char *ipname = ast_get_ignorepat_name(ip);
char ignorepat[AST_MAX_EXTENSION];
snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
if (!exten || ast_extension_match(ignorepat, exten)) {
if (!dpc->total_items++)
manager_dpsendack(s, m);
astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
astman_append(s, "\r\n");
}
}
if (!rinclude) {
struct ast_sw *sw = NULL;
while ( (sw = ast_walk_context_switches(c, sw)) ) {
if (!dpc->total_items++)
manager_dpsendack(s, m);
astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));
astman_append(s, "\r\n");
ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
}
}
ast_unlock_context(c);
}
ast_unlock_contexts();
if (dpc->total_exten == old_total_exten) {
ast_debug(3, "manager_show_dialplan: Found nothing new\n");
/* Nothing new under the sun */
return -1;
} else {
return res;
}
}
/*! \brief Manager listing of dial plan */
static int manager_show_dialplan(struct mansession *s, const struct message *m)
{
const char *exten, *context;
const char *id = astman_get_header(m, "ActionID");
char idtext[256];
/* Variables used for different counters */
struct dialplan_counters counters;
if (!ast_strlen_zero(id))
snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
else
idtext[0] = '\0';
memset(&counters, 0, sizeof(counters));
exten = astman_get_header(m, "Extension");
context = astman_get_header(m, "Context");
manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
if (!ast_strlen_zero(context) && !counters.context_existence) {
char errorbuf[BUFSIZ];
snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
astman_send_error(s, m, errorbuf);
return 0;
}
if (!ast_strlen_zero(exten) && !counters.extension_existence) {
char errorbuf[BUFSIZ];
if (!ast_strlen_zero(context))
snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
else
snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
astman_send_error(s, m, errorbuf);
return 0;
}
if (!counters.total_items) {
manager_dpsendack(s, m);
}
AMI: Make AMI actions that generate event lists consistent. * Made the following AMI actions use list API calls for consistency: Agents BridgeInfo BridgeList BridgeTechnologyList ConfbridgeLIst ConfbridgeLIstRooms CoreShowChannels DAHDIShowChannels DBGet DeviceStateList ExtensionStateList FAXSessions Hangup IAXpeerlist IAXpeers IAXregistry MeetmeList MeetmeListRooms MWIGet ParkedCalls Parkinglots PJSIPShowEndpoint PJSIPShowEndpoints PJSIPShowRegistrationsInbound PJSIPShowRegistrationsOutbound PJSIPShowResourceLists PJSIPShowSubscriptionsInbound PJSIPShowSubscriptionsOutbound PresenceStateList PRIShowSpans QueueStatus QueueSummary ShowDialPlan SIPpeers SIPpeerstatus SIPshowregistry SKINNYdevices SKINNYlines Status VoicemailUsersList * Incremented the AMI version to 2.7.0. * Changed astman_send_listack() to not use the listflag parameter and always set the value to "Start" so the start capitalization is consistent. i.e., The FAXSessions used "Start" while the rest of the system used "start". The corresponding complete event always used "Complete". * Fixed ami_show_resource_lists() "PJSIPShowResourceLists" to output the AMI ActionID for all of its list events. * Fixed off-nominal AMI protocol error in manager_bridge_info(), manager_parking_status_single_lot(), and manager_parking_status_all_lots(). Use of astman_send_error() after responding to the original AMI action request violates the action response pattern by sending two responses. * Fixed minor protocol error in action_getconfig() when no requested categories are found. Each line needs to be formatted as "Header: text". * Fixed off-nominal memory leak in manager_build_parked_call_string(). * Eliminated unnecessary use of RAII_VAR() in ami_subscription_detail(). ASTERISK-24049 #close Reported by: Jonathan Rose Review: https://reviewboard.asterisk.org/r/4315/ ........ Merged revisions 430434 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2015-01-09 18:16:54 +00:00
astman_send_list_complete_start(s, m, "ShowDialPlanComplete", counters.total_items);
astman_append(s,
"ListExtensions: %d\r\n"
"ListPriorities: %d\r\n"
AMI: Make AMI actions that generate event lists consistent. * Made the following AMI actions use list API calls for consistency: Agents BridgeInfo BridgeList BridgeTechnologyList ConfbridgeLIst ConfbridgeLIstRooms CoreShowChannels DAHDIShowChannels DBGet DeviceStateList ExtensionStateList FAXSessions Hangup IAXpeerlist IAXpeers IAXregistry MeetmeList MeetmeListRooms MWIGet ParkedCalls Parkinglots PJSIPShowEndpoint PJSIPShowEndpoints PJSIPShowRegistrationsInbound PJSIPShowRegistrationsOutbound PJSIPShowResourceLists PJSIPShowSubscriptionsInbound PJSIPShowSubscriptionsOutbound PresenceStateList PRIShowSpans QueueStatus QueueSummary ShowDialPlan SIPpeers SIPpeerstatus SIPshowregistry SKINNYdevices SKINNYlines Status VoicemailUsersList * Incremented the AMI version to 2.7.0. * Changed astman_send_listack() to not use the listflag parameter and always set the value to "Start" so the start capitalization is consistent. i.e., The FAXSessions used "Start" while the rest of the system used "start". The corresponding complete event always used "Complete". * Fixed ami_show_resource_lists() "PJSIPShowResourceLists" to output the AMI ActionID for all of its list events. * Fixed off-nominal AMI protocol error in manager_bridge_info(), manager_parking_status_single_lot(), and manager_parking_status_all_lots(). Use of astman_send_error() after responding to the original AMI action request violates the action response pattern by sending two responses. * Fixed minor protocol error in action_getconfig() when no requested categories are found. Each line needs to be formatted as "Header: text". * Fixed off-nominal memory leak in manager_build_parked_call_string(). * Eliminated unnecessary use of RAII_VAR() in ami_subscription_detail(). ASTERISK-24049 #close Reported by: Jonathan Rose Review: https://reviewboard.asterisk.org/r/4315/ ........ Merged revisions 430434 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2015-01-09 18:16:54 +00:00
"ListContexts: %d\r\n",
counters.total_exten, counters.total_prio, counters.total_context);
astman_send_list_complete_end(s);
/* everything ok */
return 0;
}
/*! \brief CLI support for listing global variables in a parseable way */
static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int i = 0;
struct ast_var_t *newvariable;
switch (cmd) {
case CLI_INIT:
e->command = "dialplan show globals";
e->usage =
"Usage: dialplan show globals\n"
" List current global dialplan variables and their values\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
ast_rwlock_rdlock(&globalslock);
AST_LIST_TRAVERSE (&globals, newvariable, entries) {
i++;
ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
}
ast_rwlock_unlock(&globalslock);
ast_cli(a->fd, "\n -- %d variable(s)\n", i);
return CLI_SUCCESS;
}
#ifdef AST_DEVMODE
static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_devstate_aggregate agg;
int i, j, exten, combined;
switch (cmd) {
case CLI_INIT:
e->command = "core show device2extenstate";
e->usage =
"Usage: core show device2extenstate\n"
" Lists device state to extension state combinations.\n";
case CLI_GENERATE:
return NULL;
}
for (i = 0; i < AST_DEVICE_TOTAL; i++) {
for (j = 0; j < AST_DEVICE_TOTAL; j++) {
ast_devstate_aggregate_init(&agg);
ast_devstate_aggregate_add(&agg, i);
ast_devstate_aggregate_add(&agg, j);
combined = ast_devstate_aggregate_result(&agg);
exten = ast_devstate_to_extenstate(combined);
ast_cli(a->fd, "\n Exten:%14s CombinedDevice:%12s Dev1:%12s Dev2:%12s", ast_extension_state2str(exten), ast_devstate_str(combined), ast_devstate_str(j), ast_devstate_str(i));
}
}
ast_cli(a->fd, "\n");
return CLI_SUCCESS;
}
#endif
/*! \brief CLI support for listing chanvar's variables in a parseable way */
static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
struct ast_channel *chan;
struct ast_var_t *var;
switch (cmd) {
case CLI_INIT:
e->command = "dialplan show chanvar";
e->usage =
"Usage: dialplan show chanvar <channel>\n"
" List current channel variables and their values\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
}
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
if (a->argc != e->args + 1) {
return CLI_SHOWUSAGE;
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
}
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
chan = ast_channel_get_by_name(a->argv[e->args]);
if (!chan) {
ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
return CLI_FAILURE;
}
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
ast_channel_lock(chan);
AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
}
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
ast_channel_unlock(chan);
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
ast_channel_unref(chan);
return CLI_SUCCESS;
}
static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
switch (cmd) {
case CLI_INIT:
e->command = "dialplan set global";
e->usage =
"Usage: dialplan set global <name> <value>\n"
" Set global dialplan variable <name> to <value>\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != e->args + 2)
return CLI_SHOWUSAGE;
pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
return CLI_SUCCESS;
}
static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel *chan;
const char *chan_name, *var_name, *var_value;
switch (cmd) {
case CLI_INIT:
e->command = "dialplan set chanvar";
e->usage =
"Usage: dialplan set chanvar <channel> <varname> <value>\n"
" Set channel variable <varname> to <value>\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
}
if (a->argc != e->args + 3)
return CLI_SHOWUSAGE;
chan_name = a->argv[e->args];
var_name = a->argv[e->args + 1];
var_value = a->argv[e->args + 2];
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
if (!(chan = ast_channel_get_by_name(chan_name))) {
ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
return CLI_FAILURE;
}
pbx_builtin_setvar_helper(chan, var_name, var_value);
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
chan = ast_channel_unref(chan);
ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
return CLI_SUCCESS;
}
static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int oldval = 0;
switch (cmd) {
case CLI_INIT:
e->command = "dialplan set extenpatternmatchnew true";
e->usage =
"Usage: dialplan set extenpatternmatchnew true|false\n"
" Use the NEW extension pattern matching algorithm, true or false.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
oldval = pbx_set_extenpatternmatchnew(1);
if (oldval)
ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
else
ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
return CLI_SUCCESS;
}
static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int oldval = 0;
switch (cmd) {
case CLI_INIT:
e->command = "dialplan set extenpatternmatchnew false";
e->usage =
"Usage: dialplan set extenpatternmatchnew true|false\n"
" Use the NEW extension pattern matching algorithm, true or false.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
oldval = pbx_set_extenpatternmatchnew(0);
if (!oldval)
ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
else
ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
return CLI_SUCCESS;
}
/*
* CLI entries for upper commands ...
*/
static struct ast_cli_entry pbx_cli[] = {
#if 0
AST_CLI_DEFINE(handle_eat_memory, "Eats all available memory"),
#endif
AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
#ifdef AST_DEVMODE
AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
#endif
AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
AST_CLI_DEFINE(handle_show_hangup_all, "Show hangup handlers of all channels"),
AST_CLI_DEFINE(handle_show_hangup_channel, "Show hangup handlers of a specified channel"),
AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
};
static void unreference_cached_app(struct ast_app *app)
{
struct ast_context *context = NULL;
struct ast_exten *eroot = NULL, *e = NULL;
ast_rdlock_contexts();
while ((context = ast_walk_contexts(context))) {
while ((eroot = ast_walk_context_extensions(context, eroot))) {
while ((e = ast_walk_extension_priorities(eroot, e))) {
if (e->cached_app == app)
e->cached_app = NULL;
}
}
}
ast_unlock_contexts();
return;
}
int ast_unregister_application(const char *app)
{
struct ast_app *cur;
int cmp;
AST_RWLIST_WRLOCK(&apps);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
cmp = strcasecmp(app, cur->name);
if (cmp > 0) {
continue;
}
if (!cmp) {
/* Found it. */
unreference_cached_app(cur);
AST_RWLIST_REMOVE_CURRENT(list);
ast_verb(2, "Unregistered application '%s'\n", cur->name);
ast_string_field_free_memory(cur);
ast_free(cur);
break;
}
/* Not in container. */
cur = NULL;
break;
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&apps);
return cur ? 0 : -1;
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
{
struct ast_context *tmp, **local_contexts;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct fake_context search;
int length = sizeof(struct ast_context) + strlen(name) + 1;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (!contexts_table) {
/* Protect creation of contexts_table from reentrancy. */
ast_wrlock_contexts();
if (!contexts_table) {
contexts_table = ast_hashtab_create(17,
ast_hashtab_compare_contexts,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
ast_hashtab_hash_contexts,
0);
}
ast_unlock_contexts();
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
ast_copy_string(search.name, name, sizeof(search.name));
if (!extcontexts) {
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
ast_rdlock_contexts();
local_contexts = &contexts;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp = ast_hashtab_lookup(contexts_table, &search);
if (tmp) {
tmp->refcount++;
ast_unlock_contexts();
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
return tmp;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
local_contexts = extcontexts;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp = ast_hashtab_lookup(exttable, &search);
if (tmp) {
tmp->refcount++;
return tmp;
}
}
if ((tmp = ast_calloc(1, length))) {
ast_rwlock_init(&tmp->lock);
ast_mutex_init(&tmp->macrolock);
strcpy(tmp->name, name);
tmp->root = NULL;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->root_table = NULL;
tmp->registrar = ast_strdup(registrar);
tmp->includes = NULL;
tmp->ignorepats = NULL;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->refcount = 1;
} else {
ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
if (!extcontexts) {
ast_unlock_contexts();
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
return NULL;
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (!extcontexts) {
tmp->next = *local_contexts;
*local_contexts = tmp;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
ast_unlock_contexts();
ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else {
tmp->next = *local_contexts;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (exttable)
ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
*local_contexts = tmp;
ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
return tmp;
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
struct store_hint {
char *context;
char *exten;
AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
int laststate;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
int last_presence_state;
char *last_presence_subtype;
char *last_presence_message;
AST_LIST_ENTRY(store_hint) list;
char data[1];
};
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
AST_LIST_HEAD_NOLOCK(store_hints, store_hint);
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
{
struct ast_include *i;
struct ast_ignorepat *ip;
struct ast_sw *sw;
ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
/* copy in the includes, switches, and ignorepats */
/* walk through includes */
for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
if (strcmp(ast_get_include_registrar(i), registrar) == 0)
continue; /* not mine */
ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
}
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
/* walk through switches */
for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
continue; /* not mine */
ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
}
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
/* walk thru ignorepats ... */
for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
continue; /* not mine */
ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
}
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* the purpose of this routine is to duplicate a context, with all its substructure,
except for any extens that have a matching registrar */
static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
{
struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
struct ast_hashtab_iter *exten_iter;
struct ast_hashtab_iter *prio_iter;
int insert_count = 0;
int first = 1;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* We'll traverse all the extensions/prios, and see which are not registrar'd with
the current registrar, and copy them to the new context. If the new context does not
exist, we'll create it "on demand". If no items are in this context to copy, then we'll
only create the empty matching context if the old one meets the criteria */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (context->root_table) {
exten_iter = ast_hashtab_start_traversal(context->root_table);
while ((exten_item=ast_hashtab_next(exten_iter))) {
if (new) {
new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
} else {
new_exten_item = NULL;
}
prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
while ((prio_item=ast_hashtab_next(prio_iter))) {
int res1;
char *dupdstr;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (new_exten_item) {
new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
} else {
new_prio_item = NULL;
}
if (strcmp(prio_item->registrar,registrar) == 0) {
continue;
}
/* make sure the new context exists, so we have somewhere to stick this exten/prio */
if (!new) {
new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
}
/* copy in the includes, switches, and ignorepats */
if (first) { /* but, only need to do this once */
context_merge_incls_swits_igps_other_registrars(new, context, registrar);
first = 0;
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (!new) {
ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
Fix a variety of memory leaks This patch addresses a number of memory leaks in a variety of modules that were found by a static analysis tool. A brief summary of the changes: * app_minivm: free ast_str objects on off nominal paths * app_page: free the ast_dial object if the requested channel technology cannot be appended to the dialing structure * app_queue: if a penalty rule failed to match any existing rule list names, the created rule would not be inserted and its memory would be leaked * app_read: dispose of the created silence detector in the presence of off nominal circumstances * app_voicemail: dispose of an allocated unique ID field for MWI event un-subscribe requests in off nominal paths; dispose of configuration objects when using the secret.conf option * chan_dahdi: dispose of the allocated frame produced by ast_dsp_process * chan_iax2: properly unref peer in CLI command "iax2 unregister" * chan_sip: dispose of the allocated frame produced by sip_rtp_read's call of ast_dsp_process; free memory in parse unit tests * func_dialgroup: properly deref ao2 object grhead in nominal path of dialgroup_read * func_odbc: free resultset in off nominal paths of odbc_read * cli: free match_list in off nominal paths of CLI match completion * config: free comment_buffer/list_buffer when configuration file load is unchanged; free the same buffers any time they were created and config files were processed * data: free XML nodes in various places * enum: free context buffer in off nominal paths * features: free ast_call_feature in off nominal paths of applicationmap config processing * netsock2: users of ast_sockaddr_resolve pass in an ast_sockaddr struct that is allocated by the method. Failures in ast_sockaddr_resolve could result in the users of the method not knowing whether or not the buffer was allocated. The method will now not allocate the ast_sockaddr struct if it will return failure. * pbx: cleanup hash table traversals in off nominal paths; free ignore pattern buffer if it already exists for the specified context * xmldoc: cleanup various nodes when we no longer need them * main/editline: various cleanup of pointers not being freed before being assigned to other memory, cleanup along off nominal paths * menuselect/mxml: cleanup of value buffer for an attribute when that attribute did not specify a value * res_calendar*: responses are allocated via the various *_request method returns and should not be allocated in the various write_event methods; ensure attendee buffer is freed if no data exists in the parsed node; ensure that calendar objects are de-ref'd appropriately * res_jabber: free buffer in off nominal path * res_musiconhold: close the DIR* object in off nominal paths * res_rtp_asterisk: if we run out of ports, close the rtp socket object and free the rtp object * res_srtp: if we fail to create the session in libsrtp, destroy the temporary ast_srtp object (issue ASTERISK-19665) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1922 ........ Merged revisions 366880 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 366881 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@366917 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-05-18 14:43:44 +00:00
ast_hashtab_end_traversal(prio_iter);
ast_hashtab_end_traversal(exten_iter);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
return; /* no sense continuing. */
}
/* we will not replace existing entries in the new context with stuff from the old context.
but, if this is because of some sort of registrar conflict, we ought to say something... */
dupdstr = ast_strdup(prio_item->data);
res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (!res1 && new_exten_item && new_prio_item){
ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
} else {
/* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
and no double frees take place, either! */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
insert_count++;
}
}
ast_hashtab_end_traversal(prio_iter);
}
ast_hashtab_end_traversal(exten_iter);
pbx_lua: fix regression with global sym export and context clash by pbx_config. ASTERISK-23818 (lua contexts being overwritten by contexts of the same name in pbx_config) surfaced because pbx_lua, having the AST_MODFLAG_GLOBAL_SYMBOLS set, was always force loaded before pbx_config. Since I couldn't find any reason for pbx_lua to export it's symbols to the rest of Asterisk, I simply changed the flag to AST_MODFLAG_DEFAULT. Problem solved. What I didn't realize was that the symbols need to be exported not because Asterisk needs them but because any external Lua modules like luasql.mysql need the base Lua language APIs exported (ASTERISK-17279). Back to ASTERISK-23818... It looks like there's an issue in pbx.c where context_merge was only merging includes, switches and ignore patterns if the context was already existing AND has extensions, or if the context was brand new. If pbx_lua is loaded before pbx_config, the context will exist BUT pbx_lua, being implemented as a switch, will never place extensions in it, just the switch statement. The result is that when pbx_config loads, it never merges the switch statement created by pbx_lua into the final context. This patch sets pbx_lua's modflag back to AST_MODFLAG_GLOBAL_SYMBOLS and adds an "else if" in context_merge that catches the case where an existing context has includes, switchs or ingore patterns but no actual extensions. ASTERISK-23818 #close Reported by: Dennis Guse Reported by: Timo Teräs Tested by: George Joseph Review: https://reviewboard.asterisk.org/r/3891/ ........ Merged revisions 420146 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 420147 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 420148 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@420149 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-08-06 16:12:26 +00:00
} else if (new) {
/* If the context existed but had no extensions, we still want to merge
* the includes, switches and ignore patterns.
*/
context_merge_incls_swits_igps_other_registrars(new, context, registrar);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
(strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
/* we could have given it the registrar of the other module who incremented the refcount,
but that's not available, so we give it the registrar we know about */
new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
/* copy in the includes, switches, and ignorepats */
context_merge_incls_swits_igps_other_registrars(new, context, registrar);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
}
}
/* XXX this does not check that multiple contexts are merged */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
{
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
double ft;
struct ast_context *tmp;
struct ast_context *oldcontextslist;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_hashtab *oldtable;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
struct store_hints hints_stored = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
struct store_hints hints_removed = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
struct store_hint *saved_hint;
struct ast_hint *hint;
struct ast_exten *exten;
int length;
struct ast_state_cb *thiscb;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_hashtab_iter *iter;
struct ao2_iterator i;
struct timeval begintime;
struct timeval writelocktime;
struct timeval endlocktime;
struct timeval enddeltime;
/*
* It is very important that this function hold the hints
* container lock _and_ the conlock during its operation; not
* only do we need to ensure that the list of contexts and
* extensions does not change, but also that no hint callbacks
* (watchers) are added or removed during the merge/delete
* process
*
* In addition, the locks _must_ be taken in this order, because
* there are already other code paths that use this order
*/
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
begintime = ast_tvnow();
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_mutex_lock(&context_merge_lock);/* Serialize ast_merge_contexts_and_delete */
ast_wrlock_contexts();
if (!contexts_table) {
/* Well, that's odd. There are no contexts. */
contexts_table = exttable;
contexts = *extcontexts;
ast_unlock_contexts();
ast_mutex_unlock(&context_merge_lock);
return;
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
iter = ast_hashtab_start_traversal(contexts_table);
while ((tmp = ast_hashtab_next(iter))) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
context_merge(extcontexts, exttable, tmp, registrar);
}
ast_hashtab_end_traversal(iter);
ao2_lock(hints);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
writelocktime = ast_tvnow();
/* preserve all watchers for hints */
i = ao2_iterator_init(hints, AO2_ITERATOR_DONTLOCK);
for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
if (ao2_container_count(hint->callbacks)) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ao2_lock(hint);
if (!hint->exten) {
/* The extension has already been destroyed. (Should never happen here) */
ao2_unlock(hint);
continue;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2
+ sizeof(*saved_hint);
if (!(saved_hint = ast_calloc(1, length))) {
ao2_unlock(hint);
continue;
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* This removes all the callbacks from the hint into saved_hint. */
while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
AST_LIST_INSERT_TAIL(&saved_hint->callbacks, thiscb, entry);
/*
* We intentionally do not unref thiscb to account for the
* non-ao2 reference in saved_hint->callbacks
*/
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
saved_hint->laststate = hint->laststate;
saved_hint->context = saved_hint->data;
strcpy(saved_hint->data, hint->exten->parent->name);
saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
strcpy(saved_hint->exten, hint->exten->exten);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
if (hint->last_presence_subtype) {
saved_hint->last_presence_subtype = ast_strdup(hint->last_presence_subtype);
}
if (hint->last_presence_message) {
saved_hint->last_presence_message = ast_strdup(hint->last_presence_message);
}
saved_hint->last_presence_state = hint->last_presence_state;
ao2_unlock(hint);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
}
}
ao2_iterator_destroy(&i);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* save the old table and list */
oldtable = contexts_table;
oldcontextslist = contexts;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* move in the new table and list */
contexts_table = exttable;
contexts = *extcontexts;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/*
* Restore the watchers for hints that can be found; notify
* those that cannot be restored.
*/
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_stored, list))) {
struct pbx_find_info q = { .stacklen = 0 };
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
PRIORITY_HINT, NULL, "", E_MATCH);
/*
* If this is a pattern, dynamically create a new extension for this
* particular match. Note that this will only happen once for each
* individual extension, because the pattern will no longer match first.
*/
if (exten && exten->exten[0] == '_') {
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_add_extension_nolock(exten->parent->name, 0, saved_hint->exten,
PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr,
exten->registrar);
/* rwlocks are not recursive locks */
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
exten = ast_hint_extension_nolock(NULL, saved_hint->context,
saved_hint->exten);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Find the hint in the hints container */
hint = exten ? ao2_find(hints, exten, 0) : NULL;
if (!hint) {
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*
* Notify watchers of this removed hint later when we aren't
* encumberd by so many locks.
*/
AST_LIST_INSERT_HEAD(&hints_removed, saved_hint, list);
} else {
ao2_lock(hint);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
ao2_link(hint->callbacks, thiscb);
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
/* Ref that we added when putting into saved_hint->callbacks */
ao2_ref(thiscb, -1);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
hint->laststate = saved_hint->laststate;
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
hint->last_presence_state = saved_hint->last_presence_state;
hint->last_presence_subtype = saved_hint->last_presence_subtype;
hint->last_presence_message = saved_hint->last_presence_message;
ao2_unlock(hint);
ao2_ref(hint, -1);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
/*
* The free of saved_hint->last_presence_subtype and
* saved_hint->last_presence_message is not necessary here.
*/
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
ast_free(saved_hint);
}
}
ao2_unlock(hints);
ast_unlock_contexts();
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/*
* Notify watchers of all removed hints with the same lock
* environment as device_state_cb().
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
*/
while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
/* this hint has been removed, notify the watchers */
while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
execute_state_callback(thiscb->change_cb,
saved_hint->context,
saved_hint->exten,
thiscb->data,
AST_HINT_UPDATE_DEVICE,
Extend extension state callbacks to have more information. Quote from review board: This patch extends the extension state callbacks so that monitoring channels (as chan_sip) get more information of the devices which are responsible for an extension state change. The additional information is needed by chan_sip to present names/numbers of the caller and callee in an early-state SIP notification. Users of extenstion state callback not interested in the additional information are not affected by the changes. Motivation: to present the involved party's name/number in an early-state nofification (used by the notified device as a pickup offer) one after another so that a user can see which call he will pick up in an undirected pickup. Such a pickup offer to a user shall indicate the same call (number/name-A calls number/name-B) as the call which would be picked up when an undirected pickup is executed. Users interested in additional state info must use the new functions ast_extension_state_add_extended() resp. ast_extension_state_add_destroy_extended() to register an extended state callback. When the callback is registered this way, an extra member device_state_info of struct ast_state_cb_info is passed to the callback in addition to the aggregated extension state. This container holds an object for every device of the monitored extension hint consisting of the device name, the device state and a channel reference to the channel which (presumably) caused the device state. The information is used by chan_sip for early-state notifications. When the state of a device changes and the new state contains AST_EVENT_RINGING, an early-state notification is sent to the subscribed devices with the caller/callee names/numbers of the oldest ringing channel of the monitored extension. The notified user may then invoke a direct pickup, which will pickup exactly this channel. Users of the old non-extended callbacks will only be called when the aggregated state did change (same behavior as before). Users of the extended callback will also be called when the state is unchanged but does contain AST_EVENT_RINGING. That could be the case if two channels are ringing at one device and one of them hangs up, so the aggregated state does not change. This way the monitoring channel can create a new early-state notification with the now ringing party-ids. Review: https://reviewboard.asterisk.org/r/2048 This contribution comes from Guenther Kelleter git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@370979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-08-09 14:52:16 +00:00
NULL,
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
NULL);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
/* Ref that we added when putting into saved_hint->callbacks */
ao2_ref(thiscb, -1);
}
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
ast_free(saved_hint->last_presence_subtype);
ast_free(saved_hint->last_presence_message);
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
ast_free(saved_hint);
}
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
ast_mutex_unlock(&context_merge_lock);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
endlocktime = ast_tvnow();
/*
* The old list and hashtab no longer are relevant, delete them
* while the rest of asterisk is now freely using the new stuff
* instead.
*/
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_destroy(oldtable, NULL);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
for (tmp = oldcontextslist; tmp; ) {
struct ast_context *next; /* next starting point */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
next = tmp->next;
__ast_internal_context_destroy(tmp);
tmp = next;
}
enddeltime = ast_tvnow();
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ft = ast_tvdiff_us(writelocktime, begintime);
ft /= 1000000.0;
ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ft = ast_tvdiff_us(endlocktime, writelocktime);
ft /= 1000000.0;
ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
ft = ast_tvdiff_us(enddeltime, endlocktime);
ft /= 1000000.0;
ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
ft = ast_tvdiff_us(enddeltime, begintime);
ft /= 1000000.0;
ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
}
/*
* errno values
* EBUSY - can't lock
* ENOENT - no existence of context
*/
int ast_context_add_include(const char *context, const char *include, const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) {
ret = ast_context_add_include2(c, include, registrar);
ast_unlock_contexts();
}
return ret;
}
/*! \brief Helper for get_range.
* return the index of the matching entry, starting from 1.
* If names is not supplied, try numeric values.
*/
static int lookup_name(const char *s, const char * const names[], int max)
{
int i;
if (names && *s > '9') {
for (i = 0; names[i]; i++) {
if (!strcasecmp(s, names[i])) {
return i;
}
}
}
/* Allow months and weekdays to be specified as numbers, as well */
if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
/* What the array offset would have been: "1" would be at offset 0 */
return i - 1;
}
return -1; /* error return */
}
/*! \brief helper function to return a range up to max (7, 12, 31 respectively).
* names, if supplied, is an array of names that should be mapped to numbers.
*/
static unsigned get_range(char *src, int max, const char * const names[], const char *msg)
{
int start, end; /* start and ending position */
unsigned int mask = 0;
char *part;
/* Check for whole range */
if (ast_strlen_zero(src) || !strcmp(src, "*")) {
return (1 << max) - 1;
}
while ((part = strsep(&src, "&"))) {
/* Get start and ending position */
char *endpart = strchr(part, '-');
if (endpart) {
*endpart++ = '\0';
}
/* Find the start */
if ((start = lookup_name(part, names, max)) < 0) {
ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
continue;
}
if (endpart) { /* find end of range */
if ((end = lookup_name(endpart, names, max)) < 0) {
ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
continue;
}
} else {
end = start;
}
/* Fill the mask. Remember that ranges are cyclic */
mask |= (1 << end); /* initialize with last element */
while (start != end) {
mask |= (1 << start);
if (++start >= max) {
start = 0;
}
}
}
return mask;
}
/*! \brief store a bitmask of valid times, one bit each 1 minute */
static void get_timerange(struct ast_timing *i, char *times)
{
char *endpart, *part;
int x;
int st_h, st_m;
int endh, endm;
int minute_start, minute_end;
/* start disabling all times, fill the fields with 0's, as they may contain garbage */
memset(i->minmask, 0, sizeof(i->minmask));
/* 1-minute per bit */
/* Star is all times */
if (ast_strlen_zero(times) || !strcmp(times, "*")) {
/* 48, because each hour takes 2 integers; 30 bits each */
for (x = 0; x < 48; x++) {
i->minmask[x] = 0x3fffffff; /* 30 bits */
}
return;
}
/* Otherwise expect a range */
while ((part = strsep(&times, "&"))) {
if (!(endpart = strchr(part, '-'))) {
if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
continue;
}
i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
continue;
}
*endpart++ = '\0';
/* why skip non digits? Mostly to skip spaces */
while (*endpart && !isdigit(*endpart)) {
endpart++;
}
if (!*endpart) {
ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
continue;
}
if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
continue;
}
if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
continue;
}
minute_start = st_h * 60 + st_m;
minute_end = endh * 60 + endm;
/* Go through the time and enable each appropriate bit */
for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
i->minmask[x / 30] |= (1 << (x % 30));
}
/* Do the last one */
i->minmask[x / 30] |= (1 << (x % 30));
}
/* All done */
return;
}
static const char * const days[] =
{
"sun",
"mon",
"tue",
"wed",
"thu",
"fri",
"sat",
NULL,
};
static const char * const months[] =
{
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
NULL,
};
/*! /brief Build timing
*
* /param i info
* /param info_in
*
*/
int ast_build_timing(struct ast_timing *i, const char *info_in)
{
char *info;
int j, num_fields, last_sep = -1;
i->timezone = NULL;
/* Check for empty just in case */
if (ast_strlen_zero(info_in)) {
return 0;
}
/* make a copy just in case we were passed a static string */
info = ast_strdupa(info_in);
/* count the number of fields in the timespec */
for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
if (info[j] == ',') {
last_sep = j;
num_fields++;
}
}
/* save the timezone, if it is specified */
if (num_fields == 5) {
i->timezone = ast_strdup(info + last_sep + 1);
}
/* Assume everything except time */
i->monthmask = 0xfff; /* 12 bits */
i->daymask = 0x7fffffffU; /* 31 bits */
i->dowmask = 0x7f; /* 7 bits */
/* on each call, use strsep() to move info to the next argument */
get_timerange(i, strsep(&info, "|,"));
if (info)
i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
if (info)
i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
if (info)
i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
return 1;
}
int ast_check_timing(const struct ast_timing *i)
{
return ast_check_timing2(i, ast_tvnow());
}
int ast_check_timing2(const struct ast_timing *i, const struct timeval tv)
{
struct ast_tm tm;
ast_localtime(&tv, &tm, i->timezone);
/* If it's not the right month, return */
if (!(i->monthmask & (1 << tm.tm_mon)))
return 0;
/* If it's not that time of the month.... */
/* Warning, tm_mday has range 1..31! */
if (!(i->daymask & (1 << (tm.tm_mday-1))))
return 0;
/* If it's not the right day of the week */
if (!(i->dowmask & (1 << tm.tm_wday)))
return 0;
/* Sanity check the hour just to be safe */
if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
ast_log(LOG_WARNING, "Insane time...\n");
return 0;
}
/* Now the tough part, we calculate if it fits
in the right time based on min/hour */
if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
return 0;
/* If we got this far, then we're good */
return 1;
}
int ast_destroy_timing(struct ast_timing *i)
{
if (i->timezone) {
ast_free(i->timezone);
i->timezone = NULL;
}
return 0;
}
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can't lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
int ast_context_add_include2(struct ast_context *con, const char *value,
const char *registrar)
{
struct ast_include *new_include;
char *c;
struct ast_include *i, *il = NULL; /* include, include_last */
int length;
char *p;
length = sizeof(struct ast_include);
length += 2 * (strlen(value) + 1);
/* allocate new include structure ... */
if (!(new_include = ast_calloc(1, length)))
return -1;
/* Fill in this structure. Use 'p' for assignments, as the fields
* in the structure are 'const char *'
*/
p = new_include->stuff;
new_include->name = p;
strcpy(p, value);
p += strlen(value) + 1;
new_include->rname = p;
strcpy(p, value);
/* Strip off timing info, and process if it is there */
if ( (c = strchr(p, ',')) ) {
*c++ = '\0';
new_include->hastime = ast_build_timing(&(new_include->timing), c);
}
new_include->next = NULL;
new_include->registrar = registrar;
ast_wrlock_context(con);
/* ... go to last include and check if context is already included too... */
for (i = con->includes; i; i = i->next) {
if (!strcasecmp(i->name, new_include->name)) {
ast_destroy_timing(&(new_include->timing));
ast_free(new_include);
ast_unlock_context(con);
errno = EEXIST;
return -1;
}
il = i;
}
/* ... include new context into context list, unlock, return */
if (il)
il->next = new_include;
else
con->includes = new_include;
ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
ast_unlock_context(con);
return 0;
}
/*
* errno values
* EBUSY - can't lock
* ENOENT - no existence of context
*/
int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) { /* found, add switch to this context */
ret = ast_context_add_switch2(c, sw, data, eval, registrar);
ast_unlock_contexts();
}
return ret;
}
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can't lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
int ast_context_add_switch2(struct ast_context *con, const char *value,
const char *data, int eval, const char *registrar)
{
struct ast_sw *new_sw;
struct ast_sw *i;
int length;
char *p;
length = sizeof(struct ast_sw);
length += strlen(value) + 1;
if (data)
length += strlen(data);
length++;
/* allocate new sw structure ... */
if (!(new_sw = ast_calloc(1, length)))
return -1;
/* ... fill in this structure ... */
p = new_sw->stuff;
new_sw->name = p;
strcpy(new_sw->name, value);
p += strlen(value) + 1;
new_sw->data = p;
if (data) {
strcpy(new_sw->data, data);
p += strlen(data) + 1;
} else {
strcpy(new_sw->data, "");
p++;
}
new_sw->eval = eval;
new_sw->registrar = registrar;
/* ... try to lock this context ... */
ast_wrlock_context(con);
/* ... go to last sw and check if context is already swd too... */
AST_LIST_TRAVERSE(&con->alts, i, list) {
if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
ast_free(new_sw);
ast_unlock_context(con);
errno = EEXIST;
return -1;
}
}
/* ... sw new context into context list, unlock, return */
AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
ast_unlock_context(con);
return 0;
}
/*
* EBUSY - can't lock
* ENOENT - there is not context existence
*/
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) {
ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
ast_unlock_contexts();
}
return ret;
}
int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
{
struct ast_ignorepat *ip, *ipl = NULL;
ast_wrlock_context(con);
for (ip = con->ignorepats; ip; ip = ip->next) {
if (!strcmp(ip->pattern, ignorepat) &&
(!registrar || (registrar == ip->registrar))) {
if (ipl) {
ipl->next = ip->next;
ast_free(ip);
} else {
con->ignorepats = ip->next;
ast_free(ip);
}
ast_unlock_context(con);
return 0;
}
ipl = ip;
}
ast_unlock_context(con);
errno = EINVAL;
return -1;
}
/*
* EBUSY - can't lock
* ENOENT - there is no existence of context
*/
int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) {
ret = ast_context_add_ignorepat2(c, value, registrar);
ast_unlock_contexts();
}
return ret;
}
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
{
struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
int length;
char *pattern;
length = sizeof(struct ast_ignorepat);
length += strlen(value) + 1;
if (!(ignorepat = ast_calloc(1, length)))
return -1;
/* The cast to char * is because we need to write the initial value.
* The field is not supposed to be modified otherwise. Also, gcc 4.2
* sees the cast as dereferencing a type-punned pointer and warns about
* it. This is the workaround (we're telling gcc, yes, that's really
* what we wanted to do).
*/
pattern = (char *) ignorepat->pattern;
strcpy(pattern, value);
ignorepat->next = NULL;
ignorepat->registrar = registrar;
ast_wrlock_context(con);
for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
ignorepatl = ignorepatc;
if (!strcasecmp(ignorepatc->pattern, value)) {
/* Already there */
ast_unlock_context(con);
Fix a variety of memory leaks This patch addresses a number of memory leaks in a variety of modules that were found by a static analysis tool. A brief summary of the changes: * app_minivm: free ast_str objects on off nominal paths * app_page: free the ast_dial object if the requested channel technology cannot be appended to the dialing structure * app_queue: if a penalty rule failed to match any existing rule list names, the created rule would not be inserted and its memory would be leaked * app_read: dispose of the created silence detector in the presence of off nominal circumstances * app_voicemail: dispose of an allocated unique ID field for MWI event un-subscribe requests in off nominal paths; dispose of configuration objects when using the secret.conf option * chan_dahdi: dispose of the allocated frame produced by ast_dsp_process * chan_iax2: properly unref peer in CLI command "iax2 unregister" * chan_sip: dispose of the allocated frame produced by sip_rtp_read's call of ast_dsp_process; free memory in parse unit tests * func_dialgroup: properly deref ao2 object grhead in nominal path of dialgroup_read * func_odbc: free resultset in off nominal paths of odbc_read * cli: free match_list in off nominal paths of CLI match completion * config: free comment_buffer/list_buffer when configuration file load is unchanged; free the same buffers any time they were created and config files were processed * data: free XML nodes in various places * enum: free context buffer in off nominal paths * features: free ast_call_feature in off nominal paths of applicationmap config processing * netsock2: users of ast_sockaddr_resolve pass in an ast_sockaddr struct that is allocated by the method. Failures in ast_sockaddr_resolve could result in the users of the method not knowing whether or not the buffer was allocated. The method will now not allocate the ast_sockaddr struct if it will return failure. * pbx: cleanup hash table traversals in off nominal paths; free ignore pattern buffer if it already exists for the specified context * xmldoc: cleanup various nodes when we no longer need them * main/editline: various cleanup of pointers not being freed before being assigned to other memory, cleanup along off nominal paths * menuselect/mxml: cleanup of value buffer for an attribute when that attribute did not specify a value * res_calendar*: responses are allocated via the various *_request method returns and should not be allocated in the various write_event methods; ensure attendee buffer is freed if no data exists in the parsed node; ensure that calendar objects are de-ref'd appropriately * res_jabber: free buffer in off nominal path * res_musiconhold: close the DIR* object in off nominal paths * res_rtp_asterisk: if we run out of ports, close the rtp socket object and free the rtp object * res_srtp: if we fail to create the session in libsrtp, destroy the temporary ast_srtp object (issue ASTERISK-19665) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1922 ........ Merged revisions 366880 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 366881 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@366917 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-05-18 14:43:44 +00:00
ast_free(ignorepat);
errno = EEXIST;
return -1;
}
}
if (ignorepatl)
ignorepatl->next = ignorepat;
else
con->ignorepats = ignorepat;
ast_unlock_context(con);
return 0;
}
int ast_ignore_pattern(const char *context, const char *pattern)
{
int ret = 0;
struct ast_context *con;
ast_rdlock_contexts();
con = ast_context_find(context);
if (con) {
struct ast_ignorepat *pat;
for (pat = con->ignorepats; pat; pat = pat->next) {
if (ast_extension_match(pat->pattern, pattern)) {
ret = 1;
break;
}
}
}
ast_unlock_contexts();
return ret;
}
/*
* ast_add_extension_nolock -- use only in situations where the conlock is already held
* ENOENT - no existence of context
*
*/
static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *), const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context(context);
if (c) {
ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
application, data, datad, registrar, 1);
}
return ret;
}
/*
* EBUSY - can't lock
* ENOENT - no existence of context
*
*/
int ast_add_extension(const char *context, int replace, const char *extension,
int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *), const char *registrar)
{
int ret = -1;
struct ast_context *c;
c = find_context_locked(context);
if (c) {
ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
application, data, datad, registrar);
ast_unlock_contexts();
}
return ret;
}
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
{
if (!chan)
return -1;
ast_channel_lock(chan);
if (!ast_strlen_zero(context))
ast_channel_context_set(chan, context);
if (!ast_strlen_zero(exten))
ast_channel_exten_set(chan, exten);
if (priority > -1) {
/* see flag description in channel.h for explanation */
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
--priority;
}
ast_channel_priority_set(chan, priority);
}
ast_channel_unlock(chan);
return 0;
}
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
{
struct ast_channel *newchan;
ast_channel_lock(chan);
/* Channels in a bridge or running a PBX can be sent directly to the specified destination */
if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
priority += 1;
}
ast_explicit_goto(chan, context, exten, priority);
ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
ast_channel_unlock(chan);
return 0;
}
ast_channel_unlock(chan);
/* Otherwise, we need to gain control of the channel first */
newchan = ast_channel_yank(chan);
if (!newchan) {
ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
return -1;
}
ast_explicit_goto(newchan, context, exten, priority);
if (ast_pbx_start(newchan)) {
ast_hangup(newchan);
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
return -1;
}
return 0;
}
int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
{
struct ast_channel *chan;
int res = -1;
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
if ((chan = ast_channel_get_by_name(channame))) {
res = ast_async_goto(chan, context, exten, priority);
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
chan = ast_channel_unref(chan);
}
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
return res;
}
/*! \brief copy a string skipping whitespace */
static int ext_strncpy(char *dst, const char *src, int len)
{
int count = 0;
int insquares = 0;
while (*src && (count < len - 1)) {
if (*src == '[') {
insquares = 1;
} else if (*src == ']') {
insquares = 0;
} else if (*src == ' ' && !insquares) {
src++;
continue;
}
*dst = *src;
dst++;
src++;
count++;
}
*dst = '\0';
return count;
}
/*!
* \brief add the extension in the priority chain.
* \retval 0 on success.
* \retval -1 on failure.
*/
static int add_priority(struct ast_context *con, struct ast_exten *tmp,
struct ast_exten *el, struct ast_exten *e, int replace)
{
struct ast_exten *ep;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct ast_exten *eh=e;
int repeated_label = 0; /* Track if this label is a repeat, assume no. */
for (ep = NULL; e ; ep = e, e = e->peer) {
if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
if (strcmp(e->exten, tmp->exten)) {
ast_log(LOG_WARNING,
"Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
tmp->exten, tmp->priority, con->name, tmp->label, e->exten, e->priority);
} else {
ast_log(LOG_WARNING,
"Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
tmp->exten, tmp->priority, con->name, tmp->label, e->priority);
}
repeated_label = 1;
}
if (e->priority >= tmp->priority) {
break;
}
}
if (repeated_label) { /* Discard the label since it's a repeat. */
tmp->label = NULL;
}
if (!e) { /* go at the end, and ep is surely set because the list is not empty */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_table, tmp);
if (tmp->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_label_table, tmp);
}
ep->peer = tmp;
return 0; /* success */
}
if (e->priority == tmp->priority) {
/* Can't have something exactly the same. Is this a
replacement? If so, replace, otherwise, bonk. */
if (!replace) {
if (strcmp(e->exten, tmp->exten)) {
ast_log(LOG_WARNING,
"Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
tmp->exten, tmp->priority, con->name, e->exten);
} else {
ast_log(LOG_WARNING,
"Unable to register extension '%s' priority %d in '%s', already in use\n",
tmp->exten, tmp->priority, con->name);
}
return -1;
}
/* we are replacing e, so copy the link fields and then update
* whoever pointed to e to point to us
*/
tmp->next = e->next; /* not meaningful if we are not first in the peer list */
tmp->peer = e->peer; /* always meaningful */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (ep) { /* We're in the peer list, just insert ourselves */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
if (e->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_table,tmp);
if (tmp->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_label_table,tmp);
}
ep->peer = tmp;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else if (el) { /* We're the first extension. Take over e's functions */
struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->peer_table = e->peer_table;
tmp->peer_label_table = e->peer_label_table;
ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
ast_hashtab_insert_safe(tmp->peer_table,tmp);
if (e->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
}
if (tmp->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(con->root_table, e);
ast_hashtab_insert_safe(con->root_table, tmp);
el->next = tmp;
/* The pattern trie points to this exten; replace the pointer,
and all will be well */
if (x) { /* if the trie isn't formed yet, don't sweat this */
if (x->exten) { /* this test for safety purposes */
x->exten = tmp; /* replace what would become a bad pointer */
} else {
ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
}
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else { /* We're the very first extension. */
struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(con->root_table, e);
ast_hashtab_insert_safe(con->root_table, tmp);
tmp->peer_table = e->peer_table;
tmp->peer_label_table = e->peer_label_table;
ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
ast_hashtab_insert_safe(tmp->peer_table, tmp);
if (e->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
}
if (tmp->label) {
ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(con->root_table, e);
ast_hashtab_insert_safe(con->root_table, tmp);
con->root = tmp;
/* The pattern trie points to this exten; replace the pointer,
and all will be well */
if (x) { /* if the trie isn't formed yet; no problem */
if (x->exten) { /* this test for safety purposes */
x->exten = tmp; /* replace what would become a bad pointer */
} else {
ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
}
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e,tmp);
/* Destroy the old one */
if (e->datad)
e->datad(e->data);
ast_free(e);
} else { /* Slip ourselves in just before e */
tmp->peer = e;
tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (ep) { /* Easy enough, we're just in the peer list */
if (tmp->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_label_table, tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(eh->peer_table, tmp);
ep->peer = tmp;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else { /* we are the first in some peer list, so link in the ext list */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->peer_table = e->peer_table;
tmp->peer_label_table = e->peer_label_table;
e->peer_table = 0;
e->peer_label_table = 0;
ast_hashtab_insert_safe(tmp->peer_table, tmp);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (tmp->label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_remove_object_via_lookup(con->root_table, e);
ast_hashtab_insert_safe(con->root_table, tmp);
if (el)
el->next = tmp; /* in the middle... */
else
con->root = tmp; /* ... or at the head */
e->next = NULL; /* e is no more at the head, so e->next must be reset */
}
/* And immediately return success. */
if (tmp->priority == PRIORITY_HINT) {
ast_add_hint(tmp);
}
}
return 0;
}
/*! \brief
* Main interface to add extensions to the list for out context.
*
* We sort extensions in order of matching preference, so that we can
* stop the search as soon as we find a suitable match.
* This ordering also takes care of wildcards such as '.' (meaning
* "one or more of any character") and '!' (which is 'earlymatch',
* meaning "zero or more of any character" but also impacts the
* return value from CANMATCH and EARLYMATCH.
*
* The extension match rules defined in the devmeeting 2006.05.05 are
* quite simple: WE SELECT THE LONGEST MATCH.
* In detail, "longest" means the number of matched characters in
* the extension. In case of ties (e.g. _XXX and 333) in the length
* of a pattern, we give priority to entries with the smallest cardinality
* (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
* while the latter has 7, etc.
* In case of same cardinality, the first element in the range counts.
* If we still have a tie, any final '!' will make this as a possibly
* less specific pattern.
*
* EBUSY - can't lock
* EEXIST - extension with the same priority exist and no replace is set
*
*/
int ast_add_extension2(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
const char *registrar)
{
return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
application, data, datad, registrar, 1);
}
int ast_add_extension2_nolock(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
const char *registrar)
{
return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
application, data, datad, registrar, 0);
}
/*!
* \brief Same as ast_add_extension2() but controls the context locking.
*
* \details
* Does all the work of ast_add_extension2, but adds an arg to
* determine if context locking should be done.
*/
static int ast_add_extension2_lockopt(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
const char *registrar, int lock_context)
{
/*
* Sort extensions (or patterns) according to the rules indicated above.
* These are implemented by the function ext_cmp()).
* All priorities for the same ext/pattern/cid are kept in a list,
* using the 'peer' field as a link field..
*/
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
struct ast_exten *tmp, *tmp2, *e, *el = NULL;
int res;
int length;
char *p;
char expand_buf[VAR_BUF_SIZE];
struct ast_exten dummy_exten = {0};
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
char dummy_name[1024];
if (ast_strlen_zero(extension)) {
ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
con->name);
return -1;
}
/* If we are adding a hint evalulate in variables and global variables */
if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
struct ast_channel *c = ast_dummy_channel_alloc();
Merged revisions 337974 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500 (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011) | 30 lines Fix deadlock when using dummy channels. Dummy channels created by ast_dummy_channel_alloc() should be destoyed by ast_channel_unref(). Using ast_channel_release() needlessly grabs the channel container lock and can cause a deadlock as a result. * Analyzed use of ast_dummy_channel_alloc() and made use ast_channel_unref() when done with the dummy channel. (Primary reason for the reported deadlock.) * Made app_dial.c:dial_exec_full() not call ast_call() holding any channel locks. Chan_local could not perform deadlock avoidance correctly. (Potential deadlock exposed by this issue. Secondary reason for the reported deadlock since the held lock was part of the deadlock chain.) * Fixed some uses of ast_dummy_channel_alloc() not checking the returned channel pointer for failure. * Fixed some potential chan=NULL pointer usage in func_odbc.c. Protected by testing the bogus_chan value. * Fixed needlessly clearing a 1024 char auto array when setting the first char to zero is enough in manager.c:action_getvar(). (closes issue ASTERISK-18613) Reported by: Thomas Arimont Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: Thomas Arimont ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-26 19:40:12 +00:00
if (c) {
ast_channel_exten_set(c, extension);
ast_channel_context_set(c, con->name);
Merged revisions 337974 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500 (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011) | 30 lines Fix deadlock when using dummy channels. Dummy channels created by ast_dummy_channel_alloc() should be destoyed by ast_channel_unref(). Using ast_channel_release() needlessly grabs the channel container lock and can cause a deadlock as a result. * Analyzed use of ast_dummy_channel_alloc() and made use ast_channel_unref() when done with the dummy channel. (Primary reason for the reported deadlock.) * Made app_dial.c:dial_exec_full() not call ast_call() holding any channel locks. Chan_local could not perform deadlock avoidance correctly. (Potential deadlock exposed by this issue. Secondary reason for the reported deadlock since the held lock was part of the deadlock chain.) * Fixed some uses of ast_dummy_channel_alloc() not checking the returned channel pointer for failure. * Fixed some potential chan=NULL pointer usage in func_odbc.c. Protected by testing the bogus_chan value. * Fixed needlessly clearing a 1024 char auto array when setting the first char to zero is enough in manager.c:action_getvar(). (closes issue ASTERISK-18613) Reported by: Thomas Arimont Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: Thomas Arimont ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-26 19:40:12 +00:00
}
pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
application = expand_buf;
Merged revisions 337974 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r337974 | rmudgett | 2011-09-26 14:35:23 -0500 (Mon, 26 Sep 2011) | 37 lines Merged revisions 337973 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r337973 | rmudgett | 2011-09-26 14:30:39 -0500 (Mon, 26 Sep 2011) | 30 lines Fix deadlock when using dummy channels. Dummy channels created by ast_dummy_channel_alloc() should be destoyed by ast_channel_unref(). Using ast_channel_release() needlessly grabs the channel container lock and can cause a deadlock as a result. * Analyzed use of ast_dummy_channel_alloc() and made use ast_channel_unref() when done with the dummy channel. (Primary reason for the reported deadlock.) * Made app_dial.c:dial_exec_full() not call ast_call() holding any channel locks. Chan_local could not perform deadlock avoidance correctly. (Potential deadlock exposed by this issue. Secondary reason for the reported deadlock since the held lock was part of the deadlock chain.) * Fixed some uses of ast_dummy_channel_alloc() not checking the returned channel pointer for failure. * Fixed some potential chan=NULL pointer usage in func_odbc.c. Protected by testing the bogus_chan value. * Fixed needlessly clearing a 1024 char auto array when setting the first char to zero is enough in manager.c:action_getvar(). (closes issue ASTERISK-18613) Reported by: Thomas Arimont Patches: jira_asterisk_18613_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: Thomas Arimont ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-26 19:40:12 +00:00
if (c) {
ast_channel_unref(c);
}
}
length = sizeof(struct ast_exten);
length += strlen(extension) + 1;
length += strlen(application) + 1;
if (label)
length += strlen(label) + 1;
if (callerid)
length += strlen(callerid) + 1;
else
length ++; /* just the '\0' */
/* Be optimistic: Build the extension structure first */
if (!(tmp = ast_calloc(1, length)))
return -1;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
label = 0;
/* use p as dst in assignments, as the fields are const char * */
p = tmp->stuff;
if (label) {
tmp->label = p;
strcpy(p, label);
p += strlen(label) + 1;
}
tmp->exten = p;
p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
tmp->priority = priority;
tmp->cidmatch = p; /* but use p for assignments below */
/* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
if (callerid) {
p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
tmp->matchcid = AST_EXT_MATCHCID_ON;
} else {
*p++ = '\0';
tmp->matchcid = AST_EXT_MATCHCID_OFF;
}
tmp->app = p;
strcpy(p, application);
tmp->parent = con;
tmp->data = data;
tmp->datad = datad;
tmp->registrar = registrar;
if (lock_context) {
ast_wrlock_context(con);
}
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
an extension, and the trie exists, then we need to incrementally add this pattern to it. */
ast_copy_string(dummy_name, extension, sizeof(dummy_name));
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
dummy_exten.exten = dummy_name;
dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
dummy_exten.cidmatch = 0;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (!tmp2) {
/* hmmm, not in the trie; */
add_exten_to_pattern_tree(con, tmp, 0);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
}
res = 0; /* some compilers will think it is uninitialized otherwise */
for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
res = ext_cmp(e->exten, tmp->exten);
if (res == 0) { /* extension match, now look at cidmatch */
if (e->matchcid == AST_EXT_MATCHCID_OFF && tmp->matchcid == AST_EXT_MATCHCID_OFF)
res = 0;
else if (tmp->matchcid == AST_EXT_MATCHCID_ON && e->matchcid == AST_EXT_MATCHCID_OFF)
res = 1;
else if (e->matchcid == AST_EXT_MATCHCID_ON && tmp->matchcid == AST_EXT_MATCHCID_OFF)
res = -1;
else
res = ext_cmp(e->cidmatch, tmp->cidmatch);
}
if (res >= 0)
break;
}
if (e && res == 0) { /* exact match, insert in the priority chain */
res = add_priority(con, tmp, el, e, replace);
if (res < 0) {
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
if (x->exten) {
x->deleted = 1;
x->exten = 0;
}
ast_hashtab_remove_this_object(con->root_table, tmp);
}
if (tmp->datad) {
tmp->datad(tmp->data);
/* if you free this, null it out */
tmp->data = NULL;
}
ast_free(tmp);
}
if (lock_context) {
ast_unlock_context(con);
}
if (res < 0) {
errno = EEXIST;
return -1;
}
} else {
/*
* not an exact match, this is the first entry with this pattern,
* so insert in the main list right before 'e' (if any)
*/
tmp->next = e;
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
if (el) { /* there is another exten already in this context */
el->next = tmp;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->peer_table = ast_hashtab_create(13,
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
hashtab_compare_exten_numbers,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_priority,
0);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
tmp->peer_label_table = ast_hashtab_create(7,
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
hashtab_compare_exten_labels,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_labels,
0);
if (label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(tmp->peer_table, tmp);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
} else { /* this is the first exten in this context */
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (!con->root_table)
con->root_table = ast_hashtab_create(27,
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
hashtab_compare_extens,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_extens,
0);
con->root = tmp;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
con->root->peer_table = ast_hashtab_create(13,
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
hashtab_compare_exten_numbers,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_priority,
0);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
con->root->peer_label_table = ast_hashtab_create(7,
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
hashtab_compare_exten_labels,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_labels,
0);
if (label) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(con->root->peer_table, tmp);
This is the perhaps the biggest, boldest, most daring change I've ever committed to trunk. Forgive me in advance any disruption this may cause, and please, report any problems via the bugtracker. The upside is that this can speed up large dialplans by 20 times (or more). Context, extension, and priority matching are all fairly constant-time searches. I introduce here my hashtables (hashtabs), and a regression for them. I would have used the ast_obj2 tables, but mine are resizeable, and don't need the object destruction capability. The hashtab stuff is well tested and stable. I introduce a data structure, a trie, for extension pattern matching, in which knowledge of all patterns is accumulated, and all matches can be found via a single traversal of the tree. This is per-context. The trie is formed on the first lookup attempt, and stored in the context for future lookups. Destruction routines are in place for hashtabs and the pattern match trie. You can see the contents of the pattern match trie by using the 'dialplan show' cli command when 'core set debug' has been done to put it in debug mode. The pattern tree traversal only traverses those parts of the tree that are interesting. It uses a scoreboard sort of approach to find the best match. The speed of the traversal is more a function of the length of the pattern than the number of patterns in the tree. The tree also contains the CID matching patterns. See the source code comments for details on how everything works. I believe the approach general enough that any issues that might come up involving fine points in the pattern matching algorithm, can be solved by just tweaking things. We shall see. The current pattern matcher is fairly involved, and replicating every nuance of it is difficult. If you find and report problems, I will try to resolve than as quickly as I can. The trie and hashtabs are added to the existing context and exten structs, and none of the old machinery has been removed for the sake of the multitude of functions that use them. In the future, we can (maybe) weed out the linked lists and save some space. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89129 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-09 16:00:22 +00:00
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_hashtab_insert_safe(con->root_table, tmp);
if (lock_context) {
ast_unlock_context(con);
}
if (tmp->priority == PRIORITY_HINT) {
ast_add_hint(tmp);
}
}
if (option_debug) {
if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
} else {
ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
tmp->exten, tmp->priority, con->name, con);
}
}
if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
tmp->exten, tmp->priority, tmp->cidmatch, con->name);
} else {
ast_verb(3, "Added extension '%s' priority %d to %s\n",
tmp->exten, tmp->priority, con->name);
}
return 0;
}
/*! \brief Structure which contains information about an outgoing dial */
struct pbx_outgoing {
/*! \brief Dialing structure being used */
struct ast_dial *dial;
/*! \brief Condition for synchronous dialing */
ast_cond_t cond;
/*! \brief Application to execute */
char app[AST_MAX_APP];
/*! \brief Application data to pass to application */
char *appdata;
/*! \brief Dialplan context */
char context[AST_MAX_CONTEXT];
/*! \brief Dialplan extension */
char exten[AST_MAX_EXTENSION];
/*! \brief Dialplan priority */
int priority;
/*! \brief Result of the dial operation when dialed is set */
int dial_res;
/*! \brief Set when dialing is completed */
unsigned int dialed:1;
/*! \brief Set when execution is completed */
unsigned int executed:1;
};
/*! \brief Destructor for outgoing structure */
static void pbx_outgoing_destroy(void *obj)
{
struct pbx_outgoing *outgoing = obj;
if (outgoing->dial) {
ast_dial_destroy(outgoing->dial);
}
ast_cond_destroy(&outgoing->cond);
Multiple revisions 375993-375994 ........ r375993 | mmichelson | 2012-11-07 11:01:13 -0600 (Wed, 07 Nov 2012) | 30 lines Fix misuses of timeouts throughout the code. Prior to this change, a common method for determining if a timeout was reached was to call a function such as ast_waitfor_n() and inspect the out parameter that told how many milliseconds were left, then use that as the input to ast_waitfor_n() on the next go-around. The problem with this is that in some cases, submillisecond timeouts can occur, resulting in the out parameter not decreasing any. When this happens thousands of times, the result is that the timeout takes much longer than intended to be reached. As an example, I had a situation where a 3 second timeout took multiple days to finally end since most wakeups from ast_waitfor_n() were under a millisecond. This patch seeks to fix this pattern throughout the code. Now we log the time when an operation began and find the difference in wall clock time between now and when the event started. This means that sub-millisecond timeouts now cannot play havoc when trying to determine if something has timed out. Part of this fix also includes changing the function ast_waitfor() so that it is possible for it to return less than zero when a negative timeout is given to it. This makes it actually possible to detect errors in ast_waitfor() when there is no timeout. (closes issue ASTERISK-20414) reported by David M. Lee Review: https://reviewboard.asterisk.org/r/2135/ ........ r375994 | mmichelson | 2012-11-07 11:08:44 -0600 (Wed, 07 Nov 2012) | 3 lines Remove some debugging that accidentally made it in the last commit. ........ Merged revisions 375993-375994 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 375995 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 376014 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@376015 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-11-07 19:15:26 +00:00
ast_free(outgoing->appdata);
}
/*! \brief Internal function which dials an outgoing leg and sends it to a provided extension or application */
static void *pbx_outgoing_exec(void *data)
{
RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
enum ast_dial_result res;
/* Notify anyone interested that dialing is complete */
res = ast_dial_run(outgoing->dial, NULL, 0);
ao2_lock(outgoing);
outgoing->dial_res = res;
outgoing->dialed = 1;
ast_cond_signal(&outgoing->cond);
ao2_unlock(outgoing);
/* If the outgoing leg was not answered we can immediately return and go no further */
if (res != AST_DIAL_RESULT_ANSWERED) {
return NULL;
}
if (!ast_strlen_zero(outgoing->app)) {
struct ast_app *app = pbx_findapp(outgoing->app);
if (app) {
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
ast_channel_name(ast_dial_answered(outgoing->dial)));
pbx_exec(ast_dial_answered(outgoing->dial), app, outgoing->appdata);
} else {
ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
}
} else {
struct ast_channel *answered = ast_dial_answered(outgoing->dial);
if (!ast_strlen_zero(outgoing->context)) {
ast_channel_context_set(answered, outgoing->context);
}
if (!ast_strlen_zero(outgoing->exten)) {
ast_channel_exten_set(answered, outgoing->exten);
}
if (outgoing->priority > 0) {
ast_channel_priority_set(answered, outgoing->priority);
}
if (ast_pbx_run(answered)) {
ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered));
} else {
/* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
ast_dial_answered_steal(outgoing->dial);
}
}
/* Notify anyone else again that may be interested that execution is complete */
ao2_lock(outgoing);
outgoing->executed = 1;
ast_cond_signal(&outgoing->cond);
ao2_unlock(outgoing);
return NULL;
}
/*! \brief Internal dialing state callback which causes early media to trigger an answer */
static void pbx_outgoing_state_callback(struct ast_dial *dial)
{
struct ast_channel *channel;
if (ast_dial_state(dial) != AST_DIAL_RESULT_PROGRESS) {
return;
}
if (!(channel = ast_dial_get_channel(dial, 0))) {
return;
}
ast_verb(4, "Treating progress as answer on '%s' due to early media option\n",
ast_channel_name(channel));
ast_queue_control(channel, AST_CONTROL_ANSWER);
}
/*!
* \brief Attempt to convert disconnect cause to old originate reason.
*
* \todo XXX The old originate reasons need to be trashed and replaced
* with normal disconnect cause codes if the call was not answered.
* The internal consumers of the reason values would also need to be
* updated: app_originate, call files, and AMI OriginateResponse.
*/
static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
{
enum ast_control_frame_type pbx_reason;
if (dial_result == AST_DIAL_RESULT_ANSWERED) {
/* Remote end answered. */
pbx_reason = AST_CONTROL_ANSWER;
} else if (dial_result == AST_DIAL_RESULT_HANGUP) {
/* Caller hungup */
pbx_reason = AST_CONTROL_HANGUP;
} else {
switch (cause) {
case AST_CAUSE_USER_BUSY:
pbx_reason = AST_CONTROL_BUSY;
break;
case AST_CAUSE_CALL_REJECTED:
case AST_CAUSE_NETWORK_OUT_OF_ORDER:
case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
case AST_CAUSE_NORMAL_TEMPORARY_FAILURE:
case AST_CAUSE_SWITCH_CONGESTION:
case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
pbx_reason = AST_CONTROL_CONGESTION;
break;
case AST_CAUSE_ANSWERED_ELSEWHERE:
case AST_CAUSE_NO_ANSWER:
/* Remote end was ringing (but isn't anymore) */
pbx_reason = AST_CONTROL_RINGING;
break;
case AST_CAUSE_UNALLOCATED:
default:
/* Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?) */
pbx_reason = 0;
break;
}
}
return pbx_reason;
}
static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
const char *addr, int timeout, const char *context, const char *exten, int priority,
const char *app, const char *appdata, int *reason, int synchronous,
const char *cid_num, const char *cid_name, struct ast_variable *vars,
const char *account, struct ast_channel **locked_channel, int early_media,
const struct ast_assigned_ids *assignedids)
{
RAII_VAR(struct pbx_outgoing *, outgoing, NULL, ao2_cleanup);
struct ast_channel *dialed;
pthread_t thread;
outgoing = ao2_alloc(sizeof(*outgoing), pbx_outgoing_destroy);
if (!outgoing) {
return -1;
}
ast_cond_init(&outgoing->cond, NULL);
if (!ast_strlen_zero(app)) {
ast_copy_string(outgoing->app, app, sizeof(outgoing->app));
outgoing->appdata = ast_strdup(appdata);
} else {
ast_copy_string(outgoing->context, context, sizeof(outgoing->context));
ast_copy_string(outgoing->exten, exten, sizeof(outgoing->exten));
outgoing->priority = priority;
}
if (!(outgoing->dial = ast_dial_create())) {
return -1;
}
if (ast_dial_append(outgoing->dial, type, addr, assignedids)) {
return -1;
}
ast_dial_set_global_timeout(outgoing->dial, timeout);
if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
if (synchronous && reason) {
*reason = pbx_dial_reason(AST_DIAL_RESULT_FAILED,
ast_dial_reason(outgoing->dial, 0));
}
return -1;
}
dialed = ast_dial_get_channel(outgoing->dial, 0);
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
if (!dialed) {
return -1;
}
ast_channel_lock(dialed);
if (vars) {
ast_set_variables(dialed, vars);
}
accountcode: Slightly change accountcode propagation. The previous behavior was to simply set the accountcode of an outgoing channel to the accountcode of the channel initiating the call. It was done this way a long time ago to allow the accountcode set on the SIP/100 channel to be propagated to a local channel so the dialplan execution on the Local;2 channel would have the SIP/100 accountcode available. SIP/100 -> Local;1/Local;2 -> SIP/200 Propagating the SIP/100 accountcode to the local channels is very useful. Without any dialplan manipulation, all channels in this call would have the same accountcode. Using dialplan, you can set a different accountcode on the SIP/200 channel either by setting the accountcode on the Local;2 channel or by the Dial application's b(pre-dial), M(macro) or U(gosub) options, or by the FollowMe application's b(pre-dial) option, or by the Queue application's macro or gosub options. Before Asterisk v12, the altered accountcode on SIP/200 will remain until the local channels optimize out and the accountcode would change to the SIP/100 accountcode. Asterisk v1.8 attempted to add peeraccount support but ultimately had to punt on the support. The peeraccount support was rendered useless because of how the CDR code needed to unconditionally force the caller's accountcode onto the peer channel's accountcode. The CEL events were thus intentionally made to always use the channel's accountcode as the peeraccount value. With the arrival of Asterisk v12, the situation has improved somewhat so peeraccount support can be made to work. Using the indicated example, the the accountcode values become as follows when the peeraccount is set on SIP/100 before calling SIP/200: SIP/100 ---> Local;1 ---- Local;2 ---> SIP/200 acct: 100 \/ acct: 200 \/ acct: 100 \/ acct: 200 peer: 200 /\ peer: 100 /\ peer: 200 /\ peer: 100 If a channel already has an accountcode it can only change by the following explicit user actions: 1) A channel originate method that can specify an accountcode to use. 2) The calling channel propagating its non-empty peeraccount or its non-empty accountcode if the peeraccount was empty to the outgoing channel's accountcode before initiating the dial. e.g., Dial and FollowMe. The exception to this propagation method is Queue. Queue will only propagate peeraccounts this way only if the outgoing channel does not have an accountcode. 3) Dialplan using CHANNEL(accountcode). 4) Dialplan using CHANNEL(peeraccount) on the other end of a local channel pair. If a channel does not have an accountcode it can get one from the following places: 1) The channel driver's configuration at channel creation. 2) Explicit user action as already indicated. 3) Entering a basic or stasis-mixing bridge from a peer channel's peeraccount value. You can specify the accountcode for an outgoing channel by setting the CHANNEL(peeraccount) before using the Dial, FollowMe, and Queue applications. Queue adds the wrinkle that it will not overwrite an existing accountcode on the outgoing channel with the calling channels values. Accountcode and peeraccount values propagate to an outgoing channel before dialing. Accountcodes also propagate when channels enter or leave a basic or stasis-mixing bridge. The peeraccount value only makes sense for mixing bridges with two channels; it is meaningless otherwise. * Made peeraccount functional by changing accountcode propagation as described above. * Fixed CEL extracting the wrong ie value for the peeraccount. This was done intentionally in Asterisk v1.8 when that version had to punt on peeraccount. * Fixed a few places dealing with accountcodes that were reading from channels without the lock held. AFS-65 #close Review: https://reviewboard.asterisk.org/r/3601/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419520 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-24 22:48:38 +00:00
if (!ast_strlen_zero(account)) {
ast_channel_stage_snapshot(dialed);
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_channel_accountcode_set(dialed, account);
accountcode: Slightly change accountcode propagation. The previous behavior was to simply set the accountcode of an outgoing channel to the accountcode of the channel initiating the call. It was done this way a long time ago to allow the accountcode set on the SIP/100 channel to be propagated to a local channel so the dialplan execution on the Local;2 channel would have the SIP/100 accountcode available. SIP/100 -> Local;1/Local;2 -> SIP/200 Propagating the SIP/100 accountcode to the local channels is very useful. Without any dialplan manipulation, all channels in this call would have the same accountcode. Using dialplan, you can set a different accountcode on the SIP/200 channel either by setting the accountcode on the Local;2 channel or by the Dial application's b(pre-dial), M(macro) or U(gosub) options, or by the FollowMe application's b(pre-dial) option, or by the Queue application's macro or gosub options. Before Asterisk v12, the altered accountcode on SIP/200 will remain until the local channels optimize out and the accountcode would change to the SIP/100 accountcode. Asterisk v1.8 attempted to add peeraccount support but ultimately had to punt on the support. The peeraccount support was rendered useless because of how the CDR code needed to unconditionally force the caller's accountcode onto the peer channel's accountcode. The CEL events were thus intentionally made to always use the channel's accountcode as the peeraccount value. With the arrival of Asterisk v12, the situation has improved somewhat so peeraccount support can be made to work. Using the indicated example, the the accountcode values become as follows when the peeraccount is set on SIP/100 before calling SIP/200: SIP/100 ---> Local;1 ---- Local;2 ---> SIP/200 acct: 100 \/ acct: 200 \/ acct: 100 \/ acct: 200 peer: 200 /\ peer: 100 /\ peer: 200 /\ peer: 100 If a channel already has an accountcode it can only change by the following explicit user actions: 1) A channel originate method that can specify an accountcode to use. 2) The calling channel propagating its non-empty peeraccount or its non-empty accountcode if the peeraccount was empty to the outgoing channel's accountcode before initiating the dial. e.g., Dial and FollowMe. The exception to this propagation method is Queue. Queue will only propagate peeraccounts this way only if the outgoing channel does not have an accountcode. 3) Dialplan using CHANNEL(accountcode). 4) Dialplan using CHANNEL(peeraccount) on the other end of a local channel pair. If a channel does not have an accountcode it can get one from the following places: 1) The channel driver's configuration at channel creation. 2) Explicit user action as already indicated. 3) Entering a basic or stasis-mixing bridge from a peer channel's peeraccount value. You can specify the accountcode for an outgoing channel by setting the CHANNEL(peeraccount) before using the Dial, FollowMe, and Queue applications. Queue adds the wrinkle that it will not overwrite an existing accountcode on the outgoing channel with the calling channels values. Accountcode and peeraccount values propagate to an outgoing channel before dialing. Accountcodes also propagate when channels enter or leave a basic or stasis-mixing bridge. The peeraccount value only makes sense for mixing bridges with two channels; it is meaningless otherwise. * Made peeraccount functional by changing accountcode propagation as described above. * Fixed CEL extracting the wrong ie value for the peeraccount. This was done intentionally in Asterisk v1.8 when that version had to punt on peeraccount. * Fixed a few places dealing with accountcodes that were reading from channels without the lock held. AFS-65 #close Review: https://reviewboard.asterisk.org/r/3601/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419520 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-24 22:48:38 +00:00
ast_channel_peeraccount_set(dialed, account);
ast_channel_stage_snapshot_done(dialed);
}
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED);
ast_channel_unlock(dialed);
if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
struct ast_party_connected_line connected;
/*
* It seems strange to set the CallerID on an outgoing call leg
* to whom we are calling, but this function's callers are doing
* various Originate methods. This call leg goes to the local
* user. Once the called party answers, the dialplan needs to
* be able to access the CallerID from the CALLERID function as
* if the called party had placed this call.
*/
ast_set_callerid(dialed, cid_num, cid_name, cid_num);
ast_party_connected_line_set_init(&connected, ast_channel_connected(dialed));
if (!ast_strlen_zero(cid_num)) {
connected.id.number.valid = 1;
connected.id.number.str = (char *) cid_num;
connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
}
if (!ast_strlen_zero(cid_name)) {
connected.id.name.valid = 1;
connected.id.name.str = (char *) cid_name;
connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
}
ast_channel_set_connected_line(dialed, &connected, NULL);
}
if (early_media) {
ast_dial_set_state_callback(outgoing->dial, pbx_outgoing_state_callback);
}
if (locked_channel) {
/*
* Keep a dialed channel ref since the caller wants
* the channel returned. We must get the ref before
* spawning off pbx_outgoing_exec().
*/
ast_channel_ref(dialed);
if (!synchronous) {
/*
* Lock it now to hold off pbx_outgoing_exec() in case the
* calling function needs the channel state/snapshot before
* dialing actually happens.
*/
ast_channel_lock(dialed);
}
}
ao2_ref(outgoing, +1);
if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
ao2_ref(outgoing, -1);
if (locked_channel) {
if (!synchronous) {
ast_channel_unlock(dialed);
}
ast_channel_unref(dialed);
}
return -1;
}
if (synchronous) {
ao2_lock(outgoing);
/* Wait for dialing to complete */
while (!outgoing->dialed) {
ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
}
if (1 < synchronous
&& outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) {
/* Wait for execution to complete */
while (!outgoing->executed) {
ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
}
}
ao2_unlock(outgoing);
/* Determine the outcome of the dialing attempt up to it being answered. */
if (reason) {
*reason = pbx_dial_reason(outgoing->dial_res,
ast_dial_reason(outgoing->dial, 0));
}
if (outgoing->dial_res != AST_DIAL_RESULT_ANSWERED) {
/* The dial operation failed. */
if (locked_channel) {
ast_channel_unref(dialed);
}
return -1;
}
if (locked_channel) {
ast_channel_lock(dialed);
}
}
if (locked_channel) {
*locked_channel = dialed;
}
return 0;
}
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
int timeout, const char *context, const char *exten, int priority, int *reason,
int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
const char *account, struct ast_channel **locked_channel, int early_media,
const struct ast_assigned_ids *assignedids)
{
int res;
int my_reason;
if (!reason) {
reason = &my_reason;
}
*reason = 0;
if (locked_channel) {
*locked_channel = NULL;
}
res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
early_media, assignedids);
if (res < 0 /* Call failed to get connected for some reason. */
&& 1 < synchronous
&& ast_exists_extension(NULL, context, "failed", 1, NULL)) {
struct ast_channel *failed;
/* We do not have to worry about a locked_channel if dialing failed. */
ast_assert(!locked_channel || !*locked_channel);
/*!
* \todo XXX Not good. The channel name is not unique if more than
* one originate fails at a time.
*/
failed = ast_channel_alloc(0, AST_STATE_DOWN, cid_num, cid_name, account,
"failed", context, NULL, NULL, 0, "OutgoingSpoolFailed");
if (failed) {
char failed_reason[12];
ast_set_variables(failed, vars);
snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
ast_channel_unlock(failed);
if (ast_pbx_run(failed)) {
ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n",
ast_channel_name(failed));
ast_hangup(failed);
}
}
}
return res;
}
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
int timeout, const char *app, const char *appdata, int *reason, int synchronous,
const char *cid_num, const char *cid_name, struct ast_variable *vars,
const char *account, struct ast_channel **locked_channel,
const struct ast_assigned_ids *assignedids)
{
if (reason) {
*reason = 0;
}
if (locked_channel) {
*locked_channel = NULL;
}
if (ast_strlen_zero(app)) {
return -1;
}
return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
assignedids);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* this is the guts of destroying a context --
freeing up the structure, traversing and destroying the
extensions, switches, ignorepats, includes, etc. etc. */
static void __ast_internal_context_destroy( struct ast_context *con)
{
struct ast_include *tmpi;
struct ast_sw *sw;
struct ast_exten *e, *el, *en;
struct ast_ignorepat *ipi;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
struct ast_context *tmp = con;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
struct ast_include *tmpil = tmpi;
tmpi = tmpi->next;
ast_free(tmpil);
}
for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
struct ast_ignorepat *ipl = ipi;
ipi = ipi->next;
ast_free(ipl);
}
if (tmp->registrar)
ast_free(tmp->registrar);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* destroy the hash tabs */
if (tmp->root_table) {
ast_hashtab_destroy(tmp->root_table, 0);
}
/* and destroy the pattern tree */
if (tmp->pattern_tree)
destroy_pattern_tree(tmp->pattern_tree);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
ast_free(sw);
for (e = tmp->root; e;) {
for (en = e->peer; en;) {
el = en;
en = en->peer;
destroy_exten(el);
}
el = e;
e = e->next;
destroy_exten(el);
}
tmp->root = NULL;
ast_rwlock_destroy(&tmp->lock);
ast_mutex_destroy(&tmp->macrolock);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_free(tmp);
}
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
{
struct ast_context *tmp, *tmpl=NULL;
struct ast_exten *exten_item, *prio_item;
for (tmp = list; tmp; ) {
struct ast_context *next = NULL; /* next starting point */
/* The following code used to skip forward to the next
context with matching registrar, but this didn't
make sense; individual priorities registrar'd to
the matching registrar could occur in any context! */
ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
if (con) {
for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
if ( !strcasecmp(tmp->name, con->name) ) {
break; /* found it */
}
}
}
if (!tmp) /* not found, we are done */
break;
ast_wrlock_context(tmp);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (registrar) {
/* then search thru and remove any extens that match registrar. */
struct ast_hashtab_iter *exten_iter;
struct ast_hashtab_iter *prio_iter;
struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
struct ast_include *i, *pi = NULL, *ni = NULL;
struct ast_sw *sw = NULL;
/* remove any ignorepats whose registrar matches */
for (ip = tmp->ignorepats; ip; ip = ipn) {
ipn = ip->next;
if (!strcmp(ip->registrar, registrar)) {
if (ipl) {
ipl->next = ip->next;
ast_free(ip);
continue; /* don't change ipl */
} else {
tmp->ignorepats = ip->next;
ast_free(ip);
continue; /* don't change ipl */
}
}
ipl = ip;
}
/* remove any includes whose registrar matches */
for (i = tmp->includes; i; i = ni) {
ni = i->next;
if (strcmp(i->registrar, registrar) == 0) {
/* remove from list */
if (pi) {
pi->next = i->next;
/* free include */
ast_free(i);
continue; /* don't change pi */
} else {
tmp->includes = i->next;
/* free include */
ast_free(i);
continue; /* don't change pi */
}
}
pi = i;
}
/* remove any switches whose registrar matches */
AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
if (strcmp(sw->registrar,registrar) == 0) {
AST_LIST_REMOVE_CURRENT(list);
ast_free(sw);
}
}
AST_LIST_TRAVERSE_SAFE_END;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
exten_iter = ast_hashtab_start_traversal(tmp->root_table);
while ((exten_item=ast_hashtab_next(exten_iter))) {
Fix potential invalid reads that could occur in pbx.c Here is a cut and paste of my review request for this change: This past weekend, Russell ran our current suite of unit tests for Asterisk under valgrind. The PBX pattern match test caused valgrind to spew forth two invalid read errors. This patch contains two changes that shut valgrind up and do not cause any new memory leaks. Change 1: In ast_context_remove_extension_callerid2, valgrind reported an invalid read in the for loop close to the function's end. Specifically, one of the the strcmp calls in the loop control was reading invalid memory. This was because the caller of ast_context_remove_extension_callerid2 (__ast_context destroy in this case) passed as a parameter a shallow copy of an ast_exten's exten field. This same ast_exten was what was destroyed inside the for loop, thus any iterations of the for loop beyond the destruction of the ast_exten would result in invalid reads. My fix for this is to make a copy of the ast_exten's exten field and pass the copy to ast_context_remove_extension_callerid2. In addition, I have also acted similarly with the ast_exten's matchcid field. Since in this case a NULL is handled quite differently than an empty string, I needed to be a bit more careful with its handling. Change 2: In __ast_context_destroy, we iterated over a hashtab and called ast_context_remove_extension_callerid2 on each item. Specifically, the hashtab over which we were iterating was an ast_exten's peer_table. Inside of ast_context_remove_extension_callerid2, we could possibly destroy this ast_exten, which also caused the hashtab to be freed. Attempting to call ast_hashtab_end_traversal on the hashtab iterator caused an invalid read to occur when trying to read the iterator->tab->do_locking field since iterator->tab had already been freed. My handling of this problem is a bit less straightforward. With each iteration over the hashtab's contents, we set a variable called "end_traversal" based on the return of ast_context_remove_extension_callerid2. If 0 is ever returned, then we know that the extension was found and destroyed. Because of this, we cannot call ast_hashtab_end_traversal because we will be guaranteeing a read of invalid memory. In such a case, we forego calling ast_hashtab_end_traversal and instead call ast_free on the hashtab iterator. Review: https://reviewboard.asterisk.org/r/585 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254362 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-03-24 21:10:38 +00:00
int end_traversal = 1;
/*
* If the extension could not be removed from the root_table due to
* a loaded PBX app, it can exist here but have its peer_table be
* destroyed due to a previous pass through this function.
*/
if (!exten_item->peer_table) {
continue;
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
while ((prio_item=ast_hashtab_next(prio_iter))) {
Fix potential invalid reads that could occur in pbx.c Here is a cut and paste of my review request for this change: This past weekend, Russell ran our current suite of unit tests for Asterisk under valgrind. The PBX pattern match test caused valgrind to spew forth two invalid read errors. This patch contains two changes that shut valgrind up and do not cause any new memory leaks. Change 1: In ast_context_remove_extension_callerid2, valgrind reported an invalid read in the for loop close to the function's end. Specifically, one of the the strcmp calls in the loop control was reading invalid memory. This was because the caller of ast_context_remove_extension_callerid2 (__ast_context destroy in this case) passed as a parameter a shallow copy of an ast_exten's exten field. This same ast_exten was what was destroyed inside the for loop, thus any iterations of the for loop beyond the destruction of the ast_exten would result in invalid reads. My fix for this is to make a copy of the ast_exten's exten field and pass the copy to ast_context_remove_extension_callerid2. In addition, I have also acted similarly with the ast_exten's matchcid field. Since in this case a NULL is handled quite differently than an empty string, I needed to be a bit more careful with its handling. Change 2: In __ast_context_destroy, we iterated over a hashtab and called ast_context_remove_extension_callerid2 on each item. Specifically, the hashtab over which we were iterating was an ast_exten's peer_table. Inside of ast_context_remove_extension_callerid2, we could possibly destroy this ast_exten, which also caused the hashtab to be freed. Attempting to call ast_hashtab_end_traversal on the hashtab iterator caused an invalid read to occur when trying to read the iterator->tab->do_locking field since iterator->tab had already been freed. My handling of this problem is a bit less straightforward. With each iteration over the hashtab's contents, we set a variable called "end_traversal" based on the return of ast_context_remove_extension_callerid2. If 0 is ever returned, then we know that the extension was found and destroyed. Because of this, we cannot call ast_hashtab_end_traversal because we will be guaranteeing a read of invalid memory. In such a case, we forego calling ast_hashtab_end_traversal and instead call ast_free on the hashtab iterator. Review: https://reviewboard.asterisk.org/r/585 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254362 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-03-24 21:10:38 +00:00
char extension[AST_MAX_EXTENSION];
char cidmatch[AST_MAX_EXTENSION];
if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
continue;
}
ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
Fix potential invalid reads that could occur in pbx.c Here is a cut and paste of my review request for this change: This past weekend, Russell ran our current suite of unit tests for Asterisk under valgrind. The PBX pattern match test caused valgrind to spew forth two invalid read errors. This patch contains two changes that shut valgrind up and do not cause any new memory leaks. Change 1: In ast_context_remove_extension_callerid2, valgrind reported an invalid read in the for loop close to the function's end. Specifically, one of the the strcmp calls in the loop control was reading invalid memory. This was because the caller of ast_context_remove_extension_callerid2 (__ast_context destroy in this case) passed as a parameter a shallow copy of an ast_exten's exten field. This same ast_exten was what was destroyed inside the for loop, thus any iterations of the for loop beyond the destruction of the ast_exten would result in invalid reads. My fix for this is to make a copy of the ast_exten's exten field and pass the copy to ast_context_remove_extension_callerid2. In addition, I have also acted similarly with the ast_exten's matchcid field. Since in this case a NULL is handled quite differently than an empty string, I needed to be a bit more careful with its handling. Change 2: In __ast_context_destroy, we iterated over a hashtab and called ast_context_remove_extension_callerid2 on each item. Specifically, the hashtab over which we were iterating was an ast_exten's peer_table. Inside of ast_context_remove_extension_callerid2, we could possibly destroy this ast_exten, which also caused the hashtab to be freed. Attempting to call ast_hashtab_end_traversal on the hashtab iterator caused an invalid read to occur when trying to read the iterator->tab->do_locking field since iterator->tab had already been freed. My handling of this problem is a bit less straightforward. With each iteration over the hashtab's contents, we set a variable called "end_traversal" based on the return of ast_context_remove_extension_callerid2. If 0 is ever returned, then we know that the extension was found and destroyed. Because of this, we cannot call ast_hashtab_end_traversal because we will be guaranteeing a read of invalid memory. In such a case, we forego calling ast_hashtab_end_traversal and instead call ast_free on the hashtab iterator. Review: https://reviewboard.asterisk.org/r/585 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254362 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-03-24 21:10:38 +00:00
ast_copy_string(extension, prio_item->exten, sizeof(extension));
if (prio_item->cidmatch) {
ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
}
end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
Fix potential invalid reads that could occur in pbx.c Here is a cut and paste of my review request for this change: This past weekend, Russell ran our current suite of unit tests for Asterisk under valgrind. The PBX pattern match test caused valgrind to spew forth two invalid read errors. This patch contains two changes that shut valgrind up and do not cause any new memory leaks. Change 1: In ast_context_remove_extension_callerid2, valgrind reported an invalid read in the for loop close to the function's end. Specifically, one of the the strcmp calls in the loop control was reading invalid memory. This was because the caller of ast_context_remove_extension_callerid2 (__ast_context destroy in this case) passed as a parameter a shallow copy of an ast_exten's exten field. This same ast_exten was what was destroyed inside the for loop, thus any iterations of the for loop beyond the destruction of the ast_exten would result in invalid reads. My fix for this is to make a copy of the ast_exten's exten field and pass the copy to ast_context_remove_extension_callerid2. In addition, I have also acted similarly with the ast_exten's matchcid field. Since in this case a NULL is handled quite differently than an empty string, I needed to be a bit more careful with its handling. Change 2: In __ast_context_destroy, we iterated over a hashtab and called ast_context_remove_extension_callerid2 on each item. Specifically, the hashtab over which we were iterating was an ast_exten's peer_table. Inside of ast_context_remove_extension_callerid2, we could possibly destroy this ast_exten, which also caused the hashtab to be freed. Attempting to call ast_hashtab_end_traversal on the hashtab iterator caused an invalid read to occur when trying to read the iterator->tab->do_locking field since iterator->tab had already been freed. My handling of this problem is a bit less straightforward. With each iteration over the hashtab's contents, we set a variable called "end_traversal" based on the return of ast_context_remove_extension_callerid2. If 0 is ever returned, then we know that the extension was found and destroyed. Because of this, we cannot call ast_hashtab_end_traversal because we will be guaranteeing a read of invalid memory. In such a case, we forego calling ast_hashtab_end_traversal and instead call ast_free on the hashtab iterator. Review: https://reviewboard.asterisk.org/r/585 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254362 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-03-24 21:10:38 +00:00
}
/* Explanation:
* ast_context_remove_extension_callerid2 will destroy the extension that it comes across. This
* destruction includes destroying the exten's peer_table, which we are currently traversing. If
* ast_context_remove_extension_callerid2 ever should return '0' then this means we have destroyed
* the hashtable which we are traversing, and thus calling ast_hashtab_end_traversal will result
* in reading invalid memory. Thus, if we detect that we destroyed the hashtable, then we will simply
* free the iterator
*/
if (end_traversal) {
ast_hashtab_end_traversal(prio_iter);
} else {
ast_free(prio_iter);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
}
}
ast_hashtab_end_traversal(exten_iter);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* delete the context if it's registrar matches, is empty, has refcount of 1, */
/* it's not empty, if it has includes, ignorepats, or switches that are registered from
another registrar. It's not empty if there are any extensions */
if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
ast_hashtab_remove_this_object(contexttab, tmp);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
next = tmp->next;
if (tmpl)
tmpl->next = next;
else
contexts = next;
/* Okay, now we're safe to let it go -- in a sense, we were
ready to let it go as soon as we locked it. */
ast_unlock_context(tmp);
__ast_internal_context_destroy(tmp);
} else {
ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
tmp->refcount, tmp->root);
ast_unlock_context(tmp);
next = tmp->next;
tmpl = tmp;
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
}
} else if (con) {
ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
ast_hashtab_remove_this_object(contexttab, tmp);
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
next = tmp->next;
if (tmpl)
tmpl->next = next;
else
contexts = next;
/* Okay, now we're safe to let it go -- in a sense, we were
ready to let it go as soon as we locked it. */
ast_unlock_context(tmp);
__ast_internal_context_destroy(tmp);
}
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
/* if we have a specific match, we are done, otherwise continue */
tmp = con ? NULL : next;
}
}
int ast_context_destroy_by_name(const char *context, const char *registrar)
{
struct ast_context *con;
int ret = -1;
ast_wrlock_contexts();
con = ast_context_find(context);
if (con) {
ast_context_destroy(con, registrar);
ret = 0;
}
ast_unlock_contexts();
return ret;
}
void ast_context_destroy(struct ast_context *con, const char *registrar)
{
ast_wrlock_contexts();
(closes issue #6002) Reported by: rizzo Tested by: murf Proposal of the changes to be made, and then an announcement of how they were accomplished: http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html and: http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html Here is a recap, file by file, of what I have done: pbx/pbx_config.c pbx/pbx_ael.c All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set. Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it is just as necessary to have the TABLE available. This is because the list/table in question might not be the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global position when things are ready. We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing "find" and "create", as all existing usages used both in tandem anyway. pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and then call merge_contexts_and_delete, which will merge (now) existing contexts and priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will lock down the contexts, swap the lists and tables, and unlock (real quick), and then destroy the old dialplan. chan_sip.c chan_iax.c chan_skinny.c All the channel drivers that would add regcontexts now use the ast_context_find_or_create now. chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered. apps/app_meetme.c apps/app_dial.c apps/app_queue.c All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead. include/asterisk/pbx.h ast_context_create() is removed. Find_or_create_ is the new method. ast_context_find_or_create() interface gets the hashtab added. ast_merge_contexts_and_delete() gets the local hashtab arg added. ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking. ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael ast_hashtab_hash_contexts was in like fashion make public. include/asterisk/pval.h ast_compile_ael2() interface changed to include the local hashtab table ptr. main/features.c For the sake of the parking context, we use ast_context_find_or_create(). main/pbx.c I changed all the "tree" names to "table" instead. That's because the original implementation was based on binary trees. (had a free library). Then I moved to hashtabs. Now, the names move forward too. refcount field added to contexts, so you can keep track of how many modules wanted this context to exist. Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING. Added some calls to ast_verb(3,...) for debug messages Lots of little mods to ast_context_remove_extension2, which is now excersized in ways it was not previously; one definite bug fixed. find_or_create was upgraded to handle both local lists/tables as well as the globals. context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables ast_merge_contexts_and_delete() was heavily modified. ast_add_extension2() was also upgraded to handle changes. the context_destroy() code was re-engineered to handle the new way of doing things, by exten/prio instead of by context. res/ael/pval.c res/ael/ael.tab.c res/ael/ael.tab.h res/ael/ael.y res/ael/ael_lex.c res/ael/ael.flex utils/ael_main.c utils/extconf.c utils/conf2ael.c utils/Makefile Had to change the interface to ast_compile_ael2(), to include the hashtab ptr. This ended up involving several external apps. The main gotcha was I had to include lock.h and hashtab.h in several places. As a side note, I tested this stuff pretty thoroughly, I replicated the problems originally reported by Luigi, and made triply sure that reloads worked, and everything worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into trunk, that did not appear in my tests of bug6002. How's this for verbose commit messages? git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-07 18:57:57 +00:00
__ast_context_destroy(contexts, contexts_table, con,registrar);
ast_unlock_contexts();
}
static void wait_for_hangup(struct ast_channel *chan, const void *data)
{
int res;
struct ast_frame *f;
double waitsec;
int waittime;
if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
waitsec = -1;
if (waitsec > -1) {
waittime = waitsec * 1000.0;
ast_safe_sleep(chan, waittime);
} else do {
res = ast_waitfor(chan, -1);
if (res < 0)
return;
f = ast_read(chan);
if (f)
ast_frfree(f);
} while(f);
}
/*!
* \ingroup applications
*/
static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
{
ast_indicate(chan, AST_CONTROL_PROCEEDING);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
{
ast_indicate(chan, AST_CONTROL_PROGRESS);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
{
ast_indicate(chan, AST_CONTROL_RINGING);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
{
ast_indicate(chan, AST_CONTROL_BUSY);
/* Don't change state of an UP channel, just indicate
busy in audio */
ast_channel_lock(chan);
if (ast_channel_state(chan) != AST_STATE_UP) {
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
ast_setstate(chan, AST_STATE_BUSY);
}
ast_channel_unlock(chan);
wait_for_hangup(chan, data);
return -1;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
{
ast_indicate(chan, AST_CONTROL_CONGESTION);
/* Don't change state of an UP channel, just indicate
congestion in audio */
ast_channel_lock(chan);
if (ast_channel_state(chan) != AST_STATE_UP) {
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
ast_setstate(chan, AST_STATE_BUSY);
}
ast_channel_unlock(chan);
wait_for_hangup(chan, data);
return -1;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
{
int delay = 0;
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(delay);
AST_APP_ARG(answer_cdr);
);
if (ast_strlen_zero(data)) {
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
return __ast_answer(chan, 0);
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP))
delay = atoi(data);
if (delay < 0) {
delay = 0;
}
if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
app_cdr,app_forkcdr,func_cdr: Synchronize with engine when manipulating state When doing the rework of the CDR engine that pushed all of the logic into cdr.c and made it respond to changes in channel state over Stasis, we knew that accessing the CDR engine from the dialplan would be "slightly" non-deterministic. Dialplan threads would be accessing CDRs while Stasis threads would be updating the state of said CDRs - whereas in the past, everything happened on the dialplan threads. Tests have shown that "slightly" is in reality "very". This patch synchronizes things by making the dialplan applications/functions that manipulate CDRs do so over Stasis. ForkCDR, NoCDR, ResetCDR, CDR, and CDR_PROP now all use Stasis to send their requests over to the CDR engine, and synchronize on the channel Stasis topic via a subscription so that they return their values/control to the dialplan at the appropriate time. While going through this, the following changes were also made: * DISA, which can reset the CDR when a user successfully authenticates, now just uses the ResetCDR app to do this. This prevents having to duplicate the same Stasis synchronization logic in that application. * Answer no longer disables CDRs. It actually didn't work anyway - calling DISABLE on the channel's CDR doesn't stop the CDR from getting the Answer time - it just kills all CDRs on that channel, which isn't what the caller would intend. (closes issue ASTERISK-22884) (closes issue ASTERISK-22886) Review: https://reviewboard.asterisk.org/r/3057/ ........ Merged revisions 404294 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404295 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-12-19 00:50:01 +00:00
ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
}
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
return __ast_answer(chan, delay);
}
static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
{
const char *options = data;
int answer = 1;
/* Some channels can receive DTMF in unanswered state; some cannot */
if (!ast_strlen_zero(options) && strchr(options, 'n')) {
answer = 0;
}
/* If the channel is hungup, stop waiting */
if (ast_check_hangup(chan)) {
return -1;
} else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
__ast_answer(chan, 0);
}
Merged revisions 335078 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r335078 | mjordan | 2011-09-09 11:27:01 -0500 (Fri, 09 Sep 2011) | 29 lines Merged revisions 335064 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r335064 | mjordan | 2011-09-09 11:09:09 -0500 (Fri, 09 Sep 2011) | 23 lines Updated SIP 484 handling; added Incomplete control frame When a SIP phone uses the dial application and receives a 484 Address Incomplete response, if overlapped dialing is enabled for SIP, then the 484 Address Incomplete is forwarded back to the SIP phone and the HANGUPCAUSE channel variable is set to 28. Previously, the Incomplete application dialplan logic was automatically triggered; now, explicit dialplan usage of the application is required. Additionally, this patch adds a new AST_CONTOL_FRAME type called AST_CONTROL_INCOMPLETE. If a channel driver receives this control frame, it is an indication that the dialplan expects more digits back from the device. If the device supports overlap dialing it should attempt to notify the device that the dialplan is waiting for more digits; otherwise, it can handle the frame in a manner appropriate to the channel driver. (closes issue ASTERISK-17288) Reported by: Mikael Carlsson Tested by: Matthew Jordan Review: https://reviewboard.asterisk.org/r/1416/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@335079 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-09 16:28:23 +00:00
ast_indicate(chan, AST_CONTROL_INCOMPLETE);
return AST_PBX_INCOMPLETE;
}
/*!
* \ingroup applications
*/
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
{
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
ast_log(AST_LOG_WARNING, "The SetAMAFlags application is deprecated. Please use the CHANNEL function instead.\n");
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
if (ast_strlen_zero(data)) {
ast_log(AST_LOG_WARNING, "No parameter passed to SetAMAFlags\n");
return 0;
}
/* Copy the AMA Flags as specified */
ast_channel_lock(chan);
Update Asterisk's CDRs for the new bridging framework This patch is the initial push to update Asterisk's CDR engine for the new bridging framework. This patch guts the existing CDR engine and builds the new on top of messages coming across Stasis. As changes in channel state and bridge state are detected, CDRs are built and dispatched accordingly. This fundamentally changes CDRs in a few ways. (1) CDRs are now *very* reflective of the actual state of channels and bridges. This means CDRs track well with what an actual channel is doing - which is useful in transfer scenarios (which were previously difficult to pin down). It does, however, mean that CDRs cannot be 'fooled'. Previous behavior in Asterisk allowed for CDR applications, channels, and other properties to be spoofed in parts of the code - this no longer works. (2) CDRs have defined behavior in multi-party scenarios. This behavior will not be what everyone wants, but it is a defined behavior and as such, it is predictable. (3) The CDR manipulation functions and applications have been overhauled. Major changes have been made to ResetCDR and ForkCDR in particular. Many of the options for these two applications no longer made any sense with the new framework and the (slightly) more immutable nature of CDRs. There are a plethora of other changes. For a full description of CDR behavior, see the CDR specification on the Asterisk wiki. (closes issue ASTERISK-21196) Review: https://reviewboard.asterisk.org/r/2486/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-06-17 03:00:38 +00:00
if (isdigit(data[0])) {
int amaflags;
if (sscanf(data, "%30d", &amaflags) != 1) {
ast_log(AST_LOG_WARNING, "Unable to set AMA flags on channel %s\n", ast_channel_name(chan));
ast_channel_unlock(chan);
return 0;
}
ast_channel_amaflags_set(chan, amaflags);
} else {
ast_channel_amaflags_set(chan, ast_channel_string2amaflag(data));
}
ast_channel_unlock(chan);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
{
int cause;
ast_set_hangupsource(chan, "dialplan/builtin", 0);
if (!ast_strlen_zero(data)) {
cause = ast_str2cause(data);
if (cause <= 0) {
if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
cause = 0;
}
}
} else {
cause = 0;
}
ast_channel_lock(chan);
if (cause <= 0) {
cause = ast_channel_hangupcause(chan);
if (cause <= 0) {
cause = AST_CAUSE_NORMAL_CLEARING;
}
}
ast_channel_hangupcause_set(chan, cause);
ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
ast_channel_unlock(chan);
return -1;
}
/*!
* \ingroup functions
*/
static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
{
struct ast_tm tm;
struct timeval tv;
char *remainder, result[30], timezone[80];
/* Turn off testing? */
if (!pbx_checkcondition(value)) {
pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
return 0;
}
/* Parse specified time */
if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
return -1;
}
sscanf(remainder, "%79s", timezone);
tv = ast_mktime(&tm, S_OR(timezone, NULL));
snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
return 0;
}
static struct ast_custom_function testtime_function = {
.name = "TESTTIME",
.write = testtime_write,
};
/*!
* \ingroup applications
*/
static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
{
char *s, *ts, *branch1, *branch2, *branch;
struct ast_timing timing;
const char *ctime;
struct timeval tv = ast_tvnow();
long timesecs;
if (!chan) {
ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
return -1;
}
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
return -1;
}
ts = s = ast_strdupa(data);
ast_channel_lock(chan);
if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", &timesecs) == 1) {
tv.tv_sec = timesecs;
} else if (ctime) {
ast_log(LOG_WARNING, "Using current time to evaluate\n");
/* Reset when unparseable */
pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
}
ast_channel_unlock(chan);
/* Separate the Goto path */
strsep(&ts, "?");
branch1 = strsep(&ts,":");
branch2 = strsep(&ts,"");
/* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
branch = branch1;
} else {
branch = branch2;
}
ast_destroy_timing(&timing);
if (ast_strlen_zero(branch)) {
ast_debug(1, "Not taking any branch\n");
return 0;
}
return pbx_builtin_goto(chan, branch);
}
/*!
* \ingroup applications
*/
static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
{
char *s, *appname;
struct ast_timing timing;
struct ast_app *app;
static const char * const usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s\n", usage);
return -1;
}
appname = ast_strdupa(data);
s = strsep(&appname, "?"); /* Separate the timerange and application name/data */
if (!appname) { /* missing application */
ast_log(LOG_WARNING, "%s\n", usage);
return -1;
}
if (!ast_build_timing(&timing, s)) {
ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
ast_destroy_timing(&timing);
return -1;
}
if (!ast_check_timing(&timing)) { /* outside the valid time window, just return */
ast_destroy_timing(&timing);
return 0;
}
ast_destroy_timing(&timing);
/* now split appname(appargs) */
if ((s = strchr(appname, '('))) {
char *e;
*s++ = '\0';
if ((e = strrchr(s, ')')))
*e = '\0';
else
ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
}
if ((app = pbx_findapp(appname))) {
return pbx_exec(chan, app, S_OR(s, ""));
} else {
ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
return -1;
}
}
/*!
* \ingroup applications
*/
static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
{
int ms;
/* Wait for "n" seconds */
if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
return ast_safe_sleep(chan, ms);
}
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
{
int ms, res;
struct ast_flags flags = {0};
char *opts[1] = { NULL };
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(timeout);
AST_APP_ARG(options);
);
if (!ast_strlen_zero(data)) {
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
} else
memset(&args, 0, sizeof(args));
if (args.options)
ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
} else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
!ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
} else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
struct ast_tone_zone_sound *ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
Merge a large set of updates to the Asterisk indications API. This patch includes a number of changes to the indications API. The primary motivation for this work was to improve stability. The object management in this API was significantly flawed, and a number of trivial situations could cause crashes. The changes included are: 1) Remove the module res_indications. This included the critical functionality that actually loaded the indications configuration. I have seen many people have Asterisk problems because they accidentally did not have an indications.conf present and loaded. Now, this code is in the core, and Asterisk will fail to start without indications configuration. There was one part of res_indications, the dialplan applications, which did belong in a module, and have been moved to a new module, app_playtones. 2) Object management has been significantly changed. Tone zones are now managed using astobj2, and it is no longer possible to crash Asterisk by issuing a reload that destroys tone zones while they are in use. 3) The API documentation has been filled out. 4) The API has been updated to follow our naming conventions. 5) Various bits of code throughout the tree have been updated to account for the API update. 6) Configuration parsing has been mostly re-written. 7) "Code cleanup" The code is from svn/asterisk/team/russell/indications/. Review: http://reviewboard.digium.com/r/149/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@176627 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-02-17 20:41:24 +00:00
if (ts) {
ast_playtones_start(chan, 0, ts->data, 0);
Merge a large set of updates to the Asterisk indications API. This patch includes a number of changes to the indications API. The primary motivation for this work was to improve stability. The object management in this API was significantly flawed, and a number of trivial situations could cause crashes. The changes included are: 1) Remove the module res_indications. This included the critical functionality that actually loaded the indications configuration. I have seen many people have Asterisk problems because they accidentally did not have an indications.conf present and loaded. Now, this code is in the core, and Asterisk will fail to start without indications configuration. There was one part of res_indications, the dialplan applications, which did belong in a module, and have been moved to a new module, app_playtones. 2) Object management has been significantly changed. Tone zones are now managed using astobj2, and it is no longer possible to crash Asterisk by issuing a reload that destroys tone zones while they are in use. 3) The API documentation has been filled out. 4) The API has been updated to follow our naming conventions. 5) Various bits of code throughout the tree have been updated to account for the API update. 6) Configuration parsing has been mostly re-written. 7) "Code cleanup" The code is from svn/asterisk/team/russell/indications/. Review: http://reviewboard.digium.com/r/149/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@176627 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-02-17 20:41:24 +00:00
ts = ast_tone_zone_sound_unref(ts);
} else {
ast_tonepair_start(chan, 350, 440, 0, 0);
Merge a large set of updates to the Asterisk indications API. This patch includes a number of changes to the indications API. The primary motivation for this work was to improve stability. The object management in this API was significantly flawed, and a number of trivial situations could cause crashes. The changes included are: 1) Remove the module res_indications. This included the critical functionality that actually loaded the indications configuration. I have seen many people have Asterisk problems because they accidentally did not have an indications.conf present and loaded. Now, this code is in the core, and Asterisk will fail to start without indications configuration. There was one part of res_indications, the dialplan applications, which did belong in a module, and have been moved to a new module, app_playtones. 2) Object management has been significantly changed. Tone zones are now managed using astobj2, and it is no longer possible to crash Asterisk by issuing a reload that destroys tone zones while they are in use. 3) The API documentation has been filled out. 4) The API has been updated to follow our naming conventions. 5) Various bits of code throughout the tree have been updated to account for the API update. 6) Configuration parsing has been mostly re-written. 7) "Code cleanup" The code is from svn/asterisk/team/russell/indications/. Review: http://reviewboard.digium.com/r/149/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@176627 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-02-17 20:41:24 +00:00
}
}
/* Wait for "n" seconds */
if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
/* Yay! */
} else if (ast_channel_pbx(chan)) {
ms = ast_channel_pbx(chan)->rtimeoutms;
} else {
ms = 10000;
}
res = ast_waitfordigit(chan, ms);
if (!res) {
if (ast_check_hangup(chan)) {
/* Call is hungup for some reason. */
res = -1;
} else if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_verb(3, "Timeout on %s, continuing...\n", ast_channel_name(chan));
} else if (ast_exists_extension(chan, ast_channel_context(chan), "t", 1,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_verb(3, "Timeout on %s, going to 't'\n", ast_channel_name(chan));
set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
} else if (ast_exists_extension(chan, ast_channel_context(chan), "e", 1,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
raise_exception(chan, "RESPONSETIMEOUT", 0); /* 0 will become 1, next time through the loop */
} else {
ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
ast_channel_context(chan));
res = -1;
}
}
if (ast_test_flag(&flags, WAITEXTEN_MOH))
ast_indicate(chan, AST_CONTROL_UNHOLD);
else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
ast_playtones_stop(chan);
return res;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_background(struct ast_channel *chan, const char *data)
{
int res = 0;
int mres = 0;
struct ast_flags flags = {0};
char *parse, exten[2] = "";
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
AST_APP_ARG(options);
AST_APP_ARG(lang);
AST_APP_ARG(context);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.lang))
args.lang = (char *)ast_channel_language(chan); /* XXX this is const */
if (ast_strlen_zero(args.context)) {
const char *context;
ast_channel_lock(chan);
if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
args.context = ast_strdupa(context);
} else {
args.context = ast_strdupa(ast_channel_context(chan));
}
ast_channel_unlock(chan);
}
if (args.options) {
if (!strcasecmp(args.options, "skip"))
flags.flags = BACKGROUND_SKIP;
else if (!strcasecmp(args.options, "noanswer"))
flags.flags = BACKGROUND_NOANSWER;
else
ast_app_parse_options(background_opts, &flags, NULL, args.options);
}
/* Answer if need be */
if (ast_channel_state(chan) != AST_STATE_UP) {
if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
goto done;
} else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
res = ast_answer(chan);
}
}
if (!res) {
char *back = ast_strip(args.filename);
char *front;
ast_stopstream(chan); /* Stop anything playing */
/* Stream the list of files */
while (!res && (front = strsep(&back, "&")) ) {
if ( (res = ast_streamfile(chan, front, args.lang)) ) {
Replace direct access to channel name with accessor functions There are many benefits to making the ast_channel an opaque handle, from increasing maintainability to presenting ways to kill masquerades. This patch kicks things off by taking things a field at a time, renaming the field to '__do_not_use_${fieldname}' and then writing setters/getters and converting the existing code to using them. When all fields are done, we can move ast_channel to a C file from channel.h and lop off the '__do_not_use_'. This patch sets up main/channel_interal_api.c to be the only file that actually accesses the ast_channel's fields directly. The intent would be for any API functions in channel.c to use the accessor functions. No more monkeying around with channel internals. We should use our own APIs. The interesting changes in this patch are the addition of channel_internal_api.c, the moving of the AST_DATA stuff from channel.c to channel_internal_api.c (note: the AST_DATA stuff will have to be reworked to use accessor functions when ast_channel is really opaque), and some re-working of the way channel iterators/callbacks are handled so as to avoid creating fake ast_channels on the stack to pass in matching data by directly accessing fields (since "name" is a stringfield and the fake channel doesn't init the stringfields, you can't use the ast_channel_name_set() function). I went with ast_channel_name(chan) for a getter, and ast_channel_name_set(chan, name) for a setter. The majority of the grunt-work for this change was done by writing a semantic patch using Coccinelle ( http://coccinelle.lip6.fr/ ). Review: https://reviewboard.asterisk.org/r/1655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@350223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-09 22:15:50 +00:00
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
res = 0;
mres = 1;
break;
}
if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
res = ast_waitstream(chan, "");
} else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
res = ast_waitstream_exten(chan, args.context);
} else {
res = ast_waitstream(chan, AST_DIGIT_ANY);
}
ast_stopstream(chan);
}
}
/*
* If the single digit DTMF is an extension in the specified context, then
* go there and signal no DTMF. Otherwise, we should exit with that DTMF.
* If we're in Macro, we'll exit and seek that DTMF as the beginning of an
* extension in the Macro's calling context. If we're not in Macro, then
* we'll simply seek that extension in the calling context. Previously,
* someone complained about the behavior as it related to the interior of a
* Gosub routine, and the fix (#14011) inadvertently broke FreePBX
* (#14940). This change should fix both of these situations, but with the
* possible incompatibility that if a single digit extension does not exist
* (but a longer extension COULD have matched), it would have previously
* gone immediately to the "i" extension, but will now need to wait for a
* timeout.
*
* Later, we had to add a flag to disable this workaround, because AGI
* users can EXEC Background and reasonably expect that the DTMF code will
* be returned (see #16434).
*/
if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
&& (exten[0] = res)
&& ast_canmatch_extension(chan, args.context, exten, 1,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
&& !ast_matchmore_extension(chan, args.context, exten, 1,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
char buf[2] = { 0, };
snprintf(buf, sizeof(buf), "%c", res);
ast_channel_exten_set(chan, buf);
ast_channel_context_set(chan, args.context);
ast_channel_priority_set(chan, 0);
res = 0;
}
done:
pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
return res;
}
/*! Goto
* \ingroup applications
*/
static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
{
int res = ast_parseable_goto(chan, data);
if (!res)
ast_verb(3, "Goto (%s,%s,%d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1);
return res;
}
int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
{
struct ast_var_t *variables;
const char *var, *val;
int total = 0;
if (!chan)
return 0;
ast_str_reset(*buf);
ast_channel_lock(chan);
AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
/* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
) {
if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
break;
} else
total++;
} else
break;
}
ast_channel_unlock(chan);
return total;
}
const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
{
struct ast_var_t *variables;
const char *ret = NULL;
int i;
struct varshead *places[2] = { NULL, &globals };
if (!name)
return NULL;
if (chan) {
ast_channel_lock(chan);
places[0] = ast_channel_varshead(chan);
}
for (i = 0; i < 2; i++) {
if (!places[i])
continue;
if (places[i] == &globals)
ast_rwlock_rdlock(&globalslock);
AST_LIST_TRAVERSE(places[i], variables, entries) {
if (!strcmp(name, ast_var_name(variables))) {
ret = ast_var_value(variables);
break;
}
}
if (places[i] == &globals)
ast_rwlock_unlock(&globalslock);
if (ret)
break;
}
if (chan)
ast_channel_unlock(chan);
return ret;
}
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
{
struct ast_var_t *newvariable;
struct varshead *headp;
if (name[strlen(name)-1] == ')') {
char *function = ast_strdupa(name);
ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
ast_func_write(chan, function, value);
return;
}
if (chan) {
ast_channel_lock(chan);
headp = ast_channel_varshead(chan);
} else {
ast_rwlock_wrlock(&globalslock);
headp = &globals;
}
if (value && (newvariable = ast_var_assign(name, value))) {
if (headp == &globals)
ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
AST_LIST_INSERT_HEAD(headp, newvariable, entries);
}
if (chan)
ast_channel_unlock(chan);
else
ast_rwlock_unlock(&globalslock);
}
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
{
struct ast_var_t *newvariable;
struct varshead *headp;
const char *nametail = name;
if (name[strlen(name) - 1] == ')') {
char *function = ast_strdupa(name);
return ast_func_write(chan, function, value);
}
if (chan) {
ast_channel_lock(chan);
headp = ast_channel_varshead(chan);
} else {
ast_rwlock_wrlock(&globalslock);
headp = &globals;
}
/* For comparison purposes, we have to strip leading underscores */
if (*nametail == '_') {
nametail++;
if (*nametail == '_')
nametail++;
}
AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
if (strcmp(ast_var_name(newvariable), nametail) == 0) {
/* there is already such a variable, delete it */
AST_LIST_REMOVE_CURRENT(entries);
ast_var_delete(newvariable);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
if (value && (newvariable = ast_var_assign(name, value))) {
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
if (headp == &globals) {
ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
stasis: Reduce creation of channel snapshots to improve performance During some performance testing of Asterisk with AGI, ARI, and lots of Local channels, we noticed that there's quite a hit in performance during channel creation and releasing to the dialplan (ARI continue). After investigating the performance spike that occurs during channel creation, we discovered that we create a lot of channel snapshots that are technically unnecessary. This includes creating snapshots during: * AGI execution * Returning objects for ARI commands * During some Local channel operations * During some dialling operations * During variable setting * During some bridging operations And more. This patch does the following: - It removes a number of fields from channel snapshots. These fields were rarely used, were expensive to have on the snapshot, and hurt performance. This included formats, translation paths, Log Call ID, callgroup, pickup group, and all channel variables. As a result, AMI Status, "core show channel", "core show channelvar", and "pjsip show channel" were modified to either hit the live channel or not show certain pieces of data. While this is unfortunate, the performance gain from this patch is worth the loss in behaviour. - It adds a mechanism to publish a cached snapshot + blob. A large number of publications were changed to use this, including: - During Dial begin - During Variable assignment (if no AMI variables are emitted - if AMI variables are set, we have to make snapshots when a variable is changed) - During channel pickup - When a channel is put on hold/unhold - When a DTMF digit is begun/ended - When creating a bridge snapshot - When an AOC event is raised - During Local channel optimization/Local bridging - When endpoint snapshots are generated - All AGI events - All ARI responses that return a channel - Events in the AgentPool, MeetMe, and some in Queue - Additionally, some extraneous channel snapshots were being made that were unnecessary. These were removed. - The result of ast_hashtab_hash_string is now cached in stasis_cache. This reduces a large number of calls to ast_hashtab_hash_string, which reduced the amount of time spent in this function in gprof by around 50%. #ASTERISK-23811 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/3568/ ........ Merged revisions 416211 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416216 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-06-13 18:24:49 +00:00
}
AST_LIST_INSERT_HEAD(headp, newvariable, entries);
ast_channel_publish_varset(chan, name, value);
}
if (chan)
ast_channel_unlock(chan);
else
ast_rwlock_unlock(&globalslock);
return 0;
}
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
{
char *name, *value, *mydata;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
return 0;
}
mydata = ast_strdupa(data);
name = strsep(&mydata, "=");
value = mydata;
if (!value) {
ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
return 0;
}
if (strchr(name, ' ')) {
ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
}
pbx_builtin_setvar_helper(chan, name, value);
return 0;
}
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
{
char *data;
int x;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(pair)[24];
);
AST_DECLARE_APP_ARGS(pair,
AST_APP_ARG(name);
AST_APP_ARG(value);
);
if (ast_strlen_zero(vdata)) {
ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
return 0;
}
data = ast_strdupa(vdata);
AST_STANDARD_APP_ARGS(args, data);
for (x = 0; x < args.argc; x++) {
AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
if (pair.argc == 2) {
pbx_builtin_setvar_helper(chan, pair.name, pair.value);
if (strchr(pair.name, ' '))
ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
} else if (!chan) {
ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
} else {
ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
}
}
return 0;
}
int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
{
char *name;
char *value;
char *channel;
char tmp[VAR_BUF_SIZE];
static int deprecation_warning = 0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
return 0;
}
tmp[0] = 0;
if (!deprecation_warning) {
ast_log(LOG_WARNING, "ImportVar is deprecated. Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
deprecation_warning = 1;
}
value = ast_strdupa(data);
name = strsep(&value,"=");
channel = strsep(&value,",");
if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
struct ast_channel *chan2 = ast_channel_get_by_name(channel);
if (chan2) {
char *s = ast_alloca(strlen(value) + 4);
sprintf(s, "${%s}", value);
pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
Convert the ast_channel data structure over to the astobj2 framework. There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-04-24 14:04:26 +00:00
chan2 = ast_channel_unref(chan2);
}
pbx_builtin_setvar_helper(chan, name, tmp);
}
return(0);
}
static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
{
return 0;
}
void pbx_builtin_clear_globals(void)
{
struct ast_var_t *vardata;
ast_rwlock_wrlock(&globalslock);
while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
ast_var_delete(vardata);
ast_rwlock_unlock(&globalslock);
}
int pbx_checkcondition(const char *condition)
{
int res;
if (ast_strlen_zero(condition)) { /* NULL or empty strings are false */
return 0;
} else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
return res;
} else { /* Strings are true */
return 1;
}
}
static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
{
char *condition, *branch1, *branch2, *branch;
char *stringp;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
return 0;
}
stringp = ast_strdupa(data);
condition = strsep(&stringp,"?");
branch1 = strsep(&stringp,":");
branch2 = strsep(&stringp,"");
branch = pbx_checkcondition(condition) ? branch1 : branch2;
if (ast_strlen_zero(branch)) {
ast_debug(1, "Not taking any branch\n");
return 0;
}
return pbx_builtin_goto(chan, branch);
}
static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
{
char tmp[256];
char *number = tmp;
int number_val;
char *options;
int res;
int interrupt = 0;
const char *interrupt_string;
ast_channel_lock(chan);
interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
if (ast_true(interrupt_string)) {
interrupt = 1;
}
ast_channel_unlock(chan);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
return -1;
}
ast_copy_string(tmp, data, sizeof(tmp));
strsep(&number, ",");
if (sscanf(tmp, "%d", &number_val) != 1) {
ast_log(LOG_WARNING, "argument '%s' to SayNumber could not be parsed as a number.\n", tmp);
return 0;
}
options = strsep(&number, ",");
if (options) {
if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
strcasecmp(options, "c") && strcasecmp(options, "n") ) {
ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
return -1;
}
}
res = ast_say_number(chan, number_val, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), options);
if (res < 0) {
ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
}
return interrupt ? res : 0;
}
static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
{
int res = 0;
int interrupt = 0;
const char *interrupt_string;
ast_channel_lock(chan);
interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
if (ast_true(interrupt_string)) {
interrupt = 1;
}
ast_channel_unlock(chan);
if (data) {
res = ast_say_digit_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
}
return res;
}
static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data)
{
int res = 0;
int sensitivity = 0;
char *parse;
int interrupt = 0;
const char *interrupt_string;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(options);
AST_APP_ARG(characters);
);
ast_channel_lock(chan);
interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
if (ast_true(interrupt_string)) {
interrupt = 1;
}
ast_channel_unlock(chan);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n");
return 0;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (!args.options || strlen(args.options) != 1) {
ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n");
return 0;
}
switch (args.options[0]) {
case 'a':
sensitivity = AST_SAY_CASE_ALL;
break;
case 'l':
sensitivity = AST_SAY_CASE_LOWER;
break;
case 'n':
sensitivity = AST_SAY_CASE_NONE;
break;
case 'u':
sensitivity = AST_SAY_CASE_UPPER;
break;
default:
ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options);
return 0;
}
res = ast_say_character_str(chan, args.characters, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), sensitivity);
return res;
}
static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
{
int res = 0;
int interrupt = 0;
const char *interrupt_string;
ast_channel_lock(chan);
interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
if (ast_true(interrupt_string)) {
interrupt = 1;
}
ast_channel_unlock(chan);
if (data) {
res = ast_say_character_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan), AST_SAY_CASE_NONE);
}
return res;
}
static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
{
int res = 0;
int interrupt = 0;
const char *interrupt_string;
ast_channel_lock(chan);
interrupt_string = pbx_builtin_getvar_helper(chan, "SAY_DTMF_INTERRUPT");
if (ast_true(interrupt_string)) {
interrupt = 1;
}
ast_channel_unlock(chan);
if (data)
res = ast_say_phonetic_str(chan, data, interrupt ? AST_DIGIT_ANY : "", ast_channel_language(chan));
return res;
}
Multiple revisions 399887,400138,400178,400180-400181 ........ r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line Minor performance bump by not allocate manager variable struct if we don't need it ........ r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines Stasis performance improvements This patch addresses several performance problems that were found in the initial performance testing of Asterisk 12. The Stasis dispatch object was allocated as an AO2 object, even though it has a very confined lifecycle. This was replaced with a straight ast_malloc(). The Stasis message router was spending an inordinate amount of time searching hash tables. In this case, most of our routers had 6 or fewer routes in them to begin with. This was replaced with an array that's searched linearly for the route. We more heavily rely on AO2 objects in Asterisk 12, and the memset() in ao2_ref() actually became noticeable on the profile. This was #ifdef'ed to only run when AO2_DEBUG was enabled. After being misled by an erroneous comment in taskprocessor.c during profiling, the wrong comment was removed. Review: https://reviewboard.asterisk.org/r/2873/ ........ r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines Taskprocessor optimization; switch Stasis to use taskprocessors This patch optimizes taskprocessor to use a semaphore for signaling, which the OS can do a better job at managing contention and waiting that we can with a mutex and condition. The taskprocessor execution was also slightly optimized to reduce the number of locks taken. The only observable difference in the taskprocessor implementation is that when the final reference to the taskprocessor goes away, it will execute all tasks to completion instead of discarding the unexecuted tasks. For systems where unnamed semaphores are not supported, a really simple semaphore implementation is provided. (Which gives identical performance as the original taskprocessor implementation). The way we ended up implementing Stasis caused the threadpool to be a burden instead of a boost to performance. This was switched to just use taskprocessors directly for subscriptions. Review: https://reviewboard.asterisk.org/r/2881/ ........ r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines Optimize how Stasis forwards are dispatched This patch optimizes how forwards are dispatched in Stasis. Originally, forwards were dispatched as subscriptions that are invoked on the publishing thread. This did not account for the vast number of forwards we would end up having in the system, and the amount of work it would take to walk though the forward subscriptions. This patch modifies Stasis so that rather than walking the tree of forwards on every dispatch, when forwards and subscriptions are changed, the subscriber list for every topic in the tree is changed. This has a couple of benefits. First, this reduces the workload of dispatching messages. It also reduces contention when dispatching to different topics that happen to forward to the same aggregation topic (as happens with all of the channel, bridge and endpoint topics). Since forwards are no longer subscriptions, the bulk of this patch is simply changing stasis_subscription objects to stasis_forward objects (which, admittedly, I should have done in the first place.) Since this required me to yet again put in a growing array, I finally abstracted that out into a set of ast_vector macros in asterisk/vector.h. Review: https://reviewboard.asterisk.org/r/2883/ ........ r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines Remove dispatch object allocation from Stasis publishing While looking for areas for performance improvement, I realized that an unused feature in Stasis was negatively impacting performance. When a message is sent to a subscriber, a dispatch object is allocated for the dispatch, containing the topic the message was published to, the subscriber the message is being sent to, and the message itself. The topic is actually unused by any subscriber in Asterisk today. And the subscriber is associated with the taskprocessor the message is being dispatched to. First, this patch removes the unused topic parameter from Stasis subscription callbacks. Second, this patch introduces the concept of taskprocessor local data, data that may be set on a taskprocessor and provided along with the data pointer when a task is pushed using the ast_taskprocessor_push_local() call. This allows the task to have both data specific to that taskprocessor, in addition to data specific to that invocation. With those two changes, the dispatch object can be removed completely, and the message is simply refcounted and sent directly to the taskprocessor. Review: https://reviewboard.asterisk.org/r/2884/ ........ Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
{
struct ast_presence_state_message *presence_state;
struct ast_hint *hint;
struct ast_str *hint_app = NULL;
struct ast_hintdevice *device;
struct ast_hintdevice *cmpdevice;
struct ao2_iterator *dev_iter;
struct ao2_iterator cb_iter;
char context_name[AST_MAX_CONTEXT];
char exten_name[AST_MAX_EXTENSION];
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
if (stasis_message_type(msg) != ast_presence_state_message_type()) {
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
return;
}
presence_state = stasis_message_data(msg);
if (ao2_container_count(hintdevices) == 0) {
/* There are no hints monitoring devices. */
return;
}
hint_app = ast_str_create(1024);
if (!hint_app) {
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
return;
}
cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(presence_state->provider));
strcpy(cmpdevice->hintdevice, presence_state->provider);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
dev_iter = ao2_t_callback(hintdevices,
OBJ_POINTER | OBJ_MULTIPLE,
hintdevice_cmp_multiple,
cmpdevice,
"find devices in container");
if (!dev_iter) {
ast_mutex_unlock(&context_merge_lock);
ast_free(hint_app);
return;
}
for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
struct ast_state_cb *state_cb;
if (!device->hint) {
/* Should never happen. */
continue;
}
hint = device->hint;
ao2_lock(hint);
if (!hint->exten) {
/* The extension has already been destroyed */
ao2_unlock(hint);
continue;
}
/*
* Save off strings in case the hint extension gets destroyed
* while we are notifying the watchers.
*/
ast_copy_string(context_name,
ast_get_context_name(ast_get_extension_context(hint->exten)),
sizeof(context_name));
ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
sizeof(exten_name));
ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
ao2_unlock(hint);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
/* Check to see if update is necessary */
if ((hint->last_presence_state == presence_state->state) &&
((hint->last_presence_subtype && presence_state->subtype && !strcmp(hint->last_presence_subtype, presence_state->subtype)) || (!hint->last_presence_subtype && !presence_state->subtype)) &&
((hint->last_presence_message && presence_state->message && !strcmp(hint->last_presence_message, presence_state->message)) || (!hint->last_presence_message && !presence_state->message))) {
/* this update is the same as the last, do nothing */
continue;
}
/* update new values */
ast_free(hint->last_presence_subtype);
ast_free(hint->last_presence_message);
hint->last_presence_state = presence_state->state;
hint->last_presence_subtype = presence_state->subtype ? ast_strdup(presence_state->subtype) : NULL;
hint->last_presence_message = presence_state->message ? ast_strdup(presence_state->message) : NULL;
/* For general callbacks */
cb_iter = ao2_iterator_init(statecbs, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
execute_state_callback(state_cb->change_cb,
context_name,
exten_name,
state_cb->data,
AST_HINT_UPDATE_PRESENCE,
hint,
NULL);
}
ao2_iterator_destroy(&cb_iter);
/* For extension callbacks */
cb_iter = ao2_iterator_init(hint->callbacks, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
execute_state_callback(state_cb->change_cb,
context_name,
exten_name,
state_cb->data,
AST_HINT_UPDATE_PRESENCE,
hint,
NULL);
}
ao2_iterator_destroy(&cb_iter);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
}
ao2_iterator_destroy(dev_iter);
ast_mutex_unlock(&context_merge_lock);
ast_free(hint_app);
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
}
/*!
* \internal
* \brief Implements the hints data provider.
*/
static int hints_data_provider_get(const struct ast_data_search *search,
struct ast_data *data_root)
{
struct ast_data *data_hint;
struct ast_hint *hint;
int watchers;
struct ao2_iterator i;
if (ao2_container_count(hints) == 0) {
return 0;
}
i = ao2_iterator_init(hints, 0);
for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
watchers = ao2_container_count(hint->callbacks);
data_hint = ast_data_add_node(data_root, "hint");
if (!data_hint) {
continue;
}
ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state));
ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, ""));
ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, ""));
ast_data_add_int(data_hint, "watchers", watchers);
if (!ast_data_search_match(search, data_hint)) {
ast_data_remove_node(data_root, data_hint);
}
}
ao2_iterator_destroy(&i);
return 0;
}
static const struct ast_data_handler hints_data_provider = {
.version = AST_DATA_HANDLER_VERSION,
.get = hints_data_provider_get
};
static const struct ast_data_entry pbx_data_providers[] = {
AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
};
static int action_extensionstatelist(struct mansession *s, const struct message *m)
{
const char *action_id = astman_get_header(m, "ActionID");
struct ast_hint *hint;
struct ao2_iterator it_hints;
int hint_count = 0;
if (!hints) {
astman_send_error(s, m, "No dialplan hints are available");
return 0;
}
astman_send_listack(s, m, "Extension Statuses will follow", "start");
ao2_lock(hints);
it_hints = ao2_iterator_init(hints, 0);
for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
ao2_lock(hint);
/* Ignore pattern matching hints; they are stored in the
* hints container but aren't real from the perspective of
* an AMI user
*/
if (hint->exten->exten[0] == '_') {
ao2_unlock(hint);
continue;
}
++hint_count;
astman_append(s, "Event: ExtensionStatus\r\n");
if (!ast_strlen_zero(action_id)) {
astman_append(s, "ActionID: %s\r\n", action_id);
}
astman_append(s,
"Exten: %s\r\n"
"Context: %s\r\n"
"Hint: %s\r\n"
"Status: %d\r\n"
"StatusText: %s\r\n\r\n",
hint->exten->exten,
hint->exten->parent->name,
hint->exten->app,
hint->laststate,
ast_extension_state2str(hint->laststate));
ao2_unlock(hint);
}
ao2_iterator_destroy(&it_hints);
ao2_unlock(hints);
AMI: Make AMI actions that generate event lists consistent. * Made the following AMI actions use list API calls for consistency: Agents BridgeInfo BridgeList BridgeTechnologyList ConfbridgeLIst ConfbridgeLIstRooms CoreShowChannels DAHDIShowChannels DBGet DeviceStateList ExtensionStateList FAXSessions Hangup IAXpeerlist IAXpeers IAXregistry MeetmeList MeetmeListRooms MWIGet ParkedCalls Parkinglots PJSIPShowEndpoint PJSIPShowEndpoints PJSIPShowRegistrationsInbound PJSIPShowRegistrationsOutbound PJSIPShowResourceLists PJSIPShowSubscriptionsInbound PJSIPShowSubscriptionsOutbound PresenceStateList PRIShowSpans QueueStatus QueueSummary ShowDialPlan SIPpeers SIPpeerstatus SIPshowregistry SKINNYdevices SKINNYlines Status VoicemailUsersList * Incremented the AMI version to 2.7.0. * Changed astman_send_listack() to not use the listflag parameter and always set the value to "Start" so the start capitalization is consistent. i.e., The FAXSessions used "Start" while the rest of the system used "start". The corresponding complete event always used "Complete". * Fixed ami_show_resource_lists() "PJSIPShowResourceLists" to output the AMI ActionID for all of its list events. * Fixed off-nominal AMI protocol error in manager_bridge_info(), manager_parking_status_single_lot(), and manager_parking_status_all_lots(). Use of astman_send_error() after responding to the original AMI action request violates the action response pattern by sending two responses. * Fixed minor protocol error in action_getconfig() when no requested categories are found. Each line needs to be formatted as "Header: text". * Fixed off-nominal memory leak in manager_build_parked_call_string(). * Eliminated unnecessary use of RAII_VAR() in ami_subscription_detail(). ASTERISK-24049 #close Reported by: Jonathan Rose Review: https://reviewboard.asterisk.org/r/4315/ ........ Merged revisions 430434 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2015-01-09 18:16:54 +00:00
astman_send_list_complete_start(s, m, "ExtensionStateListComplete", hint_count);
astman_send_list_complete_end(s);
return 0;
}
/*!
* \internal
* \brief Clean up resources on Asterisk shutdown.
*
* \note Cleans up resources allocated in load_pbx
*/
static void unload_pbx(void)
{
int x;
presence_state_sub = stasis_unsubscribe_and_join(presence_state_sub);
device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
/* Unregister builtin applications */
for (x = 0; x < ARRAY_LEN(builtins); x++) {
ast_unregister_application(builtins[x].name);
}
ast_manager_unregister("ShowDialPlan");
ast_manager_unregister("ExtensionStateList");
ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
ast_custom_function_unregister(&exception_function);
ast_custom_function_unregister(&testtime_function);
ast_data_unregister(NULL);
}
int load_pbx(void)
{
int res = 0;
int x;
ast_register_cleanup(unload_pbx);
/* Initialize the PBX */
ast_verb(1, "Asterisk PBX Core Initializing\n");
Logger/CLI/etc.: Fix some aesthetic issues; reduce chatty verbose messages This patch addresses some aesthetic issues in Asterisk. These are all just minor tweaks to improve the look of the CLI when used in a variety of settings. Specifically: * A number of chatty verbose messages were removed or demoted to DEBUG messages. Verbose messages with a verbosity level of 5 or higher were - if kept as verbose messages - demoted to level 4. Several messages that were emitted at verbose level 3 were demoted to 4, as announcement of dialplan applications being executed occur at level 3 (and so the effects of those applications should generally be less). * Some verbose messages that only appear when their respective 'debug' options are enabled were bumped up to always be displayed. * Prefix/timestamping of verbose messages were moved to the verboser handlers. This was done to prevent duplication of prefixes when the timestamp option (-T) is used with the CLI. * Verbose magic is removed from messages before being emitted to non-verboser handlers. This prevents the magic in multi-line verbose messages (such as SIP debug traces or the output of DumpChan) from being written to files. * _Slightly_ better support for the "light background" option (-W) was added. This includes using ast_term_quit in the output of XML documentation help, as well as changing the "Asterisk Ready" prompt to bright green on the default background (which stands a better chance of being displayed properly than bright white). Review: https://reviewboard.asterisk.org/r/3547/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@414798 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-05-28 22:54:12 +00:00
ast_verb(2, "Registering builtin applications and functions:\n");
ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
__ast_custom_function_register(&exception_function, NULL);
__ast_custom_function_register(&testtime_function, NULL);
/* Register builtin applications */
for (x = 0; x < ARRAY_LEN(builtins); x++) {
if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
return -1;
}
}
/* Register manager application */
res |= ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
res |= ast_manager_register_xml_core("ExtensionStateList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstatelist);
if (res) {
return -1;
}
if (!(device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL))) {
Merge changes dealing with support for Digium phones. Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-06-04 20:26:12 +00:00
return -1;
}
if (!(presence_state_sub = stasis_subscribe(ast_presence_state_topic_all(), presence_state_cb, NULL))) {
return -1;
}
return 0;
}
/*
* Lock context list functions ...
*/
int ast_wrlock_contexts(void)
{
return ast_mutex_lock(&conlock);
}
int ast_rdlock_contexts(void)
{
return ast_mutex_lock(&conlock);
}
int ast_unlock_contexts(void)
{
return ast_mutex_unlock(&conlock);
}
/*
* Lock context ...
*/
int ast_wrlock_context(struct ast_context *con)
{
return ast_rwlock_wrlock(&con->lock);
}
int ast_rdlock_context(struct ast_context *con)
{
return ast_rwlock_rdlock(&con->lock);
}
int ast_unlock_context(struct ast_context *con)
{
return ast_rwlock_unlock(&con->lock);
}
/*
* Name functions ...
*/
const char *ast_get_context_name(struct ast_context *con)
{
return con ? con->name : NULL;
}
struct ast_context *ast_get_extension_context(struct ast_exten *exten)
{
return exten ? exten->parent : NULL;
}
const char *ast_get_extension_name(struct ast_exten *exten)
{
return exten ? exten->exten : NULL;
}
const char *ast_get_extension_label(struct ast_exten *exten)
{
return exten ? exten->label : NULL;
}
const char *ast_get_include_name(struct ast_include *inc)
{
return inc ? inc->name : NULL;
}
const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
{
return ip ? ip->pattern : NULL;
}
int ast_get_extension_priority(struct ast_exten *exten)
{
return exten ? exten->priority : -1;
}
/*
* Registrar info functions ...
*/
const char *ast_get_context_registrar(struct ast_context *c)
{
return c ? c->registrar : NULL;
}
const char *ast_get_extension_registrar(struct ast_exten *e)
{
return e ? e->registrar : NULL;
}
const char *ast_get_include_registrar(struct ast_include *i)
{
return i ? i->registrar : NULL;
}
const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
{
return ip ? ip->registrar : NULL;
}
int ast_get_extension_matchcid(struct ast_exten *e)
{
return e ? e->matchcid : 0;
}
const char *ast_get_extension_cidmatch(struct ast_exten *e)
{
return e ? e->cidmatch : NULL;
}
const char *ast_get_extension_app(struct ast_exten *e)
{
return e ? e->app : NULL;
}
void *ast_get_extension_app_data(struct ast_exten *e)
{
return e ? e->data : NULL;
}
const char *ast_get_switch_name(struct ast_sw *sw)
{
return sw ? sw->name : NULL;
}
const char *ast_get_switch_data(struct ast_sw *sw)
{
return sw ? sw->data : NULL;
}
(closes issue #12238) Reported by: mvanbaak Tested by: murf, mvanbaak Due to a bug that occurred when merge_contexts_and_delete scanned the "old" or existing contexts, and found a context that doesn't exist in the new set, yet owned by a different registrar. The context is created in the new set, with the old registrar, and and all the priorities and extens that have a different registrar are copied into it. But, not the includes, ignorepats, and switches. I added code to do this immediately after the context is created. This still leaves a logical hole in the code. If you define a context in two places, (eg. in extensions.conf and also in extensions.ael), and they both have includes, but different in composition, no new context will be generated, and therefore the 'old' includes, switches, and ignorepats will not be copied. I'd have added code to simply add any non-duplicates into the 'new' context that had a different registrar, but there is one big complication: includes, and switches are definitely order dependent. (ignorepats I'm not sure about). And we'll have to develop some sort of policy about how we merge order dependent lists, especially if the intersection of the two sets is empty. (in other words, they do not have any elements in common). Do the new go first, or the old? I've elected to punt this issue until a user complains. Hopefully, this is pretty rare thing. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@109169 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2008-03-17 17:47:36 +00:00
int ast_get_switch_eval(struct ast_sw *sw)
{
return sw->eval;
}
const char *ast_get_switch_registrar(struct ast_sw *sw)
{
return sw ? sw->registrar : NULL;
}
/*
* Walking functions ...
*/
struct ast_context *ast_walk_contexts(struct ast_context *con)
{
return con ? con->next : contexts;
}
struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
struct ast_exten *exten)
{
if (!exten)
return con ? con->root : NULL;
else
return exten->next;
}
struct ast_sw *ast_walk_context_switches(struct ast_context *con,
struct ast_sw *sw)
{
if (!sw)
return con ? AST_LIST_FIRST(&con->alts) : NULL;
else
return AST_LIST_NEXT(sw, list);
}
struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
struct ast_exten *priority)
{
return priority ? priority->peer : exten;
}
struct ast_include *ast_walk_context_includes(struct ast_context *con,
struct ast_include *inc)
{
if (!inc)
return con ? con->includes : NULL;
else
return inc->next;
}
struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
struct ast_ignorepat *ip)
{
if (!ip)
return con ? con->ignorepats : NULL;
else
return ip->next;
}
int ast_context_verify_includes(struct ast_context *con)
{
struct ast_include *inc = NULL;
int res = 0;
while ( (inc = ast_walk_context_includes(con, inc)) ) {
if (ast_context_find(inc->rname))
continue;
res = -1;
ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
ast_get_context_name(con), inc->rname);
break;
}
return res;
}
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
{
int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
if (!chan)
return -2;
if (context == NULL)
context = ast_channel_context(chan);
if (exten == NULL)
exten = ast_channel_exten(chan);
goto_func = (async) ? ast_async_goto : ast_explicit_goto;
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
if (ast_exists_extension(chan, context, exten, priority,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
return goto_func(chan, context, exten, priority);
else {
return AST_PBX_GOTO_FAILED;
}
}
int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
{
return __ast_goto_if_exists(chan, context, exten, priority, 0);
}
int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
{
return __ast_goto_if_exists(chan, context, exten, priority, 1);
}
static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
{
char *exten, *pri, *context;
char *stringp;
int ipri;
int mode = 0;
if (ast_strlen_zero(goto_string)) {
ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
return -1;
}
stringp = ast_strdupa(goto_string);
context = strsep(&stringp, ","); /* guaranteed non-null */
exten = strsep(&stringp, ",");
pri = strsep(&stringp, ",");
if (!exten) { /* Only a priority in this one */
pri = context;
exten = NULL;
context = NULL;
} else if (!pri) { /* Only an extension and priority in this one */
pri = exten;
exten = context;
context = NULL;
}
if (*pri == '+') {
mode = 1;
pri++;
} else if (*pri == '-') {
mode = -1;
pri++;
}
if (sscanf(pri, "%30d", &ipri) != 1) {
ipri = ast_findlabel_extension(chan, context ? context : ast_channel_context(chan),
exten ? exten : ast_channel_exten(chan), pri,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
ast_callerid restructuring The purpose of this patch is to eliminate struct ast_callerid since it has turned into a miscellaneous collection of various party information. Eliminate struct ast_callerid and replace it with the following struct organization: struct ast_party_name { char *str; int char_set; int presentation; unsigned char valid; }; struct ast_party_number { char *str; int plan; int presentation; unsigned char valid; }; struct ast_party_subaddress { char *str; int type; unsigned char odd_even_indicator; unsigned char valid; }; struct ast_party_id { struct ast_party_name name; struct ast_party_number number; struct ast_party_subaddress subaddress; char *tag; }; struct ast_party_dialed { struct { char *str; int plan; } number; struct ast_party_subaddress subaddress; int transit_network_select; }; struct ast_party_caller { struct ast_party_id id; char *ani; int ani2; }; The new organization adds some new information as well. * The party name and number now have their own presentation value that can be manipulated independently. ISDN supplies the presentation value for the name and number at different times with the possibility that they could be different. * The party name and number now have a valid flag. Before this change the name or number string could be empty if the presentation were restricted. Most channel drivers assume that the name or number is then simply not available instead of indicating that the name or number was restricted. * The party name now has a character set value. SIP and Q.SIG have the ability to indicate what character set a name string is using so it could be presented properly. * The dialed party now has a numbering plan value that could be useful to have available. The various channel drivers will need to be updated to support the new core features as needed. They have simply been converted to supply current functionality at this time. The following items of note were either corrected or enhanced: * The CONNECTEDLINE() and REDIRECTING() dialplan functions were consolidated into func_callerid.c to share party id handling code. * CALLERPRES() is now deprecated because the name and number have their own presentation values. * Fixed app_alarmreceiver.c write_metadata(). The workstring[] could contain garbage. It also can only contain the caller id number so using ast_callerid_parse() on it is silly. There was also a typo in the CALLERNAME if test. * Fixed app_rpt.c using ast_callerid_parse() on the channel's caller id number string. ast_callerid_parse() alters the given buffer which in this case is the channel's caller id number string. Then using ast_shrink_phone_number() could alter it even more. * Fixed caller ID name and number memory leak in chan_usbradio.c. * Fixed uninitialized char arrays cid_num[] and cid_name[] in sig_analog.c. * Protected access to a caller channel with lock in chan_sip.c. * Clarified intent of code in app_meetme.c sla_ring_station() and dial_trunk(). Also made save all caller ID data instead of just the name and number strings. * Simplified cdr.c set_one_cid(). It hand coded the ast_callerid_merge() function. * Corrected some weirdness with app_privacy.c's use of caller presentation. Review: https://reviewboard.asterisk.org/r/702/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@276347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-07-14 15:48:36 +00:00
if (ipri < 1) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
return -1;
} else
mode = 0;
}
/* At this point we have a priority and maybe an extension and a context */
if (mode)
ipri = ast_channel_priority(chan) + (ipri * mode);
if (async)
ast_async_goto(chan, context, exten, ipri);
else
ast_explicit_goto(chan, context, exten, ipri);
return 0;
}
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
{
return pbx_parseable_goto(chan, goto_string, 0);
}
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
{
return pbx_parseable_goto(chan, goto_string, 1);
}
char *ast_complete_applications(const char *line, const char *word, int state)
{
struct ast_app *app;
int which = 0;
int cmp;
char *ret = NULL;
size_t wordlen = strlen(word);
AST_RWLIST_RDLOCK(&apps);
AST_RWLIST_TRAVERSE(&apps, app, list) {
cmp = strncasecmp(word, app->name, wordlen);
if (cmp > 0) {
continue;
}
if (!cmp) {
/* Found match. */
if (++which <= state) {
/* Not enough matches. */
continue;
}
ret = ast_strdup(app->name);
break;
}
/* Not in container. */
break;
}
AST_RWLIST_UNLOCK(&apps);
return ret;
}
static int hint_hash(const void *obj, const int flags)
{
const struct ast_hint *hint = obj;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
const char *exten_name;
int res;
Merged revisions 329331 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/10 ................ r329331 | rmudgett | 2011-07-22 15:43:07 -0500 (Fri, 22 Jul 2011) | 55 lines Merged revisions 329299 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r329299 | rmudgett | 2011-07-22 10:44:58 -0500 (Fri, 22 Jul 2011) | 48 lines Deadlocks dealing with dialplan hints during reload. There are two remaining different deadlocks reported dealing with dialplan hints. The deadlock in ASTERISK-17666 is caused by invalid locking order in ast_remove_hint(). The hints container must be locked before the hint object. The deadlock in ASTERISK-17760 is caused by a catch-22 situation in handle_statechange(). The deadlock is caused by not having the conlock before calling the watcher callbacks. Unfortunately, having that lock causes a different deadlock as reported in ASTERISK-16961. * Fixed ast_remove_hint() locking order. * Made handle_statechange() no longer call the watcher callbacks holding any locks that matter. * Made hint ao2 destructor do the watcher callbacks for extension deactivation to guarantee that they get called. * Fixed hint reference leak in ast_add_hint() if the callback container constructor failed. * Fixed hint reference leak in complete_core_show_hint() for every hint it found for CLI tab completion. * Adjusted locking in ast_merge_contexts_and_delete() for safety. * Added context_merge_lock to prevent ast_merge_contexts_and_delete() and handle_statechange() from interfering with each other. * Fixed ast_change_hint() not taking into account that the extension is used for the hash key. (closes issue ASTERISK-17666) Reported by: irroot Tested by: irroot JIRA SWP-3318 (closes issue ASTERISK-17760) Reported by: Byron Clark Tested by: irroot JIRA SWP-3393 Review: https://reviewboard.asterisk.org/r/1313/ ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@329332 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-07-22 20:46:36 +00:00
exten_name = ast_get_extension_name(hint->exten);
if (ast_strlen_zero(exten_name)) {
/*
* If the exten or extension name isn't set, return 0 so that
* the ao2_find() search will start in the first bucket.
*/
res = 0;
} else {
res = ast_str_case_hash(exten_name);
}
return res;
}
static int hint_cmp(void *obj, void *arg, int flags)
{
const struct ast_hint *hint = obj;
const struct ast_exten *exten = arg;
return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
}
static int statecbs_cmp(void *obj, void *arg, int flags)
{
const struct ast_state_cb *state_cb = obj;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
ast_state_cb_type change_cb = arg;
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
}
/*!
* \internal
* \brief Clean up resources on Asterisk shutdown
*/
static void pbx_shutdown(void)
{
if (hints) {
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
ao2_container_unregister("hints");
ao2_ref(hints, -1);
hints = NULL;
}
if (hintdevices) {
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
ao2_container_unregister("hintdevices");
ao2_ref(hintdevices, -1);
hintdevices = NULL;
}
if (statecbs) {
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
ao2_container_unregister("statecbs");
ao2_ref(statecbs, -1);
statecbs = NULL;
}
if (contexts_table) {
ast_hashtab_destroy(contexts_table, NULL);
}
pbx_builtin_clear_globals();
}
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
{
struct ast_hint *hint = v_obj;
if (!hint) {
return;
}
prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
ast_get_context_name(ast_get_extension_context(hint->exten)));
}
static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
{
struct ast_hintdevice *hintdevice = v_obj;
if (!hintdevice) {
return;
}
prnt(where, "%s => %s@%s", hintdevice->hintdevice,
ast_get_extension_name(hintdevice->hint->exten),
ast_get_context_name(ast_get_extension_context(hintdevice->hint->exten)));
}
static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
{
struct ast_state_cb *state_cb = v_obj;
if (!state_cb) {
return;
}
prnt(where, "%d", state_cb->id);
}
int ast_pbx_init(void)
{
hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
if (hints) {
ao2_container_register("hints", hints, print_hints_key);
}
hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
if (hintdevices) {
ao2_container_register("hintdevices", hintdevices, print_hintdevices_key);
}
Fix extension state callback references in chan_sip. Chan_sip gives a dialog reference to the extension state callback and assumes that when ast_extension_state_del() returns, the callback cannot happen anymore. Chan_sip then reduces the dialog reference count associated with the callback. Recent changes (ASTERISK-17760) have resulted in the potential for the callback to happen after ast_extension_state_del() has returned. For chan_sip, this could be very bad because the dialog pointer could have already been destroyed. * Added ast_extension_state_add_destroy() so chan_sip can account for the sip_pvt reference given to the extension state callback when the extension state callback is deleted. * Fix pbx.c awkward statecbs handling in ast_extension_state_add_destroy() and handle_statechange() now that the struct ast_state_cb has a destructor to call. * Ensure that ast_extension_state_add_destroy() will never return -1 or 0 for a successful registration. * Fixed pbx.c statecbs_cmp() to compare the correct information. The passed in value to compare is a change_cb function pointer not an object pointer. * Make pbx.c ast_merge_contexts_and_delete() not perform callbacks with AST_EXTENSION_REMOVED with locks held. Chan_sip is notorious for deadlocking when those locks are held during the callback. * Removed unused lock declaration for the pbx.c store_hints list. (closes issue ASTERISK-18844) Reported by: rmudgett Review: https://reviewboard.asterisk.org/r/1635/ ........ Merged revisions 348940 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348952 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-12-23 02:35:13 +00:00
statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
main/pbx: Improve performance of dialplan reloads with a large number of hints The PBX core maintains two hash tables for hints: a container of the actual hints (hints), along with a container of devices that are watching that hint (hintdevices). When a dialplan reload occurs, each hint in the hints container is destroyed; this requires a lookup in the container of devices to find the device => hint mapping object. In the current code, this performs an ao2_callback, iterating over each of the device to hint objects in the hintdevices container. For a large number of hints, this is extremely expensive: dialplan reloads with 20000 hints could take several minutes in just this phase. This patch improves the performance of this step in the dialplan reloads by caching which devices are watching a hint on the hint object itself. Since we don't want to create a circular reference, we just cache the name of the device. This allows us to perform a smarter ao2_callback on the hintdevices container during hint removal, hashing on the name of the device and returning an iterator to the matching names. The overall performance improvement is rather large, taking this step down to a number of seconds as opposed to minutes. In addition, this patch also registers the hint containers in the PBX core with the astobj2 library. This allows for reasonable debugging to hash collisions in those containers. ASTERISK-25040 #close Reported by: Matt Jordan Change-Id: Iedfc97a69d21070c50fca42275d7b3e714e59360
2015-04-29 19:49:23 +00:00
if (statecbs) {
ao2_container_register("statecbs", statecbs, print_statecbs_key);
}
ast_register_cleanup(pbx_shutdown);
return (hints && hintdevices && statecbs) ? 0 : -1;
}