2002-09-12 18:32:42 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-09-12 18:32:42 +00:00
*
2006-01-03 22:16:23 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2002-09-12 18:32:42 +00:00
*
2004-08-31 00:08:52 +00:00
* Mark Spencer < markster @ digium . com >
2002-09-12 18:32:42 +00:00
*
2005-09-14 20:46:50 +00:00
* 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 .
*
2002-09-12 18:32:42 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief The Asterisk Management Interface - AMI
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ author Mark Spencer < markster @ digium . com >
*
2009-04-23 20:36:35 +00:00
* \ extref OpenSSL http : //www.openssl.org - for AMI/SSL
2007-02-24 19:49:11 +00:00
*
2006-10-18 17:45:50 +00:00
* At the moment this file contains a number of functions , namely :
*
* - data structures storing AMI state
* - AMI - related API functions , used by internal asterisk components
* - handlers for AMI - related CLI functions
* - handlers for AMI functions ( available through the AMI socket )
* - the code for the main AMI listener thread and individual session threads
* - the http handlers invoked for AMI - over - HTTP by the threads in main / http . c
*
2005-10-26 23:11:36 +00:00
* \ ref amiconf
2002-09-12 18:32:42 +00:00
*/
2006-10-18 21:41:09 +00:00
/*! \addtogroup Group_AMI AMI functions
2005-11-14 19:00:38 +00:00
*/
2006-10-18 21:41:09 +00:00
/*! @{
2005-11-14 19:00:38 +00:00
Doxygen group */
2011-07-14 20:28:54 +00:00
/*** MODULEINFO
< support_level > core < / support_level >
* * */
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2007-11-20 22:18:21 +00:00
# include "asterisk/_private.h"
2007-11-20 23:16:15 +00:00
# include "asterisk/paths.h" /* use various ast_config_AST_* */
2006-04-01 08:49:54 +00:00
# include <ctype.h>
2002-09-12 18:32:42 +00:00
# include <sys/time.h>
# include <signal.h>
2007-01-05 22:52:16 +00:00
# include <sys/mman.h>
2010-06-22 16:29:18 +00:00
# include <sys/types.h>
# include <regex.h>
2005-04-21 06:02:45 +00:00
# include "asterisk/channel.h"
# include "asterisk/file.h"
# include "asterisk/manager.h"
2008-01-07 15:52:55 +00:00
# include "asterisk/module.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/config.h"
# include "asterisk/callerid.h"
# include "asterisk/lock.h"
# include "asterisk/cli.h"
# include "asterisk/app.h"
# include "asterisk/pbx.h"
# include "asterisk/md5.h"
# include "asterisk/acl.h"
# include "asterisk/utils.h"
2008-01-18 22:04:33 +00:00
# include "asterisk/tcptls.h"
2006-04-01 08:49:54 +00:00
# include "asterisk/http.h"
2008-02-26 20:02:14 +00:00
# include "asterisk/ast_version.h"
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
# include "asterisk/threadstorage.h"
2006-08-21 19:42:29 +00:00
# include "asterisk/linkedlists.h"
2007-05-10 22:25:54 +00:00
# include "asterisk/term.h"
2007-11-23 17:56:56 +00:00
# include "asterisk/astobj2.h"
2008-03-05 22:33:05 +00:00
# include "asterisk/features.h"
2009-07-11 19:15:03 +00:00
# include "asterisk/security_events.h"
Generic Advice of Charge.
Asterisk Generic AOC Representation
- Generic AOC encode/decode routines.
(Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame)
- AST_CONTROL_AOC frame type to represent generic encoded AOC data
- Manager events for AOC-S, AOC-D, and AOC-E messages
Asterisk App Support
- app_dial AOC-S pass-through support on call setup
- app_queue AOC-S pass-through support on call setup
AOC Unit Tests
- AOC Unit Tests for encode/decode routines
- AOC Unit Test for manager event representation.
SIP AOC Support
- Pass-through of generic AOC-D and AOC-E messages to snom phones via the
snom AOC specification.
- Creation of chan_sip page3 flags for the addition of the new
'snom_aoc_enabled' sip.conf option.
IAX AOC Support
- Natively supports AOC pass-through through the use of the new
AST_CONTROL_AOC frame type
DAHDI AOC Support
- ETSI PRI full AOC Pass-through support
- 'aoc_enable' chan_dahdi.conf option for independently enabling
pass-through of AOC-S, AOC-D, AOC-E.
- 'aoce_delayhangup' option for retrieving AOC-E on disconnect.
- DAHDI A() dial string option for requesting AOC services.
example usage:
;requests AOC-S, AOC-D, and AOC-E on call setup
exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e))
Review: https://reviewboard.asterisk.org/r/552/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-06-02 18:10:15 +00:00
# include "asterisk/aoc.h"
2011-09-13 18:49:26 +00:00
# include "asterisk/stringfields.h"
2002-09-12 18:32:42 +00:00
2009-05-22 17:52:35 +00:00
/*** DOCUMENTATION
< manager name = " Ping " language = " en_US " >
< synopsis >
Keepalive command .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > A ' Ping ' action will ellicit a ' Pong ' response . Used to keep the
manager connection open . < / para >
< / description >
< / manager >
< manager name = " Events " language = " en_US " >
< synopsis >
Control Event Flow .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " EventMask " required = " true " >
< enumlist >
< enum name = " on " >
< para > If all events should be sent . < / para >
< / enum >
< enum name = " off " >
< para > If no events should be sent . < / para >
< / enum >
< enum name = " system,call,log,... " >
< para > To select which flags events should have to be sent . < / para >
< / enum >
< / enumlist >
< / parameter >
< / syntax >
< description >
< para > Enable / Disable sending of events to this manager client . < / para >
< / description >
< / manager >
< manager name = " Logoff " language = " en_US " >
< synopsis >
Logoff Manager .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > Logoff the current manager session . < / para >
< / description >
< / manager >
< manager name = " Login " language = " en_US " >
< synopsis >
Login Manager .
< / synopsis >
< syntax >
< parameter name = " ActionID " >
< para > ActionID for this transaction . Will be returned . < / para >
< / parameter >
2011-06-17 18:52:33 +00:00
< parameter name = " Username " required = " true " >
< para > Username to login with as specified in manager . conf . < / para >
< / parameter >
< parameter name = " Secret " >
< para > Secret to login with as specified in manager . conf . < / para >
< / parameter >
2009-05-22 17:52:35 +00:00
< / syntax >
< description >
< para > Login Manager . < / para >
< / description >
< / manager >
< manager name = " Challenge " language = " en_US " >
< synopsis >
Generate Challenge for MD5 Auth .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
2011-10-05 16:36:49 +00:00
< parameter name = " AuthType " required = " true " >
< para > Digest algorithm to use in the challenge . Valid values are : < / para >
< enumlist >
< enum name = " MD5 " / >
< / enumlist >
< / parameter >
2009-05-22 17:52:35 +00:00
< / syntax >
< description >
< para > Generate a challenge for MD5 authentication . < / para >
< / description >
< / manager >
< manager name = " Hangup " language = " en_US " >
< synopsis >
Hangup channel .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > The channel name to be hangup . < / para >
< / parameter >
< parameter name = " Cause " >
< para > Numeric hangup cause . < / para >
< / parameter >
< / syntax >
< description >
< para > Hangup a channel . < / para >
< / description >
< / manager >
< manager name = " Status " language = " en_US " >
< synopsis >
List channel status .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > The name of the channel to query for status . < / para >
< / parameter >
< parameter name = " Variables " >
< para > Comma < literal > , < / literal > separated list of variable to include . < / para >
< / parameter >
< / syntax >
< description >
< para > Will return the status information of each channel along with the
value for the specified channel variables . < / para >
< / description >
< / manager >
< manager name = " Setvar " language = " en_US " >
< synopsis >
Set a channel variable .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " >
< para > Channel to set variable for . < / para >
< / parameter >
< parameter name = " Variable " required = " true " >
< para > Variable name . < / para >
< / parameter >
< parameter name = " Value " required = " true " >
< para > Variable value . < / para >
< / parameter >
< / syntax >
< description >
< para > Set a global or local channel variable . < / para >
2011-12-07 21:42:29 +00:00
< note >
< para > If a channel name is not provided then the variable is global . < / para >
< / note >
2009-05-22 17:52:35 +00:00
< / description >
< / manager >
< manager name = " Getvar " language = " en_US " >
< synopsis >
Gets a channel variable .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " >
< para > Channel to read variable from . < / para >
< / parameter >
< parameter name = " Variable " required = " true " >
< para > Variable name . < / para >
< / parameter >
< / syntax >
< description >
< para > Get the value of a global or local channel variable . < / para >
2011-12-07 21:42:29 +00:00
< note >
< para > If a channel name is not provided then the variable is global . < / para >
< / note >
2009-05-22 17:52:35 +00:00
< / description >
< / manager >
< manager name = " GetConfig " language = " en_US " >
< synopsis >
Retrieve configuration .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Filename " required = " true " >
< para > Configuration filename ( e . g . < filename > foo . conf < / filename > ) . < / para >
< / parameter >
< parameter name = " Category " >
< para > Category in configuration file . < / para >
< / parameter >
< / syntax >
< description >
< para > This action will dump the contents of a configuration
file by category and contents or optionally by specified category only . < / para >
< / description >
< / manager >
< manager name = " GetConfigJSON " language = " en_US " >
< synopsis >
Retrieve configuration ( JSON format ) .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Filename " required = " true " >
< para > Configuration filename ( e . g . < filename > foo . conf < / filename > ) . < / para >
< / parameter >
< / syntax >
< description >
< para > This action will dump the contents of a configuration file by category
and contents in JSON format . This only makes sense to be used using rawman over
the HTTP interface . < / para >
< / description >
< / manager >
< manager name = " UpdateConfig " language = " en_US " >
< synopsis >
Update basic configuration .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " SrcFilename " required = " true " >
< para > Configuration filename to read ( e . g . < filename > foo . conf < / filename > ) . < / para >
< / parameter >
< parameter name = " DstFilename " required = " true " >
< para > Configuration filename to write ( e . g . < filename > foo . conf < / filename > ) < / para >
< / parameter >
< parameter name = " Reload " >
< para > Whether or not a reload should take place ( or name of specific module ) . < / para >
< / parameter >
< parameter name = " Action-XXXXXX " >
< para > Action to take . < / para >
< para > X ' s represent 6 digit number beginning with 000000. < / para >
< enumlist >
< enum name = " NewCat " / >
< enum name = " RenameCat " / >
< enum name = " DelCat " / >
< enum name = " EmptyCat " / >
< enum name = " Update " / >
< enum name = " Delete " / >
< enum name = " Append " / >
< enum name = " Insert " / >
< / enumlist >
< / parameter >
< parameter name = " Cat-XXXXXX " >
< para > Category to operate on . < / para >
< xi : include xpointer = " xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2]) " / >
< / parameter >
< parameter name = " Var-XXXXXX " >
< para > Variable to work on . < / para >
< xi : include xpointer = " xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2]) " / >
< / parameter >
< parameter name = " Value-XXXXXX " >
< para > Value to work on . < / para >
< xi : include xpointer = " xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2]) " / >
< / parameter >
< parameter name = " Match-XXXXXX " >
< para > Extra match required to match line . < / para >
< xi : include xpointer = " xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2]) " / >
< / parameter >
< parameter name = " Line-XXXXXX " >
< para > Line in category to operate on ( used with delete and insert actions ) . < / para >
< xi : include xpointer = " xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2]) " / >
< / parameter >
< / syntax >
< description >
< para > This action will modify , create , or delete configuration elements
in Asterisk configuration files . < / para >
< / description >
< / manager >
< manager name = " CreateConfig " language = " en_US " >
< synopsis >
Creates an empty file in the configuration directory .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Filename " required = " true " >
< para > The configuration filename to create ( e . g . < filename > foo . conf < / filename > ) . < / para >
< / parameter >
< / syntax >
< description >
< para > This action will create an empty file in the configuration
directory . This action is intended to be used before an UpdateConfig
action . < / para >
< / description >
< / manager >
< manager name = " ListCategories " language = " en_US " >
< synopsis >
List categories in configuration file .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Filename " required = " true " >
< para > Configuration filename ( e . g . < filename > foo . conf < / filename > ) . < / para >
< / parameter >
< / syntax >
< description >
< para > This action will dump the categories in a given file . < / para >
< / description >
< / manager >
< manager name = " Redirect " language = " en_US " >
< synopsis >
Redirect ( transfer ) a call .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Channel to redirect . < / para >
< / parameter >
< parameter name = " ExtraChannel " >
< para > Second call leg to transfer ( optional ) . < / para >
< / parameter >
< parameter name = " Exten " required = " true " >
< para > Extension to transfer to . < / para >
< / parameter >
2009-12-16 00:31:53 +00:00
< parameter name = " ExtraExten " >
< para > Extension to transfer extrachannel to ( optional ) . < / para >
< / parameter >
2009-05-22 17:52:35 +00:00
< parameter name = " Context " required = " true " >
< para > Context to transfer to . < / para >
< / parameter >
2009-12-16 00:31:53 +00:00
< parameter name = " ExtraContext " >
< para > Context to transfer extrachannel to ( optional ) . < / para >
< / parameter >
2009-05-22 17:52:35 +00:00
< parameter name = " Priority " required = " true " >
< para > Priority to transfer to . < / para >
< / parameter >
2009-12-16 00:31:53 +00:00
< parameter name = " ExtraPriority " >
< para > Priority to transfer extrachannel to ( optional ) . < / para >
< / parameter >
2009-05-22 17:52:35 +00:00
< / syntax >
< description >
< para > Redirect ( transfer ) a call . < / para >
< / description >
< / manager >
< manager name = " Atxfer " language = " en_US " >
< synopsis >
Attended transfer .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Transferer ' s channel . < / para >
< / parameter >
< parameter name = " Exten " required = " true " >
< para > Extension to transfer to . < / para >
< / parameter >
< parameter name = " Context " required = " true " >
< para > Context to transfer to . < / para >
< / parameter >
< parameter name = " Priority " required = " true " >
< para > Priority to transfer to . < / para >
< / parameter >
< / syntax >
< description >
< para > Attended transfer . < / para >
< / description >
< / manager >
< manager name = " Originate " language = " en_US " >
< synopsis >
Originate a call .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Channel name to call . < / para >
< / parameter >
< parameter name = " Exten " >
< para > Extension to use ( requires < literal > Context < / literal > and
< literal > Priority < / literal > ) < / para >
< / parameter >
< parameter name = " Context " >
< para > Context to use ( requires < literal > Exten < / literal > and
< literal > Priority < / literal > ) < / para >
< / parameter >
< parameter name = " Priority " >
< para > Priority to use ( requires < literal > Exten < / literal > and
< literal > Context < / literal > ) < / para >
< / parameter >
< parameter name = " Application " >
< para > Application to execute . < / para >
< / parameter >
< parameter name = " Data " >
< para > Data to use ( requires < literal > Application < / literal > ) . < / para >
< / parameter >
2009-07-21 14:29:40 +00:00
< parameter name = " Timeout " default = " 30000 " >
< para > How long to wait for call to be answered ( in ms . ) . < / para >
2009-05-22 17:52:35 +00:00
< / parameter >
< parameter name = " CallerID " >
< para > Caller ID to be set on the outgoing channel . < / para >
< / parameter >
< parameter name = " Variable " >
< para > Channel variable to set , multiple Variable : headers are allowed . < / para >
< / parameter >
< parameter name = " Account " >
< para > Account code . < / para >
< / parameter >
< parameter name = " Async " >
< para > Set to < literal > true < / literal > for fast origination . < / para >
< / parameter >
2010-10-02 08:58:34 +00:00
< parameter name = " Codecs " >
< para > Comma - separated list of codecs to use for this call . < / para >
< / parameter >
2009-05-22 17:52:35 +00:00
< / syntax >
< description >
< para > Generates an outgoing call to a
< replaceable > Extension < / replaceable > / < replaceable > Context < / replaceable > / < replaceable > Priority < / replaceable >
or < replaceable > Application < / replaceable > / < replaceable > Data < / replaceable > < / para >
< / description >
< / manager >
< manager name = " Command " language = " en_US " >
< synopsis >
Execute Asterisk CLI Command .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Command " required = " true " >
< para > Asterisk CLI command to run . < / para >
< / parameter >
< / syntax >
< description >
< para > Run a CLI command . < / para >
< / description >
< / manager >
< manager name = " ExtensionState " language = " en_US " >
< synopsis >
Check Extension Status .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Exten " required = " true " >
< para > Extension to check state on . < / para >
< / parameter >
< parameter name = " Context " required = " true " >
< para > Context for extension . < / para >
< / parameter >
< / syntax >
< description >
< para > Report the extension state for given extension . If the extension has a hint ,
will use devicestate to check the status of the device connected to the extension . < / para >
< para > Will return an < literal > Extension Status < / literal > message . The response will include
the hint for the extension and the status . < / para >
< / description >
< / manager >
< manager name = " AbsoluteTimeout " language = " en_US " >
< synopsis >
Set absolute timeout .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Channel name to hangup . < / para >
< / parameter >
< parameter name = " Timeout " required = " true " >
< para > Maximum duration of the call ( sec ) . < / para >
< / parameter >
< / syntax >
< description >
< para > Hangup a channel after a certain time . Acknowledges set time with
< literal > Timeout Set < / literal > message . < / para >
< / description >
< / manager >
< manager name = " MailboxStatus " language = " en_US " >
< synopsis >
Check mailbox .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Mailbox " required = " true " >
< para > Full mailbox ID < replaceable > mailbox < / replaceable > @ < replaceable > vm - context < / replaceable > . < / para >
< / parameter >
< / syntax >
< description >
< para > Checks a voicemail account for status . < / para >
< para > Returns number of messages . < / para >
< para > Message : Mailbox Status . < / para >
< para > Mailbox : < replaceable > mailboxid < / replaceable > . < / para >
< para > Waiting : < replaceable > count < / replaceable > . < / para >
< / description >
< / manager >
< manager name = " MailboxCount " language = " en_US " >
< synopsis >
Check Mailbox Message Count .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Mailbox " required = " true " >
< para > Full mailbox ID < replaceable > mailbox < / replaceable > @ < replaceable > vm - context < / replaceable > . < / para >
< / parameter >
< / syntax >
< description >
< para > Checks a voicemail account for new messages . < / para >
< para > Returns number of urgent , new and old messages . < / para >
< para > Message : Mailbox Message Count < / para >
< para > Mailbox : < replaceable > mailboxid < / replaceable > < / para >
< para > UrgentMessages : < replaceable > count < / replaceable > < / para >
< para > NewMessages : < replaceable > count < / replaceable > < / para >
< para > OldMessages : < replaceable > count < / replaceable > < / para >
< / description >
< / manager >
< manager name = " ListCommands " language = " en_US " >
< synopsis >
List available manager commands .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > Returns the action name and synopsis for every action that
is available to the user . < / para >
< / description >
< / manager >
< manager name = " SendText " language = " en_US " >
< synopsis >
Send text message to channel .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Channel to send message to . < / para >
< / parameter >
< parameter name = " Message " required = " true " >
< para > Message to send . < / para >
< / parameter >
< / syntax >
< description >
< para > Sends A Text Message to a channel while in a call . < / para >
< / description >
< / manager >
< manager name = " UserEvent " language = " en_US " >
< synopsis >
Send an arbitrary event .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " UserEvent " required = " true " >
< para > Event string to send . < / para >
< / parameter >
< parameter name = " Header1 " >
< para > Content1 . < / para >
< / parameter >
< parameter name = " HeaderN " >
< para > ContentN . < / para >
< / parameter >
< / syntax >
< description >
< para > Send an event to manager sessions . < / para >
< / description >
< / manager >
< manager name = " WaitEvent " language = " en_US " >
< synopsis >
Wait for an event to occur .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Timeout " required = " true " >
< para > Maximum time ( in seconds ) to wait for events , < literal > - 1 < / literal > means forever . < / para >
< / parameter >
< / syntax >
< description >
< para > This action will ellicit a < literal > Success < / literal > response . Whenever
a manager event is queued . Once WaitEvent has been called on an HTTP manager
session , events will be generated and queued . < / para >
< / description >
< / manager >
< manager name = " CoreSettings " language = " en_US " >
< synopsis >
Show PBX core settings ( version etc ) .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > Query for Core PBX settings . < / para >
< / description >
< / manager >
< manager name = " CoreStatus " language = " en_US " >
< synopsis >
Show PBX core status variables .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > Query for Core PBX status . < / para >
< / description >
< / manager >
< manager name = " Reload " language = " en_US " >
< synopsis >
Send a reload event .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Module " >
< para > Name of the module to reload . < / para >
< / parameter >
< / syntax >
< description >
< para > Send a reload event . < / para >
< / description >
< / manager >
< manager name = " CoreShowChannels " language = " en_US " >
< synopsis >
List currently active channels .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< / syntax >
< description >
< para > List currently defined channels and some information about them . < / para >
< / description >
< / manager >
< manager name = " ModuleLoad " language = " en_US " >
< synopsis >
Module management .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Module " >
< para > Asterisk module name ( including . so extension ) or subsystem identifier : < / para >
< enumlist >
< enum name = " cdr " / >
< enum name = " enum " / >
< enum name = " dnsmgr " / >
< enum name = " extconfig " / >
< enum name = " manager " / >
< enum name = " rtp " / >
< enum name = " http " / >
< / enumlist >
< / parameter >
< parameter name = " LoadType " required = " true " >
< para > The operation to be done on module . < / para >
< enumlist >
< enum name = " load " / >
< enum name = " unload " / >
< enum name = " reload " / >
< / enumlist >
< para > If no module is specified for a < literal > reload < / literal > loadtype ,
all modules are reloaded . < / para >
< / parameter >
< / syntax >
< description >
< para > Loads , unloads or reloads an Asterisk module in a running system . < / para >
< / description >
< / manager >
< manager name = " ModuleCheck " language = " en_US " >
< synopsis >
Check if module is loaded .
< / synopsis >
< syntax >
< parameter name = " Module " required = " true " >
< para > Asterisk module name ( not including extension ) . < / para >
< / parameter >
< / syntax >
< description >
< para > Checks if Asterisk module is loaded . Will return Success / Failure .
For success returns , the module revision number is included . < / para >
< / description >
< / manager >
Generic Advice of Charge.
Asterisk Generic AOC Representation
- Generic AOC encode/decode routines.
(Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame)
- AST_CONTROL_AOC frame type to represent generic encoded AOC data
- Manager events for AOC-S, AOC-D, and AOC-E messages
Asterisk App Support
- app_dial AOC-S pass-through support on call setup
- app_queue AOC-S pass-through support on call setup
AOC Unit Tests
- AOC Unit Tests for encode/decode routines
- AOC Unit Test for manager event representation.
SIP AOC Support
- Pass-through of generic AOC-D and AOC-E messages to snom phones via the
snom AOC specification.
- Creation of chan_sip page3 flags for the addition of the new
'snom_aoc_enabled' sip.conf option.
IAX AOC Support
- Natively supports AOC pass-through through the use of the new
AST_CONTROL_AOC frame type
DAHDI AOC Support
- ETSI PRI full AOC Pass-through support
- 'aoc_enable' chan_dahdi.conf option for independently enabling
pass-through of AOC-S, AOC-D, AOC-E.
- 'aoce_delayhangup' option for retrieving AOC-E on disconnect.
- DAHDI A() dial string option for requesting AOC services.
example usage:
;requests AOC-S, AOC-D, and AOC-E on call setup
exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e))
Review: https://reviewboard.asterisk.org/r/552/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-06-02 18:10:15 +00:00
< manager name = " AOCMessage " language = " en_US " >
< synopsis >
Generate an Advice of Charge message on a channel .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Channel " required = " true " >
< para > Channel name to generate the AOC message on . < / para >
< / parameter >
< parameter name = " ChannelPrefix " >
< para > Partial channel prefix . By using this option one can match the beginning part
of a channel name without having to put the entire name in . For example
if a channel name is SIP / snom - 00000001 and this value is set to SIP / snom , then
that channel matches and the message will be sent . Note however that only
the first matched channel has the message sent on it . < / para >
< / parameter >
< parameter name = " MsgType " required = " true " >
< para > Defines what type of AOC message to create , AOC - D or AOC - E < / para >
< enumlist >
< enum name = " D " / >
< enum name = " E " / >
< / enumlist >
< / parameter >
< parameter name = " ChargeType " required = " true " >
< para > Defines what kind of charge this message represents . < / para >
< enumlist >
< enum name = " NA " / >
< enum name = " FREE " / >
< enum name = " Currency " / >
< enum name = " Unit " / >
< / enumlist >
< / parameter >
< parameter name = " UnitAmount(0) " >
< para > This represents the amount of units charged . The ETSI AOC standard specifies that
this value along with the optional UnitType value are entries in a list . To accommodate this
these values take an index value starting at 0 which can be used to generate this list of
unit entries . For Example , If two unit entires were required this could be achieved by setting the
paramter UnitAmount ( 0 ) = 1234 and UnitAmount ( 1 ) = 5678. Note that UnitAmount at index 0 is
required when ChargeType = Unit , all other entries in the list are optional .
< / para >
< / parameter >
< parameter name = " UnitType(0) " >
< para > Defines the type of unit . ETSI AOC standard specifies this as an integer
value between 1 and 16 , but this value is left open to accept any positive
integer . Like the UnitAmount parameter , this value represents a list entry
and has an index parameter that starts at 0.
< / para >
< / parameter >
< parameter name = " CurrencyName " >
< para > Specifies the currency ' s name . Note that this value is truncated after 10 characters . < / para >
< / parameter >
< parameter name = " CurrencyAmount " >
< para > Specifies the charge unit amount as a positive integer . This value is required
when ChargeType = = Currency . < / para >
< / parameter >
< parameter name = " CurrencyMultiplier " >
< para > Specifies the currency multiplier . This value is required when ChargeType = = Currency . < / para >
< enumlist >
< enum name = " OneThousandth " / >
< enum name = " OneHundredth " / >
< enum name = " OneTenth " / >
< enum name = " One " / >
< enum name = " Ten " / >
< enum name = " Hundred " / >
< enum name = " Thousand " / >
< / enumlist >
< / parameter >
< parameter name = " TotalType " default = " Total " >
< para > Defines what kind of AOC - D total is represented . < / para >
< enumlist >
< enum name = " Total " / >
< enum name = " SubTotal " / >
< / enumlist >
< / parameter >
< parameter name = " AOCBillingId " >
< para > Represents a billing ID associated with an AOC - D or AOC - E message . Note
that only the first 3 items of the enum are valid AOC - D billing IDs < / para >
< enumlist >
< enum name = " Normal " / >
< enum name = " ReverseCharge " / >
< enum name = " CreditCard " / >
< enum name = " CallFwdUnconditional " / >
< enum name = " CallFwdBusy " / >
< enum name = " CallFwdNoReply " / >
< enum name = " CallDeflection " / >
< enum name = " CallTransfer " / >
< / enumlist >
< / parameter >
< parameter name = " ChargingAssociationId " >
< para > Charging association identifier . This is optional for AOC - E and can be
set to any value between - 32768 and 32767 < / para >
< / parameter >
< parameter name = " ChargingAssociationNumber " >
< para > Represents the charging association party number . This value is optional
for AOC - E . < / para >
< / parameter >
< parameter name = " ChargingAssociationPlan " >
< para > Integer representing the charging plan associated with the ChargingAssociationNumber .
The value is bits 7 through 1 of the Q .931 octet containing the type - of - number and
numbering - plan - identification fields . < / para >
< / parameter >
< / syntax >
< description >
< para > Generates an AOC - D or AOC - E message on a channel . < / para >
< / description >
< / manager >
2011-07-05 16:46:17 +00:00
< manager name = " Filter " language = " en_US " >
< synopsis >
Dynamically add filters for the current manager session .
< / synopsis >
< syntax >
< xi : include xpointer = " xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID']) " / >
< parameter name = " Operation " >
< enumlist >
< enum name = " Add " >
< para > Add a filter . < / para >
< / enum >
< / enumlist >
< / parameter >
< parameter name = " Filter " >
< para > Filters can be whitelist or blacklist < / para >
< para > Example whitelist filter : " Event: Newchannel " < / para >
< para > Example blacklist filter : " !Channel: DAHDI.* " < / para >
< para > This filter option is used to whitelist or blacklist events per user to be
reported with regular expressions and are allowed if both the regex matches
and the user has read access as defined in manager . conf . Filters are assumed to be for whitelisting
unless preceeded by an exclamation point , which marks it as being black .
Evaluation of the filters is as follows : < / para >
< para > - If no filters are configured all events are reported as normal . < / para >
< para > - If there are white filters only : implied black all filter processed first , then white filters . < / para >
< para > - If there are black filters only : implied white all filter processed first , then black filters . < / para >
< para > - If there are both white and black filters : implied black all filter processed first , then white
filters , and lastly black filters . < / para >
< / parameter >
< / syntax >
< description >
< para > The filters added are only used for the current session .
Once the connection is closed the filters are removed . < / para >
< para > This comand requires the system permission because
this command can be used to create filters that may bypass
filters defined in manager . conf < / para >
< / description >
< / manager >
< manager name = " FilterList " language = " en_US " >
< synopsis >
Show current event filters for this session
< / synopsis >
< description >
< para > The filters displayed are for the current session . Only those filters defined in
manager . conf will be present upon starting a new session . < / para >
< / description >
< / manager >
2009-05-22 17:52:35 +00:00
* * */
2008-02-12 00:24:36 +00:00
enum error_type {
UNKNOWN_ACTION = 1 ,
UNKNOWN_CATEGORY ,
UNSPECIFIED_CATEGORY ,
UNSPECIFIED_ARGUMENT ,
FAILURE_ALLOCATION ,
2008-11-11 23:02:43 +00:00
FAILURE_NEWCAT ,
2008-02-12 00:24:36 +00:00
FAILURE_DELCAT ,
FAILURE_EMPTYCAT ,
FAILURE_UPDATE ,
FAILURE_DELETE ,
FAILURE_APPEND
} ;
2011-07-05 16:46:17 +00:00
enum add_filter_result {
FILTER_SUCCESS ,
2011-10-11 18:57:47 +00:00
FILTER_ALLOC_FAILED ,
FILTER_COMPILE_FAIL ,
2011-07-05 16:46:17 +00:00
} ;
2008-02-12 00:24:36 +00:00
2006-10-24 17:14:12 +00:00
/*!
* Linked list of events .
* Global events are appended to the list by append_event ( ) .
* The usecount is the number of stored pointers to the element ,
* excluding the list pointers . So an element that is only in
* the list has a usecount of 0 , not 1.
*
* Clients have a pointer to the last event processed , and for each
* of these clients we track the usecount of the elements .
* If we have a pointer to an entry in the list , it is safe to navigate
* it forward because elements will not be deleted , but only appended .
* The worst that can happen is seeing the pointer still NULL .
*
* When the usecount of an element drops to 0 , and the element is the
* first in the list , we can remove it . Removal is done within the
* main thread , which is woken up for the purpose .
*
* For simplicity of implementation , we make sure the list is never empty .
*/
2006-04-02 19:59:55 +00:00
struct eventqent {
2006-10-20 08:00:13 +00:00
int usecount ; /*!< # of clients who still need the event */
2006-04-02 19:59:55 +00:00
int category ;
2006-10-24 17:14:12 +00:00
unsigned int seq ; /*!< sequence number */
2010-06-01 16:41:00 +00:00
struct timeval tv ; /*!< When event was allocated */
AST_RWLIST_ENTRY ( eventqent ) eq_next ;
2006-10-20 08:00:13 +00:00
char eventdata [ 1 ] ; /*!< really variable size, allocated by append_event() */
2006-04-02 19:59:55 +00:00
} ;
2006-10-24 17:14:12 +00:00
2010-06-01 16:41:00 +00:00
static AST_RWLIST_HEAD_STATIC ( all_events , eventqent ) ;
2006-04-02 19:59:55 +00:00
2005-01-05 06:24:59 +00:00
static int displayconnects = 1 ;
2007-06-05 17:47:37 +00:00
static int allowmultiplelogin = 1 ;
2006-12-27 22:14:33 +00:00
static int timestampevents ;
2006-04-01 08:49:54 +00:00
static int httptimeout = 60 ;
2010-04-13 18:10:30 +00:00
static int broken_events_action = 0 ;
2007-02-14 20:22:20 +00:00
static int manager_enabled = 0 ;
static int webmanager_enabled = 0 ;
2011-09-19 12:20:44 +00:00
static int manager_debug = 0 ; /*!< enable some debugging code in the manager */
2011-04-05 14:16:21 +00:00
static int authtimeout ;
static int authlimit ;
2010-05-05 00:44:37 +00:00
static char * manager_channelvars ;
2005-01-05 06:24:59 +00:00
2009-04-23 20:36:35 +00:00
# define DEFAULT_REALM "asterisk"
static char global_realm [ MAXHOSTNAMELEN ] ; /*!< Default realm */
2006-12-27 22:14:33 +00:00
static int block_sockets ;
2011-04-05 14:16:21 +00:00
static int unauth_sessions = 0 ;
2006-08-21 19:42:29 +00:00
2006-11-03 18:53:26 +00:00
2007-02-24 19:49:11 +00:00
/*! \brief
2006-11-28 09:27:37 +00:00
* Descriptor for a manager session , either on the AMI socket or over HTTP .
2007-02-24 19:49:11 +00:00
*
* \ note
2006-11-28 09:27:37 +00:00
* AMI session have managerid = = 0 ; the entry is created upon a connect ,
* and destroyed with the socket .
* HTTP sessions have managerid ! = 0 , the value is used as a search key
2009-04-23 20:36:35 +00:00
* to lookup sessions ( using the mansession_id cookie , or nonce key from
* Digest Authentication http header ) .
2006-10-18 17:53:47 +00:00
*/
2008-06-02 14:41:55 +00:00
# define MAX_BLACKLIST_CMD_LEN 2
2009-05-31 01:40:02 +00:00
static const struct {
const char * words [ AST_MAX_CMD_LEN ] ;
2008-06-02 14:41:55 +00:00
} command_blacklist [ ] = {
{ { " module " , " load " , NULL } } ,
{ { " module " , " unload " , NULL } } ,
2008-12-16 20:41:51 +00:00
{ { " restart " , " gracefully " , NULL } } ,
2007-05-24 15:30:06 +00:00
} ;
2009-02-10 21:45:14 +00:00
/* In order to understand what the heck is going on with the
* mansession_session and mansession structs , we need to have a bit of a history
* lesson .
*
* In the beginning , there was the mansession . The mansession contained data that was
* intrinsic to a manager session , such as the time that it started , the name of the logged - in
* user , etc . In addition to these parameters were the f and fd parameters . For typical manager
* sessions , these were used to represent the TCP socket over which the AMI session was taking
* place . It makes perfect sense for these fields to be a part of the session - specific data since
* the session actually defines this information .
*
* Then came the HTTP AMI sessions . With these , the f and fd fields need to be opened and closed
* for every single action that occurs . Thus the f and fd fields aren ' t really specific to the session
* but rather to the action that is being executed . Because a single session may execute many commands
* at once , some sort of safety needed to be added in order to be sure that we did not end up with fd
* leaks from one action overwriting the f and fd fields used by a previous action before the previous action
* has had a chance to properly close its handles .
*
* The initial idea to solve this was to use thread synchronization , but this prevented multiple actions
* from being run at the same time in a single session . Some manager actions may block for a long time , thus
* creating a large queue of actions to execute . In addition , this fix did not address the basic architectural
* issue that for HTTP manager sessions , the f and fd variables are not really a part of the session , but are
* part of the action instead .
*
* The new idea was to create a structure on the stack for each HTTP Manager action . This structure would
* contain the action - specific information , such as which file to write to . In order to maintain expectations
* of action handlers and not have to change the public API of the manager code , we would need to name this
* new stacked structure ' mansession ' and contain within it the old mansession struct that we used to use .
* We renamed the old mansession struct ' mansession_session ' to hopefully convey that what is in this structure
* is session - specific data . The structure that it is wrapped in , called a ' mansession ' really contains action - specific
* data .
*/
struct mansession_session {
2010-08-27 14:01:21 +00:00
/*! \todo XXX need to document which fields it is protecting */
2006-10-20 08:00:13 +00:00
struct sockaddr_in sin ; /*!< address we are connecting from */
2006-12-06 18:45:19 +00:00
FILE * f ; /*!< fdopen() on the underlying fd */
2006-10-20 08:00:13 +00:00
int fd ; /*!< descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
int inuse ; /*!< number of HTTP sessions using this entry */
int needdestroy ; /*!< Whether an HTTP session should be destroyed */
2006-11-28 12:05:25 +00:00
pthread_t waiting_thread ; /*!< Sleeping thread using this descriptor */
2008-04-23 18:01:00 +00:00
uint32_t managerid ; /*!< Unique manager identifier, 0 for AMI sessions */
2007-09-19 13:30:01 +00:00
time_t sessionstart ; /*!< Session start time */
2009-07-11 19:15:03 +00:00
struct timeval sessionstart_tv ; /*!< Session start time */
2006-10-20 08:00:13 +00:00
time_t sessiontimeout ; /*!< Session timeout if HTTP */
char username [ 80 ] ; /*!< Logged in username */
char challenge [ 10 ] ; /*!< Authentication challenge */
int authenticated ; /*!< Authentication status */
int readperm ; /*!< Authorization for reading */
int writeperm ; /*!< Authorization for writing */
2010-08-27 14:01:21 +00:00
char inbuf [ 1025 ] ; /*!< Buffer - we use the extra byte to add a '\0' and simplify parsing */
2006-10-20 08:00:13 +00:00
int inlen ; /*!< number of buffered bytes */
2010-08-27 14:01:21 +00:00
struct ao2_container * whitefilters ; /*!< Manager event filters - white list */
struct ao2_container * blackfilters ; /*!< Manager event filters - black list */
2006-10-20 08:00:13 +00:00
int send_events ; /*!< XXX what ? */
2006-10-20 11:24:43 +00:00
struct eventqent * last_ev ; /*!< last event processed. */
2006-10-20 08:00:13 +00:00
int writetimeout ; /*!< Timeout for ast_carefulwrite() */
2011-04-05 14:16:21 +00:00
time_t authstart ;
2008-04-02 17:36:49 +00:00
int pending_event ; /*!< Pending events indicator in case when waiting_thread is NULL */
2009-04-23 20:36:35 +00:00
time_t noncetime ; /*!< Timer for nonce value expiration */
unsigned long oldnonce ; /*!< Stale nonce value */
unsigned long nc ; /*!< incremental nonce counter */
2008-08-05 16:56:11 +00:00
AST_LIST_HEAD_NOLOCK ( mansession_datastores , ast_datastore ) datastores ; /*!< Data stores on the session */
2009-02-10 21:45:14 +00:00
AST_LIST_ENTRY ( mansession_session ) list ;
2006-08-21 19:42:29 +00:00
} ;
2010-08-27 14:01:21 +00:00
/*! \brief In case you didn't read that giant block of text above the mansession_session struct, the
* \ ref struct mansession is named this solely to keep the API the same in Asterisk . This structure really
2009-02-10 21:45:14 +00:00
* represents data that is different from Manager action to Manager action . The mansession_session pointer
* contained within points to session - specific data .
*/
struct mansession {
struct mansession_session * session ;
2009-07-11 19:15:03 +00:00
struct ast_tcptls_session_instance * tcptls_session ;
2009-02-10 21:45:14 +00:00
FILE * f ;
int fd ;
2011-03-16 19:51:04 +00:00
int write_error : 1 ;
2009-11-03 21:26:28 +00:00
struct manager_custom_hook * hook ;
2009-05-12 22:49:13 +00:00
ast_mutex_t lock ;
2009-02-10 21:45:14 +00:00
} ;
2006-10-20 11:24:43 +00:00
2009-04-23 20:36:35 +00:00
static struct ao2_container * sessions = NULL ;
2009-02-10 21:45:14 +00:00
2009-11-13 20:42:03 +00:00
struct manager_channel_variable {
AST_LIST_ENTRY ( manager_channel_variable ) entry ;
unsigned int isfunc : 1 ;
char name [ 0 ] ; /* allocate off the end the real size. */
} ;
static AST_RWLIST_HEAD_STATIC ( channelvars , manager_channel_variable ) ;
2006-10-20 08:00:13 +00:00
/*! \brief user descriptor, as read from the config file.
2007-02-24 19:49:11 +00:00
*
2006-10-20 08:00:13 +00:00
* \ note It is still missing some fields - - e . g . we can have multiple permit and deny
2006-10-18 17:53:47 +00:00
* lines which are not supported here , and readperm / writeperm / writetimeout
* are not stored .
*/
2006-09-19 22:01:23 +00:00
struct ast_manager_user {
char username [ 80 ] ;
2010-08-27 14:01:21 +00:00
char * secret ; /*!< Secret for logging in */
2007-12-16 13:32:48 +00:00
struct ast_ha * ha ; /*!< ACL setting */
2010-08-27 14:01:21 +00:00
int readperm ; /*!< Authorization for reading */
int writeperm ; /*!< Authorization for writing */
int writetimeout ; /*!< Per user Timeout for ast_carefulwrite() */
2009-04-23 20:36:35 +00:00
int displayconnects ; /*!< XXX unused */
int keep ; /*!< mark entries created on a reload */
2010-08-27 14:01:21 +00:00
struct ao2_container * whitefilters ; /*!< Manager event filters - white list */
struct ao2_container * blackfilters ; /*!< Manager event filters - black list */
2009-04-23 20:36:35 +00:00
char * a1_hash ; /*!< precalculated A1 for Digest auth */
2007-07-24 02:59:49 +00:00
AST_RWLIST_ENTRY ( ast_manager_user ) list ;
2006-09-19 22:01:23 +00:00
} ;
2006-10-20 08:00:13 +00:00
/*! \brief list of users found in the config file */
2007-07-24 02:59:49 +00:00
static AST_RWLIST_HEAD_STATIC ( users , ast_manager_user ) ;
2006-09-19 22:01:23 +00:00
2006-10-20 08:00:13 +00:00
/*! \brief list of actions registered */
2007-08-07 22:13:40 +00:00
static AST_RWLIST_HEAD_STATIC ( actions , manager_action ) ;
2002-09-12 18:32:42 +00:00
2007-08-07 22:13:40 +00:00
/*! \brief list of hooks registered */
2006-11-06 17:05:04 +00:00
static AST_RWLIST_HEAD_STATIC ( manager_hooks , manager_custom_hook ) ;
2009-11-13 20:42:03 +00:00
static void free_channelvars ( void ) ;
2009-04-23 20:36:35 +00:00
2011-07-05 16:46:17 +00:00
static enum add_filter_result manager_add_filter ( const char * filter_pattern , struct ao2_container * whitefilters , struct ao2_container * blackfilters ) ;
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Find a registered action object .
*
* \ param name Name of AMI action to find .
*
* \ return Reffed action found or NULL
*/
static struct manager_action * action_find ( const char * name )
{
struct manager_action * act ;
AST_RWLIST_RDLOCK ( & actions ) ;
AST_RWLIST_TRAVERSE ( & actions , act , list ) {
if ( ! strcasecmp ( name , act - > action ) ) {
ao2_t_ref ( act , + 1 , " found action object " ) ;
break ;
}
}
AST_RWLIST_UNLOCK ( & actions ) ;
return act ;
}
2006-11-06 17:05:04 +00:00
/*! \brief Add a custom hook to be called when an event is fired */
void ast_manager_register_hook ( struct manager_custom_hook * hook )
{
AST_RWLIST_WRLOCK ( & manager_hooks ) ;
AST_RWLIST_INSERT_TAIL ( & manager_hooks , hook , list ) ;
AST_RWLIST_UNLOCK ( & manager_hooks ) ;
}
/*! \brief Delete a custom hook to be called when an event is fired */
void ast_manager_unregister_hook ( struct manager_custom_hook * hook )
{
AST_RWLIST_WRLOCK ( & manager_hooks ) ;
AST_RWLIST_REMOVE ( & manager_hooks , hook , list ) ;
AST_RWLIST_UNLOCK ( & manager_hooks ) ;
}
2011-10-11 18:57:47 +00:00
int check_manager_enabled ( void )
2007-02-14 20:22:20 +00:00
{
return manager_enabled ;
}
2011-10-11 18:57:47 +00:00
int check_webmanager_enabled ( void )
2007-02-14 20:22:20 +00:00
{
return ( webmanager_enabled & & manager_enabled ) ;
}
2006-10-24 17:14:12 +00:00
/*!
* Grab a reference to the last event , update usecount as needed .
* Can handle a NULL pointer .
*/
static struct eventqent * grab_last ( void )
{
struct eventqent * ret ;
2010-06-01 16:41:00 +00:00
AST_RWLIST_WRLOCK ( & all_events ) ;
ret = AST_RWLIST_LAST ( & all_events ) ;
2006-10-24 17:14:12 +00:00
/* the list is never empty now, but may become so when
* we optimize it in the future , so be prepared .
*/
2009-04-23 20:36:35 +00:00
if ( ret ) {
2006-10-24 17:14:12 +00:00
ast_atomic_fetchadd_int ( & ret - > usecount , 1 ) ;
2009-04-23 20:36:35 +00:00
}
2010-06-01 16:41:00 +00:00
AST_RWLIST_UNLOCK ( & all_events ) ;
2006-10-24 17:14:12 +00:00
return ret ;
}
/*!
* Purge unused events . Remove elements from the head
* as long as their usecount is 0 and there is a next element .
*/
2006-11-28 11:20:39 +00:00
static void purge_events ( void )
2006-10-24 17:14:12 +00:00
{
struct eventqent * ev ;
2010-06-01 16:41:00 +00:00
struct timeval now = ast_tvnow ( ) ;
2006-10-24 17:14:12 +00:00
2010-06-01 16:41:00 +00:00
AST_RWLIST_WRLOCK ( & all_events ) ;
while ( ( ev = AST_RWLIST_FIRST ( & all_events ) ) & &
ev - > usecount = = 0 & & AST_RWLIST_NEXT ( ev , eq_next ) ) {
AST_RWLIST_REMOVE_HEAD ( & all_events , eq_next ) ;
2007-06-06 21:20:11 +00:00
ast_free ( ev ) ;
2006-10-24 17:14:12 +00:00
}
2010-06-01 16:41:00 +00:00
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & all_events , ev , eq_next ) {
2010-06-07 18:59:27 +00:00
/* Never release the last event */
if ( ! AST_RWLIST_NEXT ( ev , eq_next ) ) {
break ;
}
2010-06-01 16:41:00 +00:00
/* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
if ( ev - > usecount = = 0 & & ast_tvdiff_sec ( now , ev - > tv ) > ( httptimeout > 3600 ? 3600 : httptimeout ) * 2.5 ) {
AST_RWLIST_REMOVE_CURRENT ( eq_next ) ;
ast_free ( ev ) ;
}
}
AST_RWLIST_TRAVERSE_SAFE_END ;
AST_RWLIST_UNLOCK ( & all_events ) ;
2006-10-24 17:14:12 +00:00
}
/*!
2006-10-18 17:45:50 +00:00
* helper functions to convert back and forth between
* string and numeric representation of set of flags
*/
2009-05-31 01:40:02 +00:00
static const struct permalias {
2006-10-18 17:45:50 +00:00
int num ;
2009-05-31 01:40:02 +00:00
const char * label ;
2006-10-18 17:45:50 +00:00
} perms [ ] = {
{ EVENT_FLAG_SYSTEM , " system " } ,
{ EVENT_FLAG_CALL , " call " } ,
{ EVENT_FLAG_LOG , " log " } ,
{ EVENT_FLAG_VERBOSE , " verbose " } ,
{ EVENT_FLAG_COMMAND , " command " } ,
{ EVENT_FLAG_AGENT , " agent " } ,
{ EVENT_FLAG_USER , " user " } ,
{ EVENT_FLAG_CONFIG , " config " } ,
2007-04-10 23:55:26 +00:00
{ EVENT_FLAG_DTMF , " dtmf " } ,
2007-06-21 23:07:20 +00:00
{ EVENT_FLAG_REPORTING , " reporting " } ,
2007-12-05 16:46:47 +00:00
{ EVENT_FLAG_CDR , " cdr " } ,
2008-01-10 00:12:35 +00:00
{ EVENT_FLAG_DIALPLAN , " dialplan " } ,
2008-02-22 22:55:35 +00:00
{ EVENT_FLAG_ORIGINATE , " originate " } ,
2008-11-24 21:56:22 +00:00
{ EVENT_FLAG_AGI , " agi " } ,
Merge Call completion support into trunk.
From Reviewboard:
CCSS stands for Call Completion Supplementary Services. An admittedly out-of-date
overview of the architecture can be found in the file doc/CCSS_architecture.pdf
in the CCSS branch. Off the top of my head, the big differences between what is
implemented and what is in the document are as follows:
1. We did not end up modifying the Hangup application at all.
2. The document states that a single call completion monitor may be used across
multiple calls to the same device. This proved to not be such a good idea
when implementing protocol-specific monitors, and so we ended up using one
monitor per-device per-call.
3. There are some configuration options which were conceived after the document
was written. These are documented in the ccss.conf.sample that is on this
review request.
For some basic understanding of terminology used throughout this code, see the
ccss.tex document that is on this review.
This implements CCBS and CCNR in several flavors.
First up is a "generic" implementation, which can work over any channel technology
provided that the channel technology can accurately report device state. Call
completion is requested using the dialplan application CallCompletionRequest and can
be canceled using CallCompletionCancel. Device state subscriptions are used in order
to monitor the state of called parties.
Next, there is a SIP-specific implementation of call completion. This method uses the
methods outlined in draft-ietf-bliss-call-completion-06 to implement call completion
using SIP signaling. There are a few things to note here:
* The agent/monitor terminology used throughout Asterisk sometimes is the reverse of
what is defined in the referenced draft.
* Implementation of the draft required support for SIP PUBLISH. I attempted to write
this in a generic-enough fashion such that if someone were to want to write PUBLISH
support for other event packages, such as dialog-state or presence, most of the effort
would be in writing callbacks specific to the event package.
* A subportion of supporting PUBLISH reception was that we had to implement a PIDF
parser. The PIDF support added is a bit minimal. I first wrote a validation
routine to ensure that the PIDF document is formatted properly. The rest of the
PIDF reading is done in-line in the call-completion-specific PUBLISH-handling
code. In other words, while there is PIDF support here, it is not in any state
where it could easily be applied to other event packages as is.
Finally, there are a variety of ISDN-related call completion protocols supported. These
were written by Richard Mudgett, and as such I can't really say much about their
implementation. There are notes in the CHANGES file that indicate the ISDN protocols
over which call completion is supported.
Review: https://reviewboard.asterisk.org/r/523
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@256528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-04-09 15:31:32 +00:00
{ EVENT_FLAG_CC , " cc " } ,
2010-06-02 17:13:53 +00:00
{ EVENT_FLAG_AOC , " aoc " } ,
2011-08-22 19:19:44 +00:00
{ EVENT_FLAG_TEST , " test " } ,
2010-01-09 01:08:04 +00:00
{ INT_MAX , " all " } ,
2006-10-18 17:45:50 +00:00
{ 0 , " none " } ,
} ;
2006-10-17 18:08:51 +00:00
/*! \brief Convert authority code to a list of options */
2009-05-31 01:40:02 +00:00
static const char * authority_to_str ( int authority , struct ast_str * * res )
2004-07-30 20:27:42 +00:00
{
2006-10-17 21:09:49 +00:00
int i ;
2006-12-18 11:28:37 +00:00
char * sep = " " ;
2006-08-21 19:42:29 +00:00
2008-12-13 08:36:35 +00:00
ast_str_reset ( * res ) ;
2008-07-08 16:40:28 +00:00
for ( i = 0 ; i < ARRAY_LEN ( perms ) - 1 ; i + + ) {
2004-07-30 20:27:42 +00:00
if ( authority & perms [ i ] . num ) {
2006-12-18 11:28:37 +00:00
ast_str_append ( res , 0 , " %s%s " , sep , perms [ i ] . label ) ;
2006-10-17 18:08:51 +00:00
sep = " , " ;
2004-07-30 20:27:42 +00:00
}
}
2006-08-21 19:42:29 +00:00
2008-12-13 08:36:35 +00:00
if ( ast_str_strlen ( * res ) = = 0 ) /* replace empty string with something sensible */
2006-12-18 11:28:37 +00:00
ast_str_append ( res , 0 , " <none> " ) ;
2006-10-18 21:41:09 +00:00
2008-12-13 08:36:35 +00:00
return ast_str_buffer ( * res ) ;
2004-07-30 20:27:42 +00:00
}
2006-10-18 17:45:50 +00:00
/*! Tells you if smallstr exists inside bigstr
which is delim by delim and uses no buf or stringsep
ast_instring ( " this|that|more " , " this " , ' | ' ) = = 1 ;
feel free to move this to app . c - anthm */
2006-10-18 21:41:09 +00:00
static int ast_instring ( const char * bigstr , const char * smallstr , const char delim )
2004-06-02 20:08:08 +00:00
{
2006-10-18 17:45:50 +00:00
const char * val = bigstr , * next ;
2004-06-02 20:08:08 +00:00
2006-10-18 17:45:50 +00:00
do {
if ( ( next = strchr ( val , delim ) ) ) {
2009-04-23 20:36:35 +00:00
if ( ! strncmp ( val , smallstr , ( next - val ) ) ) {
2006-10-18 17:45:50 +00:00
return 1 ;
2009-04-23 20:36:35 +00:00
} else {
2006-10-18 17:45:50 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
} else {
2006-10-18 17:45:50 +00:00
return ! strcmp ( smallstr , val ) ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
} while ( * ( val = ( next + 1 ) ) ) ;
return 0 ;
2004-06-02 20:08:08 +00:00
}
2006-10-18 17:45:50 +00:00
static int get_perm ( const char * instr )
2006-04-01 08:49:54 +00:00
{
2006-10-18 17:45:50 +00:00
int x = 0 , ret = 0 ;
2006-10-17 17:19:31 +00:00
2009-04-23 20:36:35 +00:00
if ( ! instr ) {
2006-10-18 17:45:50 +00:00
return 0 ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
2008-07-08 16:40:28 +00:00
for ( x = 0 ; x < ARRAY_LEN ( perms ) ; x + + ) {
2009-04-23 20:36:35 +00:00
if ( ast_instring ( instr , perms [ x ] . label , ' , ' ) ) {
2006-10-18 17:45:50 +00:00
ret | = perms [ x ] . num ;
2009-04-23 20:36:35 +00:00
}
2006-04-01 08:49:54 +00:00
}
2006-10-18 21:41:09 +00:00
2006-10-18 17:45:50 +00:00
return ret ;
2006-04-01 08:49:54 +00:00
}
2006-04-03 18:38:28 +00:00
2006-10-20 08:00:13 +00:00
/*!
2006-10-18 17:45:50 +00:00
* A number returns itself , false returns 0 , true returns all flags ,
* other strings return the flags that are set .
2006-10-18 06:28:34 +00:00
*/
2007-01-05 22:43:18 +00:00
static int strings_to_mask ( const char * string )
2006-04-01 08:49:54 +00:00
{
2006-10-18 17:45:50 +00:00
const char * p ;
2006-10-18 05:31:54 +00:00
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( string ) ) {
2006-10-18 17:45:50 +00:00
return - 1 ;
2009-04-23 20:36:35 +00:00
}
Improve the XML formatting of responses coming from web interface.
Normal responses are sequences of lines of the form "Name: value",
with \r\n as line terminators and an empty line as a response
terminator.
Generi CLI commands, however, do not have such a clean formatting,
and the existing code failed to generate valid XML for them.
Obviously we can only use heuristics here, and we do the following:
- accept either \r or \n as a line terminator, trimming trailing whitespace;
- if a line does not have a ":" in it, assume that from this point on
we have unformatted data, and use "Opaque-data:" as a name;
- if a line does have a ":" in it, the Name field is not always
a legal identifier, so replace non-alphanum characters with underscores;
All the above is to be refined as we improve the formatting of
responses from the CLI.
And, all the above ought to go as a comment in the code rather than
just in a commit message...
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@45334 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-10-17 17:51:34 +00:00
2009-04-23 20:36:35 +00:00
for ( p = string ; * p ; p + + ) {
if ( * p < ' 0 ' | | * p > ' 9 ' ) {
2006-10-18 17:45:50 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
}
2010-01-09 01:08:04 +00:00
if ( ! * p ) { /* all digits */
2006-10-18 17:45:50 +00:00
return atoi ( string ) ;
2009-04-23 20:36:35 +00:00
}
if ( ast_false ( string ) ) {
2006-10-18 17:45:50 +00:00
return 0 ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
if ( ast_true ( string ) ) { /* all permissions */
int x , ret = 0 ;
2009-04-23 20:36:35 +00:00
for ( x = 0 ; x < ARRAY_LEN ( perms ) ; x + + ) {
2006-10-18 21:41:09 +00:00
ret | = perms [ x ] . num ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
return ret ;
2006-04-01 08:49:54 +00:00
}
2006-10-18 17:45:50 +00:00
return get_perm ( string ) ;
}
2006-10-18 21:41:09 +00:00
2009-04-23 20:36:35 +00:00
/*! \brief Unreference manager session object.
If no more references , then go ahead and delete it */
static struct mansession_session * unref_mansession ( struct mansession_session * s )
2007-05-17 17:12:23 +00:00
{
2009-04-23 20:36:35 +00:00
int refcount = ao2_ref ( s , - 1 ) ;
if ( manager_debug ) {
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " Mansession: %p refcount now %d \n " , s , refcount - 1 ) ;
2009-04-23 20:36:35 +00:00
}
return s ;
}
2007-05-17 17:12:23 +00:00
2010-06-22 16:29:18 +00:00
static void event_filter_destructor ( void * obj )
{
regex_t * regex_filter = obj ;
regfree ( regex_filter ) ;
}
2009-04-23 20:36:35 +00:00
static void session_destructor ( void * obj )
{
struct mansession_session * session = obj ;
struct eventqent * eqe = session - > last_ev ;
2009-05-12 22:49:13 +00:00
struct ast_datastore * datastore ;
/* Get rid of each of the data stores on the session */
while ( ( datastore = AST_LIST_REMOVE_HEAD ( & session - > datastores , entry ) ) ) {
/* Free the data store */
ast_datastore_free ( datastore ) ;
}
2009-04-23 20:36:35 +00:00
if ( session - > f ! = NULL ) {
fclose ( session - > f ) ;
2007-05-17 17:12:23 +00:00
}
2010-06-05 17:27:12 +00:00
if ( eqe ) {
ast_atomic_fetchadd_int ( & eqe - > usecount , - 1 ) ;
}
2010-06-22 16:29:18 +00:00
2010-06-22 17:57:28 +00:00
if ( session - > whitefilters ) {
ao2_t_callback ( session - > whitefilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all white filters " ) ;
ao2_t_ref ( session - > whitefilters , - 1 , " decrement ref for white container, should be last one " ) ;
}
if ( session - > blackfilters ) {
ao2_t_callback ( session - > blackfilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all black filters " ) ;
ao2_t_ref ( session - > blackfilters , - 1 , " decrement ref for black container, should be last one " ) ;
}
2009-04-23 20:36:35 +00:00
}
/*! \brief Allocate manager session structure and add it to the list of sessions */
static struct mansession_session * build_mansession ( struct sockaddr_in sin )
{
struct mansession_session * newsession ;
if ( ! ( newsession = ao2_alloc ( sizeof ( * newsession ) , session_destructor ) ) ) {
return NULL ;
}
2010-06-22 17:57:28 +00:00
if ( ! ( newsession - > whitefilters = ao2_container_alloc ( 1 , NULL , NULL ) ) ) {
ao2_ref ( newsession , - 1 ) ;
return NULL ;
}
if ( ! ( newsession - > blackfilters = ao2_container_alloc ( 1 , NULL , NULL ) ) ) {
ao2_ref ( newsession , - 1 ) ; /* session_destructor will cleanup the other filter */
return NULL ;
}
2009-04-23 20:36:35 +00:00
newsession - > fd = - 1 ;
newsession - > waiting_thread = AST_PTHREADT_NULL ;
newsession - > writetimeout = 100 ;
newsession - > send_events = - 1 ;
newsession - > sin = sin ;
ao2_link ( sessions , newsession ) ;
2009-05-12 22:49:13 +00:00
return newsession ;
2009-04-23 20:36:35 +00:00
}
static int mansession_cmp_fn ( void * obj , void * arg , int flags )
{
struct mansession_session * s = obj ;
char * str = arg ;
return ! strcasecmp ( s - > username , str ) ? CMP_MATCH : 0 ;
}
static void session_destroy ( struct mansession_session * s )
{
2009-05-12 22:49:13 +00:00
unref_mansession ( s ) ;
2009-04-23 20:36:35 +00:00
ao2_unlink ( sessions , s ) ;
}
2007-05-17 17:12:23 +00:00
2009-04-23 20:36:35 +00:00
static int check_manager_session_inuse ( const char * name )
{
2009-06-16 02:32:33 +00:00
struct mansession_session * session = ao2_find ( sessions , ( char * ) name , 0 ) ;
2009-05-12 22:49:13 +00:00
int inuse = 0 ;
2009-04-23 20:36:35 +00:00
if ( session ) {
2009-05-12 22:49:13 +00:00
inuse = 1 ;
2009-04-23 20:36:35 +00:00
unref_mansession ( session ) ;
}
2009-05-12 22:49:13 +00:00
return inuse ;
2007-05-17 17:12:23 +00:00
}
2006-10-20 08:00:13 +00:00
/*!
2006-10-19 07:43:43 +00:00
* lookup an entry in the list of registered users .
* must be called with the list lock held .
*/
static struct ast_manager_user * get_manager_by_name_locked ( const char * name )
2006-09-19 22:01:23 +00:00
{
struct ast_manager_user * user = NULL ;
2009-11-03 22:08:46 +00:00
AST_RWLIST_TRAVERSE ( & users , user , list ) {
2009-04-23 20:36:35 +00:00
if ( ! strcasecmp ( user - > username , name ) ) {
2006-09-19 22:01:23 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2009-11-03 22:08:46 +00:00
}
2006-09-19 22:01:23 +00:00
return user ;
}
2007-06-11 22:07:50 +00:00
/*! \brief Get displayconnects config option.
2009-04-01 20:13:28 +00:00
* \ param session manager session to get parameter from .
2007-06-11 22:07:50 +00:00
* \ return displayconnects config option value .
*/
2009-02-10 21:45:14 +00:00
static int manager_displayconnects ( struct mansession_session * session )
2007-06-11 22:07:50 +00:00
{
struct ast_manager_user * user = NULL ;
int ret = 0 ;
2007-07-24 02:59:49 +00:00
AST_RWLIST_RDLOCK ( & users ) ;
2009-04-23 20:36:35 +00:00
if ( ( user = get_manager_by_name_locked ( session - > username ) ) ) {
2007-06-11 22:07:50 +00:00
ret = user - > displayconnects ;
2009-04-23 20:36:35 +00:00
}
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2009-04-23 20:36:35 +00:00
2007-06-11 22:07:50 +00:00
return ret ;
}
2007-09-18 22:43:45 +00:00
static char * handle_showmancmd ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2004-06-02 20:08:08 +00:00
{
2006-10-16 09:33:00 +00:00
struct manager_action * cur ;
2007-09-18 22:43:45 +00:00
struct ast_str * authority ;
int num , l , which ;
char * ret = NULL ;
2009-05-22 17:52:35 +00:00
# ifdef AST_XML_DOCS
char syntax_title [ 64 ] , description_title [ 64 ] , synopsis_title [ 64 ] , seealso_title [ 64 ] , arguments_title [ 64 ] ;
# endif
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show command " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2009-05-18 20:49:20 +00:00
" Usage: manager show command <actionname> [<actionname> [<actionname> [...]]] \n "
2007-09-18 22:43:45 +00:00
" Shows the detailed description for a specific Asterisk manager interface command. \n " ;
return NULL ;
case CLI_GENERATE :
2009-05-18 20:44:54 +00:00
l = strlen ( a - > word ) ;
which = 0 ;
AST_RWLIST_RDLOCK ( & actions ) ;
AST_RWLIST_TRAVERSE ( & actions , cur , list ) {
if ( ! strncasecmp ( a - > word , cur - > action , l ) & & + + which > a - > n ) {
ret = ast_strdup ( cur - > action ) ;
break ; /* make sure we exit even if ast_strdup() returns NULL */
2007-09-18 22:43:45 +00:00
}
}
2009-05-18 20:44:54 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
return ret ;
2007-09-18 22:43:45 +00:00
}
authority = ast_str_alloca ( 80 ) ;
2009-05-18 20:49:20 +00:00
if ( a - > argc < 4 ) {
2007-09-18 22:43:45 +00:00
return CLI_SHOWUSAGE ;
2009-04-23 20:36:35 +00:00
}
2006-08-21 19:42:29 +00:00
2009-05-22 17:52:35 +00:00
# ifdef AST_XML_DOCS
/* setup the titles */
term_color ( synopsis_title , " [Synopsis] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( description_title , " [Description] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( syntax_title , " [Syntax] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( seealso_title , " [See Also] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( arguments_title , " [Arguments] \n " , COLOR_MAGENTA , 0 , 40 ) ;
# endif
2007-08-07 22:13:40 +00:00
AST_RWLIST_RDLOCK ( & actions ) ;
AST_RWLIST_TRAVERSE ( & actions , cur , list ) {
2007-09-18 22:43:45 +00:00
for ( num = 3 ; num < a - > argc ; num + + ) {
if ( ! strcasecmp ( cur - > action , a - > argv [ num ] ) ) {
2009-05-22 17:52:35 +00:00
# ifdef AST_XML_DOCS
if ( cur - > docsrc = = AST_XML_DOC ) {
ast_cli ( a - > fd , " %s%s \n \n %s%s \n \n %s%s \n \n %s%s \n \n %s%s \n \n " ,
syntax_title ,
ast_xmldoc_printable ( S_OR ( cur - > syntax , " Not available " ) , 1 ) ,
synopsis_title ,
ast_xmldoc_printable ( S_OR ( cur - > synopsis , " Not available " ) , 1 ) ,
description_title ,
ast_xmldoc_printable ( S_OR ( cur - > description , " Not available " ) , 1 ) ,
arguments_title ,
ast_xmldoc_printable ( S_OR ( cur - > arguments , " Not available " ) , 1 ) ,
seealso_title ,
ast_xmldoc_printable ( S_OR ( cur - > seealso , " Not available " ) , 1 ) ) ;
2011-10-11 18:57:47 +00:00
} else
2009-05-22 17:52:35 +00:00
# endif
2011-10-11 18:57:47 +00:00
{
2009-05-22 17:52:35 +00:00
ast_cli ( a - > fd , " Action: %s \n Synopsis: %s \n Privilege: %s \n %s \n " ,
2011-10-11 18:57:47 +00:00
cur - > action , cur - > synopsis ,
authority_to_str ( cur - > authority , & authority ) ,
S_OR ( cur - > description , " " ) ) ;
2009-05-22 17:52:35 +00:00
}
2004-06-02 20:08:08 +00:00
}
}
}
2007-08-07 22:13:40 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2006-08-21 19:42:29 +00:00
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2004-06-02 20:08:08 +00:00
}
2007-09-18 22:43:45 +00:00
static char * handle_mandebug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-11-03 18:53:26 +00:00
{
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-09-28 23:32:14 +00:00
e - > command = " manager set debug [on|off] " ;
e - > usage = " Usage: manager set debug [on|off] \n Show, enable, disable debugging of the manager code. \n " ;
2007-09-18 22:43:45 +00:00
return NULL ;
case CLI_GENERATE :
2009-04-23 20:36:35 +00:00
return NULL ;
2007-09-18 22:43:45 +00:00
}
2009-04-23 20:36:35 +00:00
if ( a - > argc = = 3 ) {
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " manager debug is %s \n " , manager_debug ? " on " : " off " ) ;
2009-04-23 20:36:35 +00:00
} else if ( a - > argc = = 4 ) {
if ( ! strcasecmp ( a - > argv [ 3 ] , " on " ) ) {
2006-11-03 18:53:26 +00:00
manager_debug = 1 ;
2009-04-23 20:36:35 +00:00
} else if ( ! strcasecmp ( a - > argv [ 3 ] , " off " ) ) {
2006-11-03 18:53:26 +00:00
manager_debug = 0 ;
2009-04-23 20:36:35 +00:00
} else {
2007-09-18 22:43:45 +00:00
return CLI_SHOWUSAGE ;
2009-04-23 20:36:35 +00:00
}
2006-11-03 18:53:26 +00:00
}
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-11-03 18:53:26 +00:00
}
2007-09-18 22:43:45 +00:00
static char * handle_showmanager ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-19 22:01:23 +00:00
{
struct ast_manager_user * user = NULL ;
2007-09-18 22:43:45 +00:00
int l , which ;
char * ret = NULL ;
2008-12-08 18:49:50 +00:00
struct ast_str * rauthority = ast_str_alloca ( 128 ) ;
struct ast_str * wauthority = ast_str_alloca ( 128 ) ;
2007-12-16 13:32:48 +00:00
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show user " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2007-09-18 22:43:45 +00:00
" Usage: manager show user <user> \n "
" Display all information related to the manager user specified. \n " ;
return NULL ;
case CLI_GENERATE :
l = strlen ( a - > word ) ;
which = 0 ;
2009-04-23 20:36:35 +00:00
if ( a - > pos ! = 3 ) {
2007-09-18 22:43:45 +00:00
return NULL ;
2009-04-23 20:36:35 +00:00
}
2007-09-18 22:43:45 +00:00
AST_RWLIST_RDLOCK ( & users ) ;
AST_RWLIST_TRAVERSE ( & users , user , list ) {
if ( ! strncasecmp ( a - > word , user - > username , l ) & & + + which > a - > n ) {
ret = ast_strdup ( user - > username ) ;
break ;
}
}
AST_RWLIST_UNLOCK ( & users ) ;
return ret ;
}
2006-09-19 22:01:23 +00:00
2009-04-23 20:36:35 +00:00
if ( a - > argc ! = 4 ) {
2007-09-18 22:43:45 +00:00
return CLI_SHOWUSAGE ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
2007-07-24 02:59:49 +00:00
AST_RWLIST_RDLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
2007-09-18 22:43:45 +00:00
if ( ! ( user = get_manager_by_name_locked ( a - > argv [ 3 ] ) ) ) {
ast_cli ( a - > fd , " There is no manager called %s \n " , a - > argv [ 3 ] ) ;
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-09-19 22:01:23 +00:00
}
2008-02-03 17:40:48 +00:00
ast_cli ( a - > fd , " \n " ) ;
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd ,
2006-09-19 22:01:23 +00:00
" username: %s \n "
" secret: %s \n "
2007-12-16 13:32:48 +00:00
" acl: %s \n "
" read perm: %s \n "
" write perm: %s \n "
2006-09-19 22:01:23 +00:00
" displayconnects: %s \n " ,
( user - > username ? user - > username : " (N/A) " ) ,
2007-05-11 20:16:56 +00:00
( user - > secret ? " <Set> " : " (N/A) " ) ,
2007-12-16 13:32:48 +00:00
( user - > ha ? " yes " : " no " ) ,
authority_to_str ( user - > readperm , & rauthority ) ,
authority_to_str ( user - > writeperm , & wauthority ) ,
2006-09-19 22:01:23 +00:00
( user - > displayconnects ? " yes " : " no " ) ) ;
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-09-19 22:01:23 +00:00
}
2007-09-18 22:43:45 +00:00
static char * handle_showmanagers ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-19 22:01:23 +00:00
{
struct ast_manager_user * user = NULL ;
int count_amu = 0 ;
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show users " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2007-09-18 22:43:45 +00:00
" Usage: manager show users \n "
" Prints a listing of all managers that are currently configured on that \n "
" system. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2009-04-23 20:36:35 +00:00
if ( a - > argc ! = 3 ) {
2007-09-18 22:43:45 +00:00
return CLI_SHOWUSAGE ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
2007-07-24 02:59:49 +00:00
AST_RWLIST_RDLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
/* If there are no users, print out something along those lines */
2007-07-24 02:59:49 +00:00
if ( AST_RWLIST_EMPTY ( & users ) ) {
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " There are no manager users. \n " ) ;
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-09-19 22:01:23 +00:00
}
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " \n username \n -------- \n " ) ;
2006-09-19 22:01:23 +00:00
2007-07-24 02:59:49 +00:00
AST_RWLIST_TRAVERSE ( & users , user , list ) {
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " %s \n " , user - > username ) ;
2006-09-19 22:01:23 +00:00
count_amu + + ;
}
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
2009-04-23 20:36:35 +00:00
ast_cli ( a - > fd , " ------------------- \n "
" %d manager users configured. \n " , count_amu ) ;
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-09-19 22:01:23 +00:00
}
2006-10-17 18:08:51 +00:00
/*! \brief CLI command manager list commands */
2007-09-18 22:43:45 +00:00
static char * handle_showmancmds ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-01-28 22:33:41 +00:00
{
2006-10-16 09:33:00 +00:00
struct manager_action * cur ;
2007-09-18 22:43:45 +00:00
struct ast_str * authority ;
2008-03-18 15:43:34 +00:00
# define HSMC_FORMAT " %-15.15s %-15.15s %-55.55s\n"
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show commands " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2007-09-18 22:43:45 +00:00
" Usage: manager show commands \n "
" Prints a listing of all the available Asterisk manager interface commands. \n " ;
return NULL ;
case CLI_GENERATE :
2009-04-23 20:36:35 +00:00
return NULL ;
}
2007-09-18 22:43:45 +00:00
authority = ast_str_alloca ( 80 ) ;
2008-03-18 15:43:34 +00:00
ast_cli ( a - > fd , HSMC_FORMAT , " Action " , " Privilege " , " Synopsis " ) ;
ast_cli ( a - > fd , HSMC_FORMAT , " ------ " , " --------- " , " -------- " ) ;
2006-10-18 21:41:09 +00:00
2007-08-07 22:13:40 +00:00
AST_RWLIST_RDLOCK ( & actions ) ;
2011-10-11 18:57:47 +00:00
AST_RWLIST_TRAVERSE ( & actions , cur , list ) {
2008-03-18 15:43:34 +00:00
ast_cli ( a - > fd , HSMC_FORMAT , cur - > action , authority_to_str ( cur - > authority , & authority ) , cur - > synopsis ) ;
2011-10-11 18:57:47 +00:00
}
2007-08-07 22:13:40 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2006-10-18 21:41:09 +00:00
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2003-01-28 22:33:41 +00:00
}
2006-10-17 18:08:51 +00:00
/*! \brief CLI command manager list connected */
2007-09-18 22:43:45 +00:00
static char * handle_showmanconn ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-02-21 06:00:08 +00:00
{
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2007-09-19 13:30:01 +00:00
time_t now = time ( NULL ) ;
2008-03-18 15:43:34 +00:00
# define HSMCONN_FORMAT1 " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
# define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
2007-09-11 13:15:37 +00:00
int count = 0 ;
2009-04-23 20:36:35 +00:00
struct ao2_iterator i ;
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show connected " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2007-09-18 22:43:45 +00:00
" Usage: manager show connected \n "
" Prints a listing of the users that are currently connected to the \n "
" Asterisk manager interface. \n " ;
return NULL ;
case CLI_GENERATE :
2009-04-23 20:36:35 +00:00
return NULL ;
2007-09-18 22:43:45 +00:00
}
2007-09-19 13:30:01 +00:00
2008-03-18 15:43:34 +00:00
ast_cli ( a - > fd , HSMCONN_FORMAT1 , " Username " , " IP Address " , " Start " , " Elapsed " , " FileDes " , " HttpCnt " , " Read " , " Write " ) ;
2006-10-18 21:41:09 +00:00
2009-04-23 20:36:35 +00:00
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
2009-02-10 21:45:14 +00:00
ast_cli ( a - > fd , HSMCONN_FORMAT2 , session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) , ( int ) ( session - > sessionstart ) , ( int ) ( now - session - > sessionstart ) , session - > fd , session - > inuse , session - > readperm , session - > writeperm ) ;
2007-09-11 13:15:37 +00:00
count + + ;
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2007-09-11 13:15:37 +00:00
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " %d users connected. \n " , count ) ;
2007-09-11 13:15:37 +00:00
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2003-02-21 06:00:08 +00:00
}
2006-10-16 11:29:22 +00:00
/*! \brief CLI command manager list eventq */
2006-04-02 19:59:55 +00:00
/* Should change to "manager show connected" */
2007-09-18 22:43:45 +00:00
static char * handle_showmaneventq ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-04-02 19:59:55 +00:00
{
struct eventqent * s ;
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show eventq " ;
2009-04-23 20:36:35 +00:00
e - > usage =
2007-09-18 22:43:45 +00:00
" Usage: manager show eventq \n "
" Prints a listing of all events pending in the Asterisk manger \n "
" event queue. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2010-06-01 16:41:00 +00:00
AST_RWLIST_RDLOCK ( & all_events ) ;
AST_RWLIST_TRAVERSE ( & all_events , s , eq_next ) {
2008-02-03 17:40:48 +00:00
ast_cli ( a - > fd , " Usecount: %d \n " , s - > usecount ) ;
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " Category: %d \n " , s - > category ) ;
ast_cli ( a - > fd , " Event: \n %s " , s - > eventdata ) ;
2006-04-02 19:59:55 +00:00
}
2010-06-01 16:41:00 +00:00
AST_RWLIST_UNLOCK ( & all_events ) ;
2006-08-21 19:42:29 +00:00
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2006-04-02 19:59:55 +00:00
}
2007-12-16 13:35:09 +00:00
/*! \brief CLI command manager reload */
static char * handle_manager_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager reload " ;
e - > usage =
" Usage: manager reload \n "
" Reloads the manager configuration. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2009-04-23 20:36:35 +00:00
if ( a - > argc > 2 ) {
2007-12-16 13:35:09 +00:00
return CLI_SHOWUSAGE ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:35:09 +00:00
reload_manager ( ) ;
return CLI_SUCCESS ;
}
2010-06-01 16:41:00 +00:00
static struct eventqent * advance_event ( struct eventqent * e )
2006-04-02 19:59:55 +00:00
{
2010-06-01 16:41:00 +00:00
struct eventqent * next ;
2006-04-02 19:59:55 +00:00
2010-06-01 16:41:00 +00:00
AST_RWLIST_RDLOCK ( & all_events ) ;
if ( ( next = AST_RWLIST_NEXT ( e , eq_next ) ) ) {
ast_atomic_fetchadd_int ( & next - > usecount , 1 ) ;
ast_atomic_fetchadd_int ( & e - > usecount , - 1 ) ;
}
AST_RWLIST_UNLOCK ( & all_events ) ;
return next ;
2006-10-24 17:14:12 +00:00
}
2010-08-27 14:01:21 +00:00
# define GET_HEADER_FIRST_MATCH 0
# define GET_HEADER_LAST_MATCH 1
# define GET_HEADER_SKIP_EMPTY 2
2011-10-11 18:57:47 +00:00
/*!
* \ brief Return a matching header value .
*
* \ details
* Generic function to return either the first or the last
* matching header from a list of variables , possibly skipping
* empty strings .
*
* \ note At the moment there is only one use of this function in
* this file , so we make it static .
*
* \ note Never returns NULL .
2008-05-20 18:07:24 +00:00
*/
static const char * __astman_get_header ( const struct message * m , char * var , int mode )
2002-09-12 18:32:42 +00:00
{
2006-10-16 11:29:22 +00:00
int x , l = strlen ( var ) ;
2008-05-20 18:07:24 +00:00
const char * result = " " ;
2006-08-21 19:42:29 +00:00
for ( x = 0 ; x < m - > hdrcount ; x + + ) {
2007-01-05 22:43:18 +00:00
const char * h = m - > headers [ x ] ;
2010-08-28 21:30:25 +00:00
if ( ! strncasecmp ( var , h , l ) & & h [ l ] = = ' : ' ) {
const char * value = h + l + 1 ;
value = ast_skip_blanks ( value ) ; /* ignore leading spaces in the value */
2008-05-20 18:07:24 +00:00
/* found a potential candidate */
2011-10-11 18:57:47 +00:00
if ( ( mode & GET_HEADER_SKIP_EMPTY ) & & ast_strlen_zero ( value ) ) {
2008-05-20 18:07:24 +00:00
continue ; /* not interesting */
2011-10-11 18:57:47 +00:00
}
if ( mode & GET_HEADER_LAST_MATCH ) {
2008-08-10 19:35:50 +00:00
result = value ; /* record the last match so far */
2011-10-11 18:57:47 +00:00
} else {
2008-08-10 19:35:50 +00:00
return value ;
2011-10-11 18:57:47 +00:00
}
2008-05-20 18:07:24 +00:00
}
2006-08-21 19:42:29 +00:00
}
2011-05-03 20:45:32 +00:00
return result ;
2002-09-12 18:32:42 +00:00
}
2011-10-11 18:57:47 +00:00
/*!
* \ brief Return the first matching variable from an array .
*
* \ note This is the legacy function and is implemented in
* therms of __astman_get_header ( ) .
*
* \ note Never returns NULL .
2008-05-20 18:07:24 +00:00
*/
const char * astman_get_header ( const struct message * m , char * var )
{
return __astman_get_header ( m , var , GET_HEADER_FIRST_MATCH ) ;
}
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Process one " Variable: " header value string .
*
* \ param head Current list of AMI variables to get new values added .
* \ param hdr_val Header value string to process .
*
* \ return New variable list head .
*/
static struct ast_variable * man_do_variable_value ( struct ast_variable * head , const char * hdr_val )
2005-07-15 23:24:51 +00:00
{
2011-10-11 18:57:47 +00:00
char * parse ;
2006-01-23 18:07:12 +00:00
AST_DECLARE_APP_ARGS ( args ,
2011-10-11 18:57:47 +00:00
AST_APP_ARG ( vars ) [ 64 ] ;
2006-01-23 18:07:12 +00:00
) ;
2011-10-11 18:57:47 +00:00
hdr_val = ast_skip_blanks ( hdr_val ) ; /* ignore leading spaces in the value */
parse = ast_strdupa ( hdr_val ) ;
2006-10-18 11:43:31 +00:00
2011-10-11 18:57:47 +00:00
/* Break the header value string into name=val pair items. */
AST_STANDARD_APP_ARGS ( args , parse ) ;
if ( args . argc ) {
int y ;
2005-11-08 02:11:42 +00:00
2011-10-11 18:57:47 +00:00
/* Process each name=val pair item. */
2006-10-18 11:43:31 +00:00
for ( y = 0 ; y < args . argc ; y + + ) {
2011-10-11 18:57:47 +00:00
struct ast_variable * cur ;
char * var ;
char * val ;
2009-04-23 20:36:35 +00:00
if ( ! args . vars [ y ] ) {
2006-10-18 11:43:31 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
2011-10-11 18:57:47 +00:00
var = val = args . vars [ y ] ;
2006-10-18 11:43:31 +00:00
strsep ( & val , " = " ) ;
2011-10-11 18:57:47 +00:00
/* XXX We may wish to trim whitespace from the strings. */
2009-04-23 20:36:35 +00:00
if ( ! val | | ast_strlen_zero ( var ) ) {
2006-10-18 11:43:31 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
2011-10-11 18:57:47 +00:00
/* Create new variable list node and prepend it to the list. */
2007-08-29 20:55:40 +00:00
cur = ast_variable_new ( var , val , " " ) ;
2011-10-11 18:57:47 +00:00
if ( cur ) {
cur - > next = head ;
head = cur ;
}
}
}
return head ;
}
struct ast_variable * astman_get_variables ( const struct message * m )
{
int varlen ;
int x ;
struct ast_variable * head = NULL ;
static const char var_hdr [ ] = " Variable: " ;
/* Process all "Variable:" headers. */
varlen = strlen ( var_hdr ) ;
for ( x = 0 ; x < m - > hdrcount ; x + + ) {
if ( strncasecmp ( var_hdr , m - > headers [ x ] , varlen ) ) {
continue ;
2005-07-15 23:24:51 +00:00
}
2011-10-11 18:57:47 +00:00
head = man_do_variable_value ( head , m - > headers [ x ] + varlen ) ;
2005-07-15 23:24:51 +00:00
}
return head ;
}
2010-08-27 14:01:21 +00:00
/*! \brief access for hooks to send action messages to ami */
2009-11-03 21:26:28 +00:00
int ast_hook_send_action ( struct manager_custom_hook * hook , const char * msg )
{
const char * action ;
int ret = 0 ;
2011-10-11 18:57:47 +00:00
struct manager_action * act_found ;
2009-11-03 21:26:28 +00:00
struct mansession s = { . session = NULL , } ;
struct message m = { 0 } ;
2011-10-11 18:57:47 +00:00
char * dup_str ;
char * src ;
2009-11-03 21:26:28 +00:00
int x = 0 ;
int curlen ;
if ( hook = = NULL ) {
return - 1 ;
}
2011-10-11 18:57:47 +00:00
/* Create our own copy of the AMI action msg string. */
src = dup_str = ast_strdup ( msg ) ;
if ( ! dup_str ) {
return - 1 ;
}
2009-11-03 21:26:28 +00:00
/* convert msg string to message struct */
2011-10-11 18:57:47 +00:00
curlen = strlen ( src ) ;
2009-11-03 21:26:28 +00:00
for ( x = 0 ; x < curlen ; x + + ) {
int cr ; /* set if we have \r */
if ( src [ x ] = = ' \r ' & & x + 1 < curlen & & src [ x + 1 ] = = ' \n ' )
cr = 2 ; /* Found. Update length to include \r\n */
else if ( src [ x ] = = ' \n ' )
cr = 1 ; /* also accept \n only */
else
continue ;
2011-10-11 18:57:47 +00:00
/* don't keep empty lines */
if ( x & & m . hdrcount < ARRAY_LEN ( m . headers ) ) {
/* ... but trim \r\n and terminate the header string */
src [ x ] = ' \0 ' ;
m . headers [ m . hdrcount + + ] = src ;
2009-11-03 21:26:28 +00:00
}
x + = cr ;
curlen - = x ; /* remaining size */
src + = x ; /* update pointer */
x = - 1 ; /* reset loop */
}
2011-10-11 18:57:47 +00:00
action = astman_get_header ( & m , " Action " ) ;
if ( strcasecmp ( action , " login " ) ) {
act_found = action_find ( action ) ;
if ( act_found ) {
2009-11-03 21:26:28 +00:00
/*
2011-10-11 18:57:47 +00:00
* we have to simulate a session for this action request
* to be able to pass it down for processing
* This is necessary to meet the previous design of manager . c
*/
2009-11-03 21:26:28 +00:00
s . hook = hook ;
s . f = ( void * ) 1 ; /* set this to something so our request will make it through all functions that test it*/
2011-10-11 18:57:47 +00:00
ao2_lock ( act_found ) ;
if ( act_found - > registered & & act_found - > func ) {
ret = act_found - > func ( & s , & m ) ;
} else {
ret = - 1 ;
}
ao2_unlock ( act_found ) ;
ao2_t_ref ( act_found , - 1 , " done with found action object " ) ;
2009-11-03 21:26:28 +00:00
}
}
2011-10-11 18:57:47 +00:00
ast_free ( dup_str ) ;
2009-11-03 21:26:28 +00:00
return ret ;
}
2006-11-28 10:23:25 +00:00
/*!
* helper function to send a string to the socket .
* Return - 1 on error ( e . g . buffer full ) .
*/
static int send_string ( struct mansession * s , char * string )
{
2011-03-16 19:51:04 +00:00
int res ;
2011-03-17 15:02:12 +00:00
FILE * f = s - > f ? s - > f : s - > session - > f ;
int fd = s - > f ? s - > fd : s - > session - > fd ;
2009-11-03 21:26:28 +00:00
/* It's a result from one of the hook's action invocation */
if ( s - > hook ) {
/*
* to send responses , we ' re using the same function
* as for receiving events . We call the event " HookResponse "
*/
s - > hook - > helper ( EVENT_FLAG_HOOKRESPONSE , " HookResponse " , string ) ;
return 0 ;
2011-03-17 15:02:12 +00:00
}
if ( ( res = ast_careful_fwrite ( f , fd , string , strlen ( string ) , s - > session - > writetimeout ) ) ) {
2011-03-16 19:51:04 +00:00
s - > write_error = 1 ;
2009-02-10 21:45:14 +00:00
}
2011-03-16 19:51:04 +00:00
return res ;
2006-11-28 10:23:25 +00:00
}
2007-07-30 19:31:27 +00:00
/*!
* \ brief thread local buffer for astman_append
*
* \ note This can not be defined within the astman_append ( ) function
* because it declares a couple of functions that get used to
* initialize the thread local storage key .
*/
2006-12-18 11:28:37 +00:00
AST_THREADSTORAGE ( astman_append_buf ) ;
2010-08-27 14:01:21 +00:00
2009-01-19 20:05:52 +00:00
AST_THREADSTORAGE ( userevent_buf ) ;
2007-07-30 19:31:27 +00:00
/*! \brief initial allocated size for the astman_append_buf */
2006-12-18 11:28:37 +00:00
# define ASTMAN_APPEND_BUF_INITSIZE 256
/*!
2006-10-18 17:45:50 +00:00
* utility functions for creating AMI replies
*/
void astman_append ( struct mansession * s , const char * fmt , . . . )
{
va_list ap ;
2006-12-15 23:10:42 +00:00
struct ast_str * buf ;
2006-10-18 17:45:50 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ( buf = ast_str_thread_get ( & astman_append_buf , ASTMAN_APPEND_BUF_INITSIZE ) ) ) {
2006-10-18 17:45:50 +00:00
return ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
va_start ( ap , fmt ) ;
2006-12-15 23:10:42 +00:00
ast_str_set_va ( & buf , 0 , fmt , ap ) ;
2006-10-18 17:45:50 +00:00
va_end ( ap ) ;
2006-10-18 21:41:09 +00:00
2009-02-10 21:45:14 +00:00
if ( s - > f ! = NULL | | s - > session - > f ! = NULL ) {
2008-12-13 08:36:35 +00:00
send_string ( s , ast_str_buffer ( buf ) ) ;
} else {
2006-11-28 10:23:25 +00:00
ast_verbose ( " fd == -1 in astman_append, should not happen \n " ) ;
2008-12-13 08:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
}
2006-10-18 11:43:31 +00:00
/*! \note NOTE: XXX this comment is unclear and possibly wrong.
2005-09-30 23:52:04 +00:00
Callers of astman_send_error ( ) , astman_send_response ( ) or astman_send_ack ( ) must EITHER
2009-02-10 21:45:14 +00:00
hold the session lock _or_ be running in an action callback ( in which case s - > session - > busy will
2005-09-30 23:52:04 +00:00
be non - zero ) . In either of these cases , there is no need to lock - protect the session ' s
fd , since no other output will be sent ( events will be queued ) , and no input will
be read until either the current action finishes or get_input ( ) obtains the session
lock .
*/
2002-09-12 18:32:42 +00:00
2010-08-27 14:01:21 +00:00
/*! \todo XXX MSG_MOREDATA should go to a header file. */
# define MSG_MOREDATA ((char *)astman_send_response)
2006-10-18 14:21:15 +00:00
/*! \brief send a response with an optional message,
* and terminate it with an empty line .
* m is used only to grab the ' ActionID ' field .
*
* Use the explicit constant MSG_MOREDATA to remove the empty line .
* XXX MSG_MOREDATA should go to a header file .
*/
2007-01-05 22:43:18 +00:00
static void astman_send_response_full ( struct mansession * s , const struct message * m , char * resp , char * msg , char * listflag )
2002-09-12 18:32:42 +00:00
{
2008-02-03 17:40:48 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
2004-07-08 15:39:35 +00:00
2006-10-18 17:45:50 +00:00
astman_append ( s , " Response: %s \r \n " , resp ) ;
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-10-18 17:45:50 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
}
if ( listflag ) {
2010-06-23 20:35:45 +00:00
astman_append ( s , " EventList: %s \r \n " , listflag ) ; /* Start, complete, cancelled */
2009-04-23 20:36:35 +00:00
}
if ( msg = = MSG_MOREDATA ) {
2006-10-18 17:45:50 +00:00
return ;
2009-04-23 20:36:35 +00:00
} else if ( msg ) {
2006-10-18 17:45:50 +00:00
astman_append ( s , " Message: %s \r \n \r \n " , msg ) ;
2009-04-23 20:36:35 +00:00
} else {
2006-10-18 17:45:50 +00:00
astman_append ( s , " \r \n " ) ;
2009-04-23 20:36:35 +00:00
}
2004-07-08 15:39:35 +00:00
}
2007-01-05 22:43:18 +00:00
void astman_send_response ( struct mansession * s , const struct message * m , char * resp , char * msg )
2006-10-30 21:18:39 +00:00
{
astman_send_response_full ( s , m , resp , msg , NULL ) ;
}
2007-01-05 22:43:18 +00:00
void astman_send_error ( struct mansession * s , const struct message * m , char * error )
2002-09-12 18:32:42 +00:00
{
2006-10-30 21:18:39 +00:00
astman_send_response_full ( s , m , " Error " , error , NULL ) ;
2006-10-18 17:45:50 +00:00
}
2004-07-08 15:39:35 +00:00
2007-01-05 22:43:18 +00:00
void astman_send_ack ( struct mansession * s , const struct message * m , char * msg )
2006-10-18 17:45:50 +00:00
{
2006-10-30 21:18:39 +00:00
astman_send_response_full ( s , m , " Success " , msg , NULL ) ;
2004-07-08 15:39:35 +00:00
}
2007-01-05 22:43:18 +00:00
static void astman_start_ack ( struct mansession * s , const struct message * m )
2004-07-08 17:08:38 +00:00
{
2006-10-30 21:18:39 +00:00
astman_send_response_full ( s , m , " Success " , MSG_MOREDATA , NULL ) ;
}
2007-01-05 22:43:18 +00:00
void astman_send_listack ( struct mansession * s , const struct message * m , char * msg , char * listflag )
2006-10-30 21:18:39 +00:00
{
astman_send_response_full ( s , m , " Success " , msg , listflag ) ;
2006-10-18 17:45:50 +00:00
}
2004-07-08 15:39:35 +00:00
2009-05-12 22:49:13 +00:00
/*! \brief Lock the 'mansession' structure. */
static void mansession_lock ( struct mansession * s )
{
ast_mutex_lock ( & s - > lock ) ;
}
/*! \brief Unlock the 'mansession' structure. */
static void mansession_unlock ( struct mansession * s )
{
ast_mutex_unlock ( & s - > lock ) ;
}
2004-07-08 15:39:35 +00:00
2006-06-22 15:34:20 +00:00
/*! \brief
2006-10-18 21:41:09 +00:00
Rather than braindead on , off this now can also accept a specific int mask value
2004-07-08 15:39:35 +00:00
or a ' , ' delim list of mask strings ( the same as manager . conf ) - anthm
*/
2007-01-05 22:43:18 +00:00
static int set_eventmask ( struct mansession * s , const char * eventmask )
2004-03-02 08:45:51 +00:00
{
2007-01-05 22:43:18 +00:00
int maskint = strings_to_mask ( eventmask ) ;
2004-07-08 15:39:35 +00:00
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-04-23 20:36:35 +00:00
if ( maskint > = 0 ) {
2009-02-10 21:45:14 +00:00
s - > session - > send_events = maskint ;
2009-04-23 20:36:35 +00:00
}
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-10-18 21:41:09 +00:00
2005-07-25 23:01:39 +00:00
return maskint ;
2004-03-02 08:45:51 +00:00
}
2009-07-11 19:15:03 +00:00
static enum ast_security_event_transport_type mansession_get_transport ( const struct mansession * s )
{
return s - > tcptls_session - > parent - > tls_cfg ? AST_SECURITY_EVENT_TRANSPORT_TLS :
AST_SECURITY_EVENT_TRANSPORT_TCP ;
}
static struct sockaddr_in * mansession_encode_sin_local ( const struct mansession * s ,
struct sockaddr_in * sin_local )
{
2010-07-08 22:08:07 +00:00
ast_sockaddr_to_sin ( & s - > tcptls_session - > parent - > local_address ,
sin_local ) ;
2009-07-11 19:15:03 +00:00
return sin_local ;
}
static void report_invalid_user ( const struct mansession * s , const char * username )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_inval_acct_id inval_acct_id = {
. common . event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID ,
. common . version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION ,
. common . service = " AMI " ,
. common . account_id = username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s ) ;
ast_security_event_report ( AST_SEC_EVT ( & inval_acct_id ) ) ;
}
static void report_failed_acl ( const struct mansession * s , const char * username )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_failed_acl failed_acl_event = {
. common . event_type = AST_SECURITY_EVENT_FAILED_ACL ,
. common . version = AST_SECURITY_EVENT_FAILED_ACL_VERSION ,
. common . service = " AMI " ,
. common . account_id = username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
ast_security_event_report ( AST_SEC_EVT ( & failed_acl_event ) ) ;
}
static void report_inval_password ( const struct mansession * s , const char * username )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_inval_password inval_password = {
. common . event_type = AST_SECURITY_EVENT_INVAL_PASSWORD ,
. common . version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION ,
. common . service = " AMI " ,
. common . account_id = username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
ast_security_event_report ( AST_SEC_EVT ( & inval_password ) ) ;
}
static void report_auth_success ( const struct mansession * s )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_successful_auth successful_auth = {
. common . event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH ,
. common . version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION ,
. common . service = " AMI " ,
. common . account_id = s - > session - > username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
ast_security_event_report ( AST_SEC_EVT ( & successful_auth ) ) ;
}
static void report_req_not_allowed ( const struct mansession * s , const char * action )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
char request_type [ 64 ] ;
struct ast_security_event_req_not_allowed req_not_allowed = {
. common . event_type = AST_SECURITY_EVENT_REQ_NOT_ALLOWED ,
. common . version = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION ,
. common . service = " AMI " ,
. common . account_id = s - > session - > username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
. request_type = request_type ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
snprintf ( request_type , sizeof ( request_type ) , " Action: %s " , action ) ;
ast_security_event_report ( AST_SEC_EVT ( & req_not_allowed ) ) ;
}
static void report_req_bad_format ( const struct mansession * s , const char * action )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
char request_type [ 64 ] ;
struct ast_security_event_req_bad_format req_bad_format = {
. common . event_type = AST_SECURITY_EVENT_REQ_BAD_FORMAT ,
. common . version = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION ,
. common . service = " AMI " ,
. common . account_id = s - > session - > username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
. request_type = request_type ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
snprintf ( request_type , sizeof ( request_type ) , " Action: %s " , action ) ;
ast_security_event_report ( AST_SEC_EVT ( & req_bad_format ) ) ;
}
static void report_failed_challenge_response ( const struct mansession * s ,
const char * response , const char * expected_response )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_chal_resp_failed chal_resp_failed = {
. common . event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED ,
. common . version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION ,
. common . service = " AMI " ,
. common . account_id = s - > session - > username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
. challenge = s - > session - > challenge ,
. response = response ,
. expected_response = expected_response ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
ast_security_event_report ( AST_SEC_EVT ( & chal_resp_failed ) ) ;
}
static void report_session_limit ( const struct mansession * s )
{
struct sockaddr_in sin_local ;
char session_id [ 32 ] ;
struct ast_security_event_session_limit session_limit = {
. common . event_type = AST_SECURITY_EVENT_SESSION_LIMIT ,
. common . version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION ,
. common . service = " AMI " ,
. common . account_id = s - > session - > username ,
. common . session_tv = & s - > session - > sessionstart_tv ,
. common . local_addr = {
. sin = mansession_encode_sin_local ( s , & sin_local ) ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . remote_addr = {
. sin = & s - > session - > sin ,
. transport = mansession_get_transport ( s ) ,
} ,
. common . session_id = session_id ,
} ;
snprintf ( session_id , sizeof ( session_id ) , " %p " , s - > session ) ;
ast_security_event_report ( AST_SEC_EVT ( & session_limit ) ) ;
}
2006-10-18 17:45:50 +00:00
/*
* Here we start with action_ handlers for AMI actions ,
* and the internal functions used by them .
* Generally , the handlers are called action_foo ( )
*/
/* helper function for action_login() */
2007-01-05 22:43:18 +00:00
static int authenticate ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2007-12-16 13:32:48 +00:00
const char * username = astman_get_header ( m , " Username " ) ;
const char * password = astman_get_header ( m , " Secret " ) ;
2006-10-18 12:38:24 +00:00
int error = - 1 ;
2007-12-16 13:32:48 +00:00
struct ast_manager_user * user = NULL ;
2010-06-22 16:29:18 +00:00
regex_t * regex_filter ;
struct ao2_iterator filter_iter ;
2010-07-19 14:17:16 +00:00
struct ast_sockaddr addr ;
2006-10-18 08:48:50 +00:00
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( username ) ) { /* missing username */
2002-09-12 18:32:42 +00:00
return - 1 ;
2009-04-23 20:36:35 +00:00
}
2007-01-18 18:54:51 +00:00
2007-12-16 13:32:48 +00:00
/* locate user in locked state */
AST_RWLIST_WRLOCK ( & users ) ;
2006-10-18 12:38:24 +00:00
2010-07-19 14:17:16 +00:00
ast_sockaddr_from_sin ( & addr , & s - > session - > sin ) ;
2007-12-16 13:32:48 +00:00
if ( ! ( user = get_manager_by_name_locked ( username ) ) ) {
2009-07-11 19:15:03 +00:00
report_invalid_user ( s , username ) ;
2009-02-10 21:45:14 +00:00
ast_log ( LOG_NOTICE , " %s tried to authenticate with nonexistent user '%s' \n " , ast_inet_ntoa ( s - > session - > sin . sin_addr ) , username ) ;
2010-07-19 14:17:16 +00:00
} else if ( user - > ha & & ! ast_apply_ha ( user - > ha , & addr ) ) {
2009-07-11 19:15:03 +00:00
report_failed_acl ( s , username ) ;
2009-02-10 21:45:14 +00:00
ast_log ( LOG_NOTICE , " %s failed to pass IP ACL as '%s' \n " , ast_inet_ntoa ( s - > session - > sin . sin_addr ) , username ) ;
2007-12-16 13:32:48 +00:00
} else if ( ! strcasecmp ( astman_get_header ( m , " AuthType " ) , " MD5 " ) ) {
2007-01-05 22:43:18 +00:00
const char * key = astman_get_header ( m , " Key " ) ;
2009-02-10 21:45:14 +00:00
if ( ! ast_strlen_zero ( key ) & & ! ast_strlen_zero ( s - > session - > challenge ) & & user - > secret ) {
2006-10-18 12:38:24 +00:00
int x ;
int len = 0 ;
char md5key [ 256 ] = " " ;
struct MD5Context md5 ;
unsigned char digest [ 16 ] ;
MD5Init ( & md5 ) ;
2009-02-10 21:45:14 +00:00
MD5Update ( & md5 , ( unsigned char * ) s - > session - > challenge , strlen ( s - > session - > challenge ) ) ;
2008-01-12 18:12:56 +00:00
MD5Update ( & md5 , ( unsigned char * ) user - > secret , strlen ( user - > secret ) ) ;
2006-10-18 12:38:24 +00:00
MD5Final ( digest , & md5 ) ;
2008-02-11 18:27:47 +00:00
for ( x = 0 ; x < 16 ; x + + )
2006-10-18 12:38:24 +00:00
len + = sprintf ( md5key + len , " %2.2x " , digest [ x ] ) ;
2009-04-23 20:36:35 +00:00
if ( ! strcmp ( md5key , key ) ) {
2006-10-18 12:38:24 +00:00
error = 0 ;
2009-07-11 19:15:03 +00:00
} else {
report_failed_challenge_response ( s , key , md5key ) ;
2009-04-23 20:36:35 +00:00
}
2007-05-11 16:21:45 +00:00
} else {
2009-04-23 20:36:35 +00:00
ast_debug ( 1 , " MD5 authentication is not possible. challenge: '%s' \n " ,
2009-02-10 21:45:14 +00:00
S_OR ( s - > session - > challenge , " " ) ) ;
2002-09-12 18:32:42 +00:00
}
2009-07-11 19:15:03 +00:00
} else if ( user - > secret ) {
if ( ! strcmp ( password , user - > secret ) ) {
error = 0 ;
} else {
report_inval_password ( s , username ) ;
}
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
2006-10-18 12:38:24 +00:00
if ( error ) {
2009-02-10 21:45:14 +00:00
ast_log ( LOG_NOTICE , " %s failed to authenticate as '%s' \n " , ast_inet_ntoa ( s - > session - > sin . sin_addr ) , username ) ;
2007-12-16 13:32:48 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2006-10-18 12:38:24 +00:00
return - 1 ;
}
2007-12-16 13:32:48 +00:00
/* auth complete */
2009-04-23 20:36:35 +00:00
2010-06-22 16:29:18 +00:00
/* All of the user parameters are copied to the session so that in the event
2010-08-27 14:01:21 +00:00
* of a reload and a configuration change , the session parameters are not
* changed . */
2009-02-10 21:45:14 +00:00
ast_copy_string ( s - > session - > username , username , sizeof ( s - > session - > username ) ) ;
s - > session - > readperm = user - > readperm ;
s - > session - > writeperm = user - > writeperm ;
s - > session - > writetimeout = user - > writetimeout ;
2010-06-22 16:29:18 +00:00
2010-06-22 17:57:28 +00:00
filter_iter = ao2_iterator_init ( user - > whitefilters , 0 ) ;
while ( ( regex_filter = ao2_iterator_next ( & filter_iter ) ) ) {
ao2_t_link ( s - > session - > whitefilters , regex_filter , " add white user filter to session " ) ;
ao2_t_ref ( regex_filter , - 1 , " remove iterator ref " ) ;
}
ao2_iterator_destroy ( & filter_iter ) ;
filter_iter = ao2_iterator_init ( user - > blackfilters , 0 ) ;
while ( ( regex_filter = ao2_iterator_next ( & filter_iter ) ) ) {
ao2_t_link ( s - > session - > blackfilters , regex_filter , " add black user filter to session " ) ;
ao2_t_ref ( regex_filter , - 1 , " remove iterator ref " ) ;
2010-06-22 16:29:18 +00:00
}
2010-06-22 17:57:28 +00:00
ao2_iterator_destroy ( & filter_iter ) ;
2009-02-10 21:45:14 +00:00
s - > session - > sessionstart = time ( NULL ) ;
2009-07-11 19:15:03 +00:00
s - > session - > sessionstart_tv = ast_tvnow ( ) ;
2006-10-18 12:38:24 +00:00
set_eventmask ( s , astman_get_header ( m , " Events " ) ) ;
2009-04-23 20:36:35 +00:00
2009-07-11 19:15:03 +00:00
report_auth_success ( s ) ;
2007-12-16 13:32:48 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2006-10-18 12:38:24 +00:00
return 0 ;
2002-09-12 18:32:42 +00:00
}
2007-01-05 22:43:18 +00:00
static int action_ping ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2008-12-18 21:43:17 +00:00
const char * actionid = astman_get_header ( m , " ActionID " ) ;
2009-06-26 20:52:19 +00:00
struct timeval now = ast_tvnow ( ) ;
2008-12-18 21:43:17 +00:00
astman_append ( s , " Response: Success \r \n " ) ;
if ( ! ast_strlen_zero ( actionid ) ) {
astman_append ( s , " ActionID: %s \r \n " , actionid ) ;
}
2009-09-09 12:11:12 +00:00
astman_append (
s ,
" Ping: Pong \r \n "
" Timestamp: %ld.%06lu \r \n "
" \r \n " ,
2010-03-20 12:03:07 +00:00
( long ) now . tv_sec , ( unsigned long ) now . tv_usec ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_getconfig ( struct mansession * s , const struct message * m )
2006-07-19 13:28:38 +00:00
{
struct ast_config * cfg ;
2007-01-05 22:43:18 +00:00
const char * fn = astman_get_header ( m , " Filename " ) ;
2008-02-12 00:24:36 +00:00
const char * category = astman_get_header ( m , " Category " ) ;
2006-07-19 13:28:38 +00:00
int catcount = 0 ;
int lineno = 0 ;
2008-02-12 00:24:36 +00:00
char * cur_category = NULL ;
2006-07-19 13:28:38 +00:00
struct ast_variable * v ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE } ;
2006-07-19 13:28:38 +00:00
if ( ast_strlen_zero ( fn ) ) {
astman_send_error ( s , m , " Filename not specified " ) ;
return 0 ;
}
2008-09-12 23:30:03 +00:00
cfg = ast_config_load2 ( fn , " manager " , config_flags ) ;
2009-08-27 21:26:37 +00:00
if ( cfg = = CONFIG_STATUS_FILEMISSING ) {
2006-07-19 13:28:38 +00:00
astman_send_error ( s , m , " Config file not found " ) ;
return 0 ;
2009-08-27 21:26:37 +00:00
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
astman_send_error ( s , m , " Config file has invalid format " ) ;
return 0 ;
2006-07-19 13:28:38 +00:00
}
2008-02-12 00:24:36 +00:00
astman_start_ack ( s , m ) ;
while ( ( cur_category = ast_category_browse ( cfg , cur_category ) ) ) {
if ( ast_strlen_zero ( category ) | | ( ! ast_strlen_zero ( category ) & & ! strcmp ( category , cur_category ) ) ) {
lineno = 0 ;
astman_append ( s , " Category-%06d: %s \r \n " , catcount , cur_category ) ;
2009-04-23 20:36:35 +00:00
for ( v = ast_variable_browse ( cfg , cur_category ) ; v ; v = v - > next ) {
2008-02-12 00:24:36 +00:00
astman_append ( s , " Line-%06d-%06d: %s=%s \r \n " , catcount , lineno + + , v - > name , v - > value ) ;
2009-04-23 20:36:35 +00:00
}
2008-02-12 00:24:36 +00:00
catcount + + ;
}
}
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( category ) & & catcount = = 0 ) { /* TODO: actually, a config with no categories doesn't even get loaded */
2008-12-03 20:35:36 +00:00
astman_append ( s , " No categories found \r \n " ) ;
2009-04-23 20:36:35 +00:00
}
2008-02-12 00:24:36 +00:00
ast_config_destroy ( cfg ) ;
astman_append ( s , " \r \n " ) ;
return 0 ;
}
static int action_listcategories ( struct mansession * s , const struct message * m )
{
struct ast_config * cfg ;
const char * fn = astman_get_header ( m , " Filename " ) ;
char * category = NULL ;
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE } ;
int catcount = 0 ;
if ( ast_strlen_zero ( fn ) ) {
astman_send_error ( s , m , " Filename not specified " ) ;
return 0 ;
}
2008-03-26 18:39:06 +00:00
if ( ! ( cfg = ast_config_load2 ( fn , " manager " , config_flags ) ) ) {
2009-08-27 21:26:37 +00:00
astman_send_error ( s , m , " Config file not found " ) ;
return 0 ;
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
astman_send_error ( s , m , " Config file has invalid format " ) ;
2008-02-12 00:24:36 +00:00
return 0 ;
}
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
2006-07-19 13:28:38 +00:00
while ( ( category = ast_category_browse ( cfg , category ) ) ) {
astman_append ( s , " Category-%06d: %s \r \n " , catcount , category ) ;
catcount + + ;
}
2009-04-23 20:36:35 +00:00
if ( catcount = = 0 ) { /* TODO: actually, a config with no categories doesn't even get loaded */
2008-12-03 20:32:20 +00:00
astman_append ( s , " Error: no categories found \r \n " ) ;
2009-04-23 20:36:35 +00:00
}
2006-07-19 13:28:38 +00:00
ast_config_destroy ( cfg ) ;
astman_append ( s , " \r \n " ) ;
2006-08-21 19:42:29 +00:00
2006-07-19 13:28:38 +00:00
return 0 ;
}
2008-02-12 00:24:36 +00:00
2009-04-23 20:36:35 +00:00
2008-02-12 00:24:36 +00:00
2007-04-23 18:49:19 +00:00
/*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
static void json_escape ( char * out , const char * in )
{
for ( ; * in ; in + + ) {
2009-04-23 20:36:35 +00:00
if ( * in = = ' \\ ' | | * in = = ' \" ' ) {
2007-04-23 18:49:19 +00:00
* out + + = ' \\ ' ;
2009-04-23 20:36:35 +00:00
}
2007-04-23 18:49:19 +00:00
* out + + = * in ;
}
* out = ' \0 ' ;
}
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Append a JSON escaped string to the manager stream .
*
* \ param s AMI stream to append a string .
* \ param str String to append to the stream after JSON escaping it .
*
* \ return Nothing
*/
static void astman_append_json ( struct mansession * s , const char * str )
{
char * buf ;
buf = alloca ( 2 * strlen ( str ) + 1 ) ;
json_escape ( buf , str ) ;
astman_append ( s , " %s " , buf ) ;
}
2007-02-23 00:45:04 +00:00
static int action_getconfigjson ( struct mansession * s , const struct message * m )
{
struct ast_config * cfg ;
const char * fn = astman_get_header ( m , " Filename " ) ;
char * category = NULL ;
struct ast_variable * v ;
int comma1 = 0 ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE } ;
2007-02-23 00:45:04 +00:00
if ( ast_strlen_zero ( fn ) ) {
astman_send_error ( s , m , " Filename not specified " ) ;
return 0 ;
}
2008-03-26 18:39:06 +00:00
if ( ! ( cfg = ast_config_load2 ( fn , " manager " , config_flags ) ) ) {
2007-02-23 00:45:04 +00:00
astman_send_error ( s , m , " Config file not found " ) ;
return 0 ;
2009-08-27 21:26:37 +00:00
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
astman_send_error ( s , m , " Config file has invalid format " ) ;
return 0 ;
2007-02-23 00:45:04 +00:00
}
astman_start_ack ( s , m ) ;
astman_append ( s , " JSON: { " ) ;
while ( ( category = ast_category_browse ( cfg , category ) ) ) {
int comma2 = 0 ;
2011-10-11 18:57:47 +00:00
astman_append ( s , " %s \" " , comma1 ? " , " : " " ) ;
astman_append_json ( s , category ) ;
astman_append ( s , " \" :[ " ) ;
comma1 = 1 ;
2007-02-23 00:45:04 +00:00
for ( v = ast_variable_browse ( cfg , category ) ; v ; v = v - > next ) {
2011-10-11 18:57:47 +00:00
astman_append ( s , " %s \" " , comma2 ? " , " : " " ) ;
astman_append_json ( s , v - > name ) ;
astman_append ( s , " \" : \" " ) ;
astman_append_json ( s , v - > value ) ;
astman_append ( s , " \" " ) ;
comma2 = 1 ;
2007-02-23 00:45:04 +00:00
}
astman_append ( s , " ] " ) ;
}
astman_append ( s , " } \r \n \r \n " ) ;
ast_config_destroy ( cfg ) ;
return 0 ;
}
2010-08-27 14:01:21 +00:00
/*! \brief helper function for action_updateconfig */
2008-02-12 00:24:36 +00:00
static enum error_type handle_updates ( struct mansession * s , const struct message * m , struct ast_config * cfg , const char * dfn )
2006-07-19 13:28:38 +00:00
{
int x ;
char hdr [ 40 ] ;
2008-07-25 19:12:17 +00:00
const char * action , * cat , * var , * value , * match , * line ;
2006-07-19 13:28:38 +00:00
struct ast_category * category ;
struct ast_variable * v ;
2008-07-18 20:57:47 +00:00
struct ast_str * str1 = ast_str_create ( 16 ) , * str2 = ast_str_create ( 16 ) ;
enum error_type result = 0 ;
2006-10-18 21:41:09 +00:00
2008-11-11 23:32:31 +00:00
for ( x = 0 ; x < 100000 ; x + + ) { /* 100000 = the max number of allowed updates + 1 */
2007-04-20 18:23:24 +00:00
unsigned int object = 0 ;
2006-07-19 13:28:38 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Action-%06d " , x ) ;
action = astman_get_header ( m , hdr ) ;
2008-11-11 23:32:31 +00:00
if ( ast_strlen_zero ( action ) ) /* breaks the for loop if no action header */
break ; /* this could cause problems if actions come in misnumbered */
2008-11-11 23:02:43 +00:00
2006-07-19 13:28:38 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Cat-%06d " , x ) ;
cat = astman_get_header ( m , hdr ) ;
2008-11-11 23:32:31 +00:00
if ( ast_strlen_zero ( cat ) ) { /* every action needs a category */
2008-11-11 23:02:43 +00:00
result = UNSPECIFIED_CATEGORY ;
break ;
}
2006-07-19 13:28:38 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Var-%06d " , x ) ;
2008-07-25 19:12:17 +00:00
var = astman_get_header ( m , hdr ) ;
2008-11-11 23:02:43 +00:00
2006-07-19 13:28:38 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Value-%06d " , x ) ;
2008-07-25 19:12:17 +00:00
value = astman_get_header ( m , hdr ) ;
2007-04-20 18:23:24 +00:00
if ( ! ast_strlen_zero ( value ) & & * value = = ' > ' ) {
object = 1 ;
value + + ;
}
2009-04-23 20:36:35 +00:00
2006-07-29 22:02:37 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Match-%06d " , x ) ;
match = astman_get_header ( m , hdr ) ;
2008-11-11 23:02:43 +00:00
2008-02-12 00:24:36 +00:00
snprintf ( hdr , sizeof ( hdr ) , " Line-%06d " , x ) ;
line = astman_get_header ( m , hdr ) ;
2008-11-11 23:02:43 +00:00
2006-07-19 13:28:38 +00:00
if ( ! strcasecmp ( action , " newcat " ) ) {
2008-11-11 23:32:31 +00:00
if ( ast_category_get ( cfg , cat ) ) { /* check to make sure the cat doesn't */
result = FAILURE_NEWCAT ; /* already exist */
2008-07-18 20:57:47 +00:00
break ;
}
if ( ! ( category = ast_category_new ( cat , dfn , - 1 ) ) ) {
result = FAILURE_ALLOCATION ;
break ;
}
2008-02-12 00:24:36 +00:00
if ( ast_strlen_zero ( match ) ) {
ast_category_append ( cfg , category ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-12 00:24:36 +00:00
ast_category_insert ( cfg , category , match ) ;
2009-04-23 20:36:35 +00:00
}
2006-07-19 13:28:38 +00:00
} else if ( ! strcasecmp ( action , " renamecat " ) ) {
2008-11-11 23:02:43 +00:00
if ( ast_strlen_zero ( value ) ) {
2008-07-18 20:57:47 +00:00
result = UNSPECIFIED_ARGUMENT ;
break ;
}
if ( ! ( category = ast_category_get ( cfg , cat ) ) ) {
result = UNKNOWN_CATEGORY ;
break ;
}
2008-02-12 00:24:36 +00:00
ast_category_rename ( category , value ) ;
2006-07-19 13:28:38 +00:00
} else if ( ! strcasecmp ( action , " delcat " ) ) {
2008-07-18 20:57:47 +00:00
if ( ast_category_delete ( cfg , cat ) ) {
result = FAILURE_DELCAT ;
break ;
}
2008-02-12 00:24:36 +00:00
} else if ( ! strcasecmp ( action , " emptycat " ) ) {
2008-07-18 20:57:47 +00:00
if ( ast_category_empty ( cfg , cat ) ) {
result = FAILURE_EMPTYCAT ;
break ;
}
2006-07-19 13:28:38 +00:00
} else if ( ! strcasecmp ( action , " update " ) ) {
2008-11-11 23:02:43 +00:00
if ( ast_strlen_zero ( var ) ) {
2008-07-18 20:57:47 +00:00
result = UNSPECIFIED_ARGUMENT ;
break ;
}
if ( ! ( category = ast_category_get ( cfg , cat ) ) ) {
result = UNKNOWN_CATEGORY ;
break ;
}
if ( ast_variable_update ( category , var , value , match , object ) ) {
result = FAILURE_UPDATE ;
break ;
}
2006-07-19 13:28:38 +00:00
} else if ( ! strcasecmp ( action , " delete " ) ) {
2008-11-11 23:02:43 +00:00
if ( ( ast_strlen_zero ( var ) & & ast_strlen_zero ( line ) ) ) {
2008-07-18 20:57:47 +00:00
result = UNSPECIFIED_ARGUMENT ;
break ;
}
if ( ! ( category = ast_category_get ( cfg , cat ) ) ) {
result = UNKNOWN_CATEGORY ;
break ;
}
if ( ast_variable_delete ( category , var , match , line ) ) {
result = FAILURE_DELETE ;
break ;
}
2006-07-19 13:28:38 +00:00
} else if ( ! strcasecmp ( action , " append " ) ) {
2008-11-11 23:02:43 +00:00
if ( ast_strlen_zero ( var ) ) {
2008-07-18 20:57:47 +00:00
result = UNSPECIFIED_ARGUMENT ;
break ;
}
if ( ! ( category = ast_category_get ( cfg , cat ) ) ) {
2009-04-23 20:36:35 +00:00
result = UNKNOWN_CATEGORY ;
2008-07-18 20:57:47 +00:00
break ;
}
if ( ! ( v = ast_variable_new ( var , value , dfn ) ) ) {
result = FAILURE_ALLOCATION ;
break ;
}
2009-04-23 20:36:35 +00:00
if ( object | | ( match & & ! strcasecmp ( match , " object " ) ) ) {
2008-02-12 00:24:36 +00:00
v - > object = 1 ;
2009-04-23 20:36:35 +00:00
}
2008-02-12 00:24:36 +00:00
ast_variable_append ( category , v ) ;
} else if ( ! strcasecmp ( action , " insert " ) ) {
2008-11-11 23:02:43 +00:00
if ( ast_strlen_zero ( var ) | | ast_strlen_zero ( line ) ) {
2008-07-18 20:57:47 +00:00
result = UNSPECIFIED_ARGUMENT ;
break ;
}
if ( ! ( category = ast_category_get ( cfg , cat ) ) ) {
result = UNKNOWN_CATEGORY ;
break ;
}
if ( ! ( v = ast_variable_new ( var , value , dfn ) ) ) {
result = FAILURE_ALLOCATION ;
break ;
}
2008-02-12 00:24:36 +00:00
ast_variable_insert ( category , v , line ) ;
}
else {
ast_log ( LOG_WARNING , " Action-%06d: %s not handled \n " , x , action ) ;
2008-07-18 20:57:47 +00:00
result = UNKNOWN_ACTION ;
break ;
2006-07-19 13:28:38 +00:00
}
}
2008-07-18 20:57:47 +00:00
ast_free ( str1 ) ;
ast_free ( str2 ) ;
return result ;
2006-07-19 13:28:38 +00:00
}
2007-01-05 22:43:18 +00:00
static int action_updateconfig ( struct mansession * s , const struct message * m )
2006-07-19 13:28:38 +00:00
{
struct ast_config * cfg ;
2007-01-05 22:43:18 +00:00
const char * sfn = astman_get_header ( m , " SrcFilename " ) ;
const char * dfn = astman_get_header ( m , " DstFilename " ) ;
2006-07-19 13:28:38 +00:00
int res ;
2007-01-05 22:43:18 +00:00
const char * rld = astman_get_header ( m , " Reload " ) ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE } ;
2008-02-12 00:24:36 +00:00
enum error_type result ;
2006-07-19 13:28:38 +00:00
if ( ast_strlen_zero ( sfn ) | | ast_strlen_zero ( dfn ) ) {
astman_send_error ( s , m , " Filename not specified " ) ;
return 0 ;
}
2008-03-26 18:39:06 +00:00
if ( ! ( cfg = ast_config_load2 ( sfn , " manager " , config_flags ) ) ) {
2008-03-04 23:04:29 +00:00
astman_send_error ( s , m , " Config file not found " ) ;
return 0 ;
2009-08-27 21:26:37 +00:00
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
astman_send_error ( s , m , " Config file has invalid format " ) ;
return 0 ;
2008-03-04 23:04:29 +00:00
}
2008-02-12 00:24:36 +00:00
result = handle_updates ( s , m , cfg , dfn ) ;
if ( ! result ) {
ast_include_rename ( cfg , sfn , dfn ) ; /* change the include references from dfn to sfn, so things match up */
2008-11-04 18:47:20 +00:00
res = ast_config_text_file_save ( dfn , cfg , " Manager " ) ;
2008-02-12 00:24:36 +00:00
ast_config_destroy ( cfg ) ;
if ( res ) {
astman_send_error ( s , m , " Save of config failed " ) ;
return 0 ;
}
astman_send_ack ( s , m , NULL ) ;
if ( ! ast_strlen_zero ( rld ) ) {
2009-04-23 20:36:35 +00:00
if ( ast_true ( rld ) ) {
2008-02-12 00:24:36 +00:00
rld = NULL ;
2009-04-23 20:36:35 +00:00
}
2008-02-12 00:24:36 +00:00
ast_module_reload ( rld ) ;
}
} else {
ast_config_destroy ( cfg ) ;
switch ( result ) {
case UNKNOWN_ACTION :
astman_send_error ( s , m , " Unknown action command " ) ;
break ;
case UNKNOWN_CATEGORY :
astman_send_error ( s , m , " Given category does not exist " ) ;
break ;
case UNSPECIFIED_CATEGORY :
astman_send_error ( s , m , " Category not specified " ) ;
break ;
case UNSPECIFIED_ARGUMENT :
astman_send_error ( s , m , " Problem with category, value, or line (if required) " ) ;
break ;
case FAILURE_ALLOCATION :
astman_send_error ( s , m , " Memory allocation failure, this should not happen " ) ;
break ;
2008-11-11 23:02:43 +00:00
case FAILURE_NEWCAT :
astman_send_error ( s , m , " Create category did not complete successfully " ) ;
break ;
2008-02-12 00:24:36 +00:00
case FAILURE_DELCAT :
astman_send_error ( s , m , " Delete category did not complete successfully " ) ;
break ;
case FAILURE_EMPTYCAT :
astman_send_error ( s , m , " Empty category did not complete successfully " ) ;
break ;
case FAILURE_UPDATE :
astman_send_error ( s , m , " Update did not complete successfully " ) ;
break ;
case FAILURE_DELETE :
astman_send_error ( s , m , " Delete did not complete successfully " ) ;
break ;
case FAILURE_APPEND :
astman_send_error ( s , m , " Append did not complete successfully " ) ;
break ;
}
2006-09-16 23:53:58 +00:00
}
2006-07-19 13:28:38 +00:00
return 0 ;
}
2008-02-12 00:24:36 +00:00
static int action_createconfig ( struct mansession * s , const struct message * m )
{
int fd ;
const char * fn = astman_get_header ( m , " Filename " ) ;
struct ast_str * filepath = ast_str_alloca ( PATH_MAX ) ;
ast_str_set ( & filepath , 0 , " %s/ " , ast_config_AST_CONFIG_DIR ) ;
ast_str_append ( & filepath , 0 , " %s " , fn ) ;
2008-12-13 08:36:35 +00:00
if ( ( fd = open ( ast_str_buffer ( filepath ) , O_CREAT | O_EXCL , AST_FILE_MODE ) ) ! = - 1 ) {
2008-02-12 00:24:36 +00:00
close ( fd ) ;
astman_send_ack ( s , m , " New configuration file created successfully " ) ;
2008-12-13 08:36:35 +00:00
} else {
2008-02-12 00:24:36 +00:00
astman_send_error ( s , m , strerror ( errno ) ) ;
2008-12-13 08:36:35 +00:00
}
2008-02-12 00:24:36 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_waitevent ( struct mansession * s , const struct message * m )
2006-04-01 08:49:54 +00:00
{
2007-01-05 22:43:18 +00:00
const char * timeouts = astman_get_header ( m , " Timeout " ) ;
2006-11-28 12:05:25 +00:00
int timeout = - 1 ;
2006-04-01 08:49:54 +00:00
int x ;
int needexit = 0 ;
2008-02-03 17:40:48 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] ;
2006-04-01 08:49:54 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-04-01 08:49:54 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-03 17:40:48 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2006-04-01 08:49:54 +00:00
if ( ! ast_strlen_zero ( timeouts ) ) {
2009-08-10 19:20:57 +00:00
sscanf ( timeouts , " %30i " , & timeout ) ;
2009-04-23 20:36:35 +00:00
if ( timeout < - 1 ) {
2006-11-28 12:05:25 +00:00
timeout = - 1 ;
2009-04-23 20:36:35 +00:00
}
2006-11-28 12:05:25 +00:00
/* XXX maybe put an upper bound, or prevent the use of 0 ? */
2006-04-01 08:49:54 +00:00
}
2006-10-18 21:41:09 +00:00
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-04-23 20:36:35 +00:00
if ( s - > session - > waiting_thread ! = AST_PTHREADT_NULL ) {
2009-02-10 21:45:14 +00:00
pthread_kill ( s - > session - > waiting_thread , SIGURG ) ;
2009-04-23 20:36:35 +00:00
}
2006-11-28 12:05:25 +00:00
2009-02-10 21:45:14 +00:00
if ( s - > session - > managerid ) { /* AMI-over-HTTP session */
2006-11-28 12:05:25 +00:00
/*
* Make sure the timeout is within the expire time of the session ,
* as the client will likely abort the request if it does not see
* data coming after some amount of time .
*/
time_t now = time ( NULL ) ;
2009-02-10 21:45:14 +00:00
int max = s - > session - > sessiontimeout - now - 10 ;
2006-11-28 12:05:25 +00:00
2009-04-23 20:36:35 +00:00
if ( max < 0 ) { /* We are already late. Strange but possible. */
2006-04-01 08:49:54 +00:00
max = 0 ;
2009-04-23 20:36:35 +00:00
}
if ( timeout < 0 | | timeout > max ) {
2006-04-01 08:49:54 +00:00
timeout = max ;
2009-04-23 20:36:35 +00:00
}
if ( ! s - > session - > send_events ) { /* make sure we record events */
2009-02-10 21:45:14 +00:00
s - > session - > send_events = - 1 ;
2009-04-23 20:36:35 +00:00
}
2006-04-01 08:49:54 +00:00
}
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-11-28 12:05:25 +00:00
/* XXX should this go inside the lock ? */
2009-02-10 21:45:14 +00:00
s - > session - > waiting_thread = pthread_self ( ) ; /* let new events wake up this thread */
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Starting waiting for an event! \n " ) ;
2006-11-28 12:05:25 +00:00
2008-02-11 18:27:47 +00:00
for ( x = 0 ; x < timeout | | timeout < 0 ; x + + ) {
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2010-06-01 16:41:00 +00:00
if ( AST_RWLIST_NEXT ( s - > session - > last_ev , eq_next ) ) {
2006-04-01 08:49:54 +00:00
needexit = 1 ;
2009-04-23 20:36:35 +00:00
}
2006-11-28 12:05:25 +00:00
/* We can have multiple HTTP session point to the same mansession entry.
* The way we deal with it is not very nice : newcomers kick out the previous
* HTTP session . XXX this needs to be improved .
*/
2009-04-23 20:36:35 +00:00
if ( s - > session - > waiting_thread ! = pthread_self ( ) ) {
2006-04-01 08:49:54 +00:00
needexit = 1 ;
2009-04-23 20:36:35 +00:00
}
if ( s - > session - > needdestroy ) {
2006-04-01 08:49:54 +00:00
needexit = 1 ;
2009-04-23 20:36:35 +00:00
}
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2009-04-23 20:36:35 +00:00
if ( needexit ) {
2006-04-01 08:49:54 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2009-02-10 21:45:14 +00:00
if ( s - > session - > managerid = = 0 ) { /* AMI session */
2009-04-23 20:36:35 +00:00
if ( ast_wait_for_input ( s - > session - > fd , 1000 ) ) {
2006-04-01 08:49:54 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2006-10-19 17:07:08 +00:00
} else { /* HTTP session */
2006-04-01 08:49:54 +00:00
sleep ( 1 ) ;
}
}
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Finished waiting for an event! \n " ) ;
2009-04-23 20:36:35 +00:00
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-02-10 21:45:14 +00:00
if ( s - > session - > waiting_thread = = pthread_self ( ) ) {
2010-06-01 16:41:00 +00:00
struct eventqent * eqe = s - > session - > last_ev ;
2006-11-28 12:05:25 +00:00
astman_send_response ( s , m , " Success " , " Waiting for Event completed. " ) ;
2010-06-01 16:41:00 +00:00
while ( ( eqe = advance_event ( eqe ) ) ) {
2009-02-10 21:45:14 +00:00
if ( ( ( s - > session - > readperm & eqe - > category ) = = eqe - > category ) & &
( ( s - > session - > send_events & eqe - > category ) = = eqe - > category ) ) {
2006-04-02 19:59:55 +00:00
astman_append ( s , " %s " , eqe - > eventdata ) ;
}
2010-06-01 16:41:00 +00:00
s - > session - > last_ev = eqe ;
2006-04-01 08:49:54 +00:00
}
astman_append ( s ,
" Event: WaitEventComplete \r \n "
" %s "
2006-04-04 19:03:12 +00:00
" \r \n " , idText ) ;
2009-02-10 21:45:14 +00:00
s - > session - > waiting_thread = AST_PTHREADT_NULL ;
2006-04-01 08:49:54 +00:00
} else {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Abandoning event request! \n " ) ;
2006-04-01 08:49:54 +00:00
}
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-04-01 08:49:54 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_listcommands ( struct mansession * s , const struct message * m )
2004-06-02 22:30:42 +00:00
{
2006-10-16 09:33:00 +00:00
struct manager_action * cur ;
2011-10-11 18:57:47 +00:00
struct ast_str * temp = ast_str_alloca ( 256 ) ;
2004-06-02 22:30:42 +00:00
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
2011-10-11 18:57:47 +00:00
AST_RWLIST_RDLOCK ( & actions ) ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_TRAVERSE ( & actions , cur , list ) {
2011-10-11 18:57:47 +00:00
if ( ( s - > session - > writeperm & cur - > authority ) | | cur - > authority = = 0 ) {
2006-12-18 11:28:37 +00:00
astman_append ( s , " %s: %s (Priv: %s) \r \n " ,
cur - > action , cur - > synopsis , authority_to_str ( cur - > authority , & temp ) ) ;
2009-04-23 20:36:35 +00:00
}
2004-06-02 22:30:42 +00:00
}
2011-10-11 18:57:47 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " \r \n " ) ;
2004-06-02 22:30:42 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_events ( struct mansession * s , const struct message * m )
2004-03-01 21:12:32 +00:00
{
2007-01-05 22:43:18 +00:00
const char * mask = astman_get_header ( m , " EventMask " ) ;
2010-04-13 18:10:30 +00:00
int res , x ;
2011-05-05 21:54:17 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
char id_text [ 256 ] ;
if ( ! ast_strlen_zero ( id ) ) {
snprintf ( id_text , sizeof ( id_text ) , " ActionID: %s \r \n " , id ) ;
} else {
id_text [ 0 ] = ' \0 ' ;
}
2004-03-02 08:45:51 +00:00
res = set_eventmask ( s , mask ) ;
2010-04-13 18:10:30 +00:00
if ( broken_events_action ) {
/* if this option is set we should not return a response on
* error , or when all events are set */
if ( res > 0 ) {
for ( x = 0 ; x < ARRAY_LEN ( perms ) ; x + + ) {
if ( ! strcasecmp ( perms [ x ] . label , " all " ) & & res = = perms [ x ] . num ) {
return 0 ;
}
}
2011-05-05 21:54:17 +00:00
astman_append ( s , " Response: Success \r \n %s "
" Events: On \r \n \r \n " , id_text ) ;
2010-04-13 18:10:30 +00:00
} else if ( res = = 0 )
2011-05-05 21:54:17 +00:00
astman_append ( s , " Response: Success \r \n %s "
" Events: Off \r \n \r \n " , id_text ) ;
2010-04-13 18:10:30 +00:00
return 0 ;
}
2004-03-02 08:45:51 +00:00
if ( res > 0 )
2011-05-05 21:54:17 +00:00
astman_append ( s , " Response: Success \r \n %s "
" Events: On \r \n \r \n " , id_text ) ;
2004-03-02 08:45:51 +00:00
else if ( res = = 0 )
2011-05-05 21:54:17 +00:00
astman_append ( s , " Response: Success \r \n %s "
" Events: Off \r \n \r \n " , id_text ) ;
2010-04-13 18:10:30 +00:00
else
astman_send_error ( s , m , " Invalid event mask " ) ;
2004-03-01 21:12:32 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_logoff ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2003-09-08 16:44:36 +00:00
astman_send_response ( s , m , " Goodbye " , " Thanks for all the fish. " ) ;
2002-09-12 18:32:42 +00:00
return - 1 ;
}
2007-01-05 22:43:18 +00:00
static int action_login ( struct mansession * s , const struct message * m )
2006-10-18 13:23:22 +00:00
{
2009-04-23 20:36:35 +00:00
/* still authenticated - don't process again */
if ( s - > session - > authenticated ) {
astman_send_ack ( s , m , " Already authenticated " ) ;
return 0 ;
}
2006-10-18 13:23:22 +00:00
if ( authenticate ( s , m ) ) {
sleep ( 1 ) ;
astman_send_error ( s , m , " Authentication failed " ) ;
return - 1 ;
}
2009-02-10 21:45:14 +00:00
s - > session - > authenticated = 1 ;
2011-04-05 14:16:21 +00:00
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
2009-04-23 20:36:35 +00:00
if ( manager_displayconnects ( s - > session ) ) {
2009-02-10 21:45:14 +00:00
ast_verb ( 2 , " %sManager '%s' logged on from %s \n " , ( s - > session - > managerid ? " HTTP " : " " ) , s - > session - > username , ast_inet_ntoa ( s - > session - > sin . sin_addr ) ) ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 13:23:22 +00:00
astman_send_ack ( s , m , " Authentication accepted " ) ;
2011-05-03 18:23:03 +00:00
if ( ( s - > session - > send_events & EVENT_FLAG_SYSTEM )
& & ast_test_flag ( & ast_options , AST_OPT_FLAG_FULLY_BOOTED ) ) {
2011-02-24 17:59:32 +00:00
struct ast_str * auth = ast_str_alloca ( 80 ) ;
const char * cat_str = authority_to_str ( EVENT_FLAG_SYSTEM , & auth ) ;
astman_append ( s , " Event: FullyBooted \r \n "
" Privilege: %s \r \n "
" Status: Fully Booted \r \n \r \n " , cat_str ) ;
2010-05-24 22:21:58 +00:00
}
2006-10-18 13:23:22 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_challenge ( struct mansession * s , const struct message * m )
2006-10-18 13:23:22 +00:00
{
2007-01-05 22:43:18 +00:00
const char * authtype = astman_get_header ( m , " AuthType " ) ;
2006-10-18 13:23:22 +00:00
if ( ! strcasecmp ( authtype , " MD5 " ) ) {
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( s - > session - > challenge ) ) {
2009-02-10 21:45:14 +00:00
snprintf ( s - > session - > challenge , sizeof ( s - > session - > challenge ) , " %ld " , ast_random ( ) ) ;
2009-04-23 20:36:35 +00:00
}
2009-05-12 22:49:13 +00:00
mansession_lock ( s ) ;
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
2009-02-10 21:45:14 +00:00
astman_append ( s , " Challenge: %s \r \n \r \n " , s - > session - > challenge ) ;
2009-05-12 22:49:13 +00:00
mansession_unlock ( s ) ;
2006-10-18 13:23:22 +00:00
} else {
astman_send_error ( s , m , " Must specify AuthType " ) ;
}
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_hangup ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
struct ast_channel * c = NULL ;
2009-04-01 00:39:01 +00:00
int causecode = 0 ; /* all values <= 0 mean 'do not set hangupcause in channel' */
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
2009-04-01 00:39:01 +00:00
const char * cause = astman_get_header ( m , " Cause " ) ;
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
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
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
2009-04-01 00:39:01 +00:00
if ( ! ast_strlen_zero ( cause ) ) {
char * endptr ;
causecode = strtol ( cause , & endptr , 10 ) ;
if ( causecode < 0 | | causecode > 127 | | * endptr ! = ' \0 ' ) {
ast_log ( LOG_NOTICE , " Invalid 'Cause: %s' in manager action Hangup \n " , cause ) ;
/* keep going, better to hangup without cause than to not hang up at all */
causecode = 0 ; /* do not set channel's hangupcause */
}
}
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No such channel " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
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
ast_channel_lock ( c ) ;
2009-04-01 00:39:01 +00:00
if ( causecode > 0 ) {
2009-04-01 13:59:34 +00:00
ast_debug ( 1 , " Setting hangupcause of channel %s to %d (is %d now) \n " ,
2012-02-20 23:43:27 +00:00
ast_channel_name ( c ) , causecode , ast_channel_hangupcause ( c ) ) ;
ast_channel_hangupcause_set ( c , causecode ) ;
2009-04-01 00:39:01 +00:00
}
2009-04-01 13:59:34 +00:00
ast_softhangup_nolock ( c , AST_SOFTHANGUP_EXPLICIT ) ;
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( c ) ;
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
c = ast_channel_unref ( c ) ;
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Channel Hungup " ) ;
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
2002-09-12 18:32:42 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_setvar ( struct mansession * s , const struct message * m )
2004-06-03 15:42:36 +00:00
{
2007-06-06 20:35:05 +00:00
struct ast_channel * c = NULL ;
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
const char * varname = astman_get_header ( m , " Variable " ) ;
const char * varval = astman_get_header ( m , " Value " ) ;
2010-01-25 20:27:59 +00:00
int res = 0 ;
2005-11-08 03:35:40 +00:00
if ( ast_strlen_zero ( varname ) ) {
2004-06-03 15:42:36 +00:00
astman_send_error ( s , m , " No variable specified " ) ;
return 0 ;
}
2006-10-18 21:41:09 +00:00
2005-11-08 03:35:40 +00:00
if ( ! ast_strlen_zero ( name ) ) {
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2005-11-08 03:35:40 +00:00
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
2004-06-03 15:42:36 +00:00
}
2010-01-25 21:13:20 +00:00
res = pbx_builtin_setvar_helper ( c , varname , S_OR ( varval , " " ) ) ;
2006-10-18 21:41:09 +00:00
2009-04-23 20:36:35 +00:00
if ( c ) {
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
c = ast_channel_unref ( c ) ;
2009-04-23 20:36:35 +00:00
}
2010-01-25 20:27:59 +00:00
if ( res = = 0 ) {
astman_send_ack ( s , m , " Variable Set " ) ;
} else {
astman_send_error ( s , m , " Variable not set " ) ;
}
2004-06-03 15:42:36 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_getvar ( struct mansession * s , const struct message * m )
2004-06-03 15:42:36 +00:00
{
2005-12-27 19:13:13 +00:00
struct ast_channel * c = NULL ;
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
const char * varname = astman_get_header ( m , " Variable " ) ;
2005-12-27 19:13:13 +00:00
char * varval ;
2011-09-26 19:40:12 +00:00
char workspace [ 1024 ] ;
2004-06-03 15:42:36 +00:00
2005-12-27 19:13:13 +00:00
if ( ast_strlen_zero ( varname ) ) {
2004-06-03 15:42:36 +00:00
astman_send_error ( s , m , " No variable specified " ) ;
return 0 ;
}
2005-12-27 19:13:13 +00:00
if ( ! ast_strlen_zero ( name ) ) {
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2005-10-13 20:30:39 +00:00
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
2004-06-03 15:42:36 +00:00
}
2005-12-27 19:13:13 +00:00
2011-09-26 19:40:12 +00:00
workspace [ 0 ] = ' \0 ' ;
2006-01-15 05:50:19 +00:00
if ( varname [ strlen ( varname ) - 1 ] = = ' ) ' ) {
2008-10-18 02:18:33 +00:00
if ( ! c ) {
2009-06-26 15:28:53 +00:00
c = ast_dummy_channel_alloc ( ) ;
2008-10-18 02:18:33 +00:00
if ( c ) {
ast_func_read ( c , ( char * ) varname , workspace , sizeof ( workspace ) ) ;
} else
ast_log ( LOG_ERROR , " Unable to allocate bogus channel for variable substitution. Function results may be blank. \n " ) ;
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
} else {
2008-10-18 02:18:33 +00:00
ast_func_read ( c , ( char * ) varname , workspace , sizeof ( workspace ) ) ;
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
}
2007-04-19 04:37:29 +00:00
varval = workspace ;
2006-01-15 05:50:19 +00:00
} else {
pbx_retrieve_variable ( c , varname , & varval , workspace , sizeof ( workspace ) , NULL ) ;
}
2005-12-27 19:13:13 +00:00
2009-04-23 20:36:35 +00:00
if ( c ) {
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
c = ast_channel_unref ( c ) ;
2009-04-23 20:36:35 +00:00
}
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
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
2010-07-16 18:14:05 +00:00
astman_append ( s , " Variable: %s \r \n Value: %s \r \n \r \n " , varname , S_OR ( varval , " " ) ) ;
2004-06-03 15:42:36 +00:00
return 0 ;
}
2006-06-22 15:34:20 +00:00
/*! \brief Manager "status" command to show channels */
2005-04-13 05:45:53 +00:00
/* Needs documentation... */
2007-01-05 22:43:18 +00:00
static int action_status ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2008-02-03 17:40:48 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
2008-05-05 19:33:14 +00:00
const char * cvariables = astman_get_header ( m , " Variables " ) ;
char * variables = ast_strdupa ( S_OR ( cvariables , " " ) ) ;
2002-09-12 18:32:42 +00:00
struct ast_channel * c ;
char bridge [ 256 ] ;
2005-07-15 23:00:47 +00:00
struct timeval now = ast_tvnow ( ) ;
2006-04-04 19:03:12 +00:00
long elapsed_seconds = 0 ;
2007-12-06 15:50:43 +00:00
int channels = 0 ;
2005-10-26 18:54:24 +00:00
int all = ast_strlen_zero ( name ) ; /* set if we want all channels */
2008-02-03 17:40:48 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] ;
2008-05-05 19:33:14 +00:00
AST_DECLARE_APP_ARGS ( vars ,
AST_APP_ARG ( name ) [ 100 ] ;
) ;
struct ast_str * str = ast_str_create ( 1000 ) ;
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_iterator * iter = NULL ;
2004-08-03 17:48:18 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-07-19 13:28:38 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-03 17:40:48 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 14:21:15 +00:00
2009-04-23 20:36:35 +00:00
if ( all ) {
2009-10-21 21:08:47 +00:00
if ( ! ( iter = ast_channel_iterator_all_new ( ) ) ) {
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
ast_free ( str ) ;
astman_send_error ( s , m , " Memory Allocation Failure " ) ;
return 1 ;
}
c = ast_channel_iterator_next ( iter ) ;
2009-04-23 20:36:35 +00:00
} else {
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2004-06-26 14:31:09 +00:00
astman_send_error ( s , m , " No such channel " ) ;
2009-02-06 10:25:09 +00:00
ast_free ( str ) ;
2004-06-26 14:31:09 +00:00
return 0 ;
}
}
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
2007-02-06 07:07:22 +00:00
astman_send_ack ( s , m , " Channel status will follow " ) ;
2007-12-06 15:50:43 +00:00
2008-05-05 19:33:14 +00:00
if ( ! ast_strlen_zero ( cvariables ) ) {
AST_STANDARD_APP_ARGS ( vars , variables ) ;
}
2005-06-06 02:29:18 +00:00
/* if we look by name, we break after the first iteration */
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
for ( ; c ; c = ast_channel_iterator_next ( iter ) ) {
ast_channel_lock ( c ) ;
2008-05-05 19:33:14 +00:00
if ( ! ast_strlen_zero ( cvariables ) ) {
int i ;
ast_str_reset ( str ) ;
for ( i = 0 ; i < vars . argc ; i + + ) {
char valbuf [ 512 ] , * ret = NULL ;
if ( vars . name [ i ] [ strlen ( vars . name [ i ] ) - 1 ] = = ' ) ' ) {
if ( ast_func_read ( c , vars . name [ i ] , valbuf , sizeof ( valbuf ) ) < 0 ) {
valbuf [ 0 ] = ' \0 ' ;
}
ret = valbuf ;
} else {
pbx_retrieve_variable ( c , vars . name [ i ] , & ret , valbuf , sizeof ( valbuf ) , NULL ) ;
}
ast_str_append ( & str , 0 , " Variable: %s=%s \r \n " , vars . name [ i ] , ret ) ;
}
}
2007-12-06 15:50:43 +00:00
channels + + ;
2009-04-23 20:36:35 +00:00
if ( c - > _bridge ) {
2012-01-24 20:12:09 +00:00
snprintf ( bridge , sizeof ( bridge ) , " BridgedChannel: %s \r \n BridgedUniqueid: %s \r \n " , ast_channel_name ( c - > _bridge ) , ast_channel_uniqueid ( c - > _bridge ) ) ;
2009-04-23 20:36:35 +00:00
} else {
2004-07-14 07:44:19 +00:00
bridge [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2012-02-20 23:43:27 +00:00
if ( ast_channel_pbx ( c ) ) {
if ( ast_channel_cdr ( c ) ) {
elapsed_seconds = now . tv_sec - ast_channel_cdr ( c ) - > start . tv_sec ;
2004-08-03 17:48:18 +00:00
}
2006-03-25 23:50:09 +00:00
astman_append ( s ,
2002-09-12 18:32:42 +00:00
" Event: Status \r \n "
2005-04-04 16:18:11 +00:00
" Privilege: Call \r \n "
2002-09-12 18:32:42 +00:00
" Channel: %s \r \n "
2006-04-11 23:23:16 +00:00
" CallerIDNum: %s \r \n "
2004-10-02 00:58:31 +00:00
" CallerIDName: %s \r \n "
2011-05-23 18:00:02 +00:00
" ConnectedLineNum: %s \r \n "
" ConnectedLineName: %s \r \n "
2007-12-06 15:50:43 +00:00
" Accountcode: %s \r \n "
" ChannelState: %d \r \n "
" ChannelStateDesc: %s \r \n "
2002-09-12 18:32:42 +00:00
" Context: %s \r \n "
" Extension: %s \r \n "
" Priority: %d \r \n "
2004-08-03 17:48:18 +00:00
" Seconds: %ld \r \n "
2002-09-12 18:32:42 +00:00
" %s "
2003-06-14 14:57:35 +00:00
" Uniqueid: %s \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2008-05-05 19:33:14 +00:00
" %s "
2003-06-14 14:57:35 +00:00
" \r \n " ,
2012-01-09 22:15:50 +00:00
ast_channel_name ( c ) ,
2012-02-29 16:52:47 +00:00
S_COR ( ast_channel_caller ( c ) - > id . number . valid , ast_channel_caller ( c ) - > id . number . str , " <unknown> " ) ,
S_COR ( ast_channel_caller ( c ) - > id . name . valid , ast_channel_caller ( c ) - > id . name . str , " <unknown> " ) ,
S_COR ( ast_channel_connected ( c ) - > id . number . valid , ast_channel_connected ( c ) - > id . number . str , " <unknown> " ) ,
S_COR ( ast_channel_connected ( c ) - > id . name . valid , ast_channel_connected ( c ) - > id . name . str , " <unknown> " ) ,
2012-01-24 20:12:09 +00:00
ast_channel_accountcode ( c ) ,
2012-02-20 23:43:27 +00:00
ast_channel_state ( c ) ,
ast_state2str ( ast_channel_state ( c ) ) , ast_channel_context ( c ) ,
ast_channel_exten ( c ) , ast_channel_priority ( c ) , ( long ) elapsed_seconds , bridge , ast_channel_uniqueid ( c ) , ast_str_buffer ( str ) , idText ) ;
2002-09-12 18:32:42 +00:00
} else {
2006-03-25 23:50:09 +00:00
astman_append ( s ,
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
" Event: Status \r \n "
" Privilege: Call \r \n "
" Channel: %s \r \n "
" CallerIDNum: %s \r \n "
" CallerIDName: %s \r \n "
2011-05-23 18:00:02 +00:00
" ConnectedLineNum: %s \r \n "
" ConnectedLineName: %s \r \n "
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
" Account: %s \r \n "
" State: %s \r \n "
" %s "
" Uniqueid: %s \r \n "
" %s "
" %s "
" \r \n " ,
2012-01-09 22:15:50 +00:00
ast_channel_name ( c ) ,
2012-02-29 16:52:47 +00:00
S_COR ( ast_channel_caller ( c ) - > id . number . valid , ast_channel_caller ( c ) - > id . number . str , " <unknown> " ) ,
S_COR ( ast_channel_caller ( c ) - > id . name . valid , ast_channel_caller ( c ) - > id . name . str , " <unknown> " ) ,
S_COR ( ast_channel_connected ( c ) - > id . number . valid , ast_channel_connected ( c ) - > id . number . str , " <unknown> " ) ,
S_COR ( ast_channel_connected ( c ) - > id . name . valid , ast_channel_connected ( c ) - > id . name . str , " <unknown> " ) ,
2012-01-24 20:12:09 +00:00
ast_channel_accountcode ( c ) ,
2012-02-20 23:43:27 +00:00
ast_state2str ( ast_channel_state ( c ) ) , bridge , ast_channel_uniqueid ( c ) ,
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
ast_str_buffer ( str ) , idText ) ;
2002-09-12 18:32:42 +00:00
}
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
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( c ) ;
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
c = ast_channel_unref ( c ) ;
2009-04-23 20:36:35 +00:00
if ( ! all ) {
2004-06-26 14:31:09 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
}
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
2009-10-21 21:08:47 +00:00
if ( iter ) {
ast_channel_iterator_destroy ( iter ) ;
}
2006-03-25 23:50:09 +00:00
astman_append ( s ,
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
" Event: StatusComplete \r \n "
" %s "
" Items: %d \r \n "
" \r \n " , idText , channels ) ;
2008-05-05 19:33:14 +00:00
ast_free ( str ) ;
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
2002-09-12 18:32:42 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_sendtext ( struct mansession * s , const struct message * m )
2006-10-31 10:42:22 +00:00
{
struct ast_channel * c = NULL ;
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
const char * textmsg = astman_get_header ( m , " Message " ) ;
2006-10-31 10:42:22 +00:00
int res = 0 ;
2006-10-31 15:22:28 +00:00
if ( ast_strlen_zero ( name ) ) {
2006-10-31 10:42:22 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
return 0 ;
}
2006-10-31 15:22:28 +00:00
if ( ast_strlen_zero ( textmsg ) ) {
2006-10-31 10:42:22 +00:00
astman_send_error ( s , m , " No Message specified " ) ;
return 0 ;
}
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2006-10-31 10:42:22 +00:00
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
res = ast_sendtext ( c , textmsg ) ;
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
c = ast_channel_unref ( c ) ;
2009-04-23 20:36:35 +00:00
2011-02-03 00:29:46 +00:00
if ( res > = 0 ) {
2006-10-31 10:42:22 +00:00
astman_send_ack ( s , m , " Success " ) ;
2009-04-23 20:36:35 +00:00
} else {
2006-10-31 10:42:22 +00:00
astman_send_error ( s , m , " Failure " ) ;
2009-04-23 20:36:35 +00:00
}
2006-10-31 10:42:22 +00:00
return res ;
}
2005-10-26 13:03:17 +00:00
/*! \brief action_redirect: The redirect manager command */
2007-01-05 22:43:18 +00:00
static int action_redirect ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
const char * name2 = astman_get_header ( m , " ExtraChannel " ) ;
const char * exten = astman_get_header ( m , " Exten " ) ;
2009-12-16 00:31:53 +00:00
const char * exten2 = astman_get_header ( m , " ExtraExten " ) ;
2007-01-05 22:43:18 +00:00
const char * context = astman_get_header ( m , " Context " ) ;
2009-12-16 00:31:53 +00:00
const char * context2 = astman_get_header ( m , " ExtraContext " ) ;
2007-01-05 22:43:18 +00:00
const char * priority = astman_get_header ( m , " Priority " ) ;
2009-12-16 00:31:53 +00:00
const char * priority2 = astman_get_header ( m , " ExtraPriority " ) ;
2007-10-01 21:31:16 +00:00
struct ast_channel * chan , * chan2 = NULL ;
2009-12-16 00:31:53 +00:00
int pi , pi2 = 0 ;
2002-09-12 18:32:42 +00:00
int res ;
2005-04-13 05:45:53 +00:00
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Channel not specified " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
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
2009-08-10 19:20:57 +00:00
if ( ! ast_strlen_zero ( priority ) & & ( sscanf ( priority , " %30d " , & pi ) ! = 1 ) ) {
2005-12-27 19:13:13 +00:00
if ( ( pi = ast_findlabel_extension ( NULL , context , exten , priority , NULL ) ) < 1 ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Invalid priority " ) ;
2005-12-27 19:13:13 +00:00
return 0 ;
}
2002-09-12 18:32:42 +00:00
}
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
2009-12-16 00:31:53 +00:00
if ( ! ast_strlen_zero ( priority2 ) & & ( sscanf ( priority2 , " %30d " , & pi2 ) ! = 1 ) ) {
if ( ( pi2 = ast_findlabel_extension ( NULL , context2 , exten2 , priority2 , NULL ) ) < 1 ) {
astman_send_error ( s , m , " Invalid ExtraPriority " ) ;
return 0 ;
}
}
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 ( name ) ) ) {
2008-03-04 23:24:56 +00:00
char buf [ 256 ] ;
2005-04-13 05:45:53 +00:00
snprintf ( buf , sizeof ( buf ) , " Channel does not exist: %s " , name ) ;
astman_send_error ( s , m , buf ) ;
2004-05-24 15:28:36 +00:00
return 0 ;
}
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 ( ast_check_hangup_locked ( chan ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Redirect failed, channel not up. " ) ;
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 ) ;
2007-03-07 00:26:01 +00:00
return 0 ;
}
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 ( ! ast_strlen_zero ( name2 ) ) {
chan2 = ast_channel_get_by_name ( name2 ) ;
}
if ( chan2 & & ast_check_hangup_locked ( chan2 ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Redirect failed, extra channel not up. " ) ;
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 ) ;
chan2 = ast_channel_unref ( chan2 ) ;
2007-03-07 00:26:01 +00:00
return 0 ;
}
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
2012-02-20 23:43:27 +00:00
if ( ast_channel_pbx ( chan ) ) {
Merged revisions 172030 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r172030 | murf | 2009-01-28 11:51:16 -0700 (Wed, 28 Jan 2009) | 46 lines
This patch fixes h-exten running misbehavior in manager-redirected
situations.
What it does:
1. A new Flag value is defined in include/asterisk/channel.h,
AST_FLAG_BRIDGE_HANGUP_DONT, which used as a messenge to the
bridge hangup exten code not to run the h-exten there (nor
publish the bridge cdr there). It will done at the pbx-loop
level instead.
2. In the manager Redirect code, I set this flag on the channel
if the channel has a non-null pbx pointer. I did the same for the
second (chan2) channel, which gets run if name2 is set...
and the first succeeds.
3. I restored the ending of the cdr for the pbx loop h-exten
running code. Don't know why it was removed in the first place.
4. The first attempt at the fix for this bug was to place code
directly in the async_goto routine, which was called from a
large number of places, and could affect a large number of
cases, so I tested that fix against a fair number of transfer
scenarios, both with and without the patch. In the process,
I saw that putting the fix in async_goto seemed not to affect
any of the blind or attended scenarios, but still, I was
was highly concerned that some other scenarios I had not tested
might be negatively impacted, so I refined the patch to
its current scope, and jmls tested both. In the process, tho,
I saw that blind xfers in one situation, when the one-touch
blind-xfer feature is used by the peer, we got strange
h-exten behavior. So, I inserted code to swap CDRs and
to set the HANGUP_DONT field, to get uniform behavior.
5. I added code to the bridge to obey the HANGUP_DONT flag,
skipping both publishing the bridge CDR, and running
the h-exten; they will be done at the pbx-loop (higher)
level instead.
6. I removed all the debug logs from the patch before committing.
7. I moved the AUTOLOOP set/reset in the h-exten code in res_features
so it's only done if the h-exten is going to be run. A very
minor performance improvement, but technically correct.
(closes issue #14241)
Reported by: jmls
Patches:
14241_redirect_no_bridgeCDR_or_h_exten_via_transfer uploaded by murf (license 17)
Tested by: murf, jmls
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@172063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-01-28 20:31:06 +00:00
ast_channel_lock ( chan ) ;
ast_set_flag ( chan , AST_FLAG_BRIDGE_HANGUP_DONT ) ; /* don't let the after-bridge code run the h-exten */
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
2004-05-22 04:11:22 +00:00
res = ast_async_goto ( chan , context , exten , pi ) ;
2002-09-12 18:32:42 +00:00
if ( ! res ) {
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( name2 ) ) {
Merged revisions 172030 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r172030 | murf | 2009-01-28 11:51:16 -0700 (Wed, 28 Jan 2009) | 46 lines
This patch fixes h-exten running misbehavior in manager-redirected
situations.
What it does:
1. A new Flag value is defined in include/asterisk/channel.h,
AST_FLAG_BRIDGE_HANGUP_DONT, which used as a messenge to the
bridge hangup exten code not to run the h-exten there (nor
publish the bridge cdr there). It will done at the pbx-loop
level instead.
2. In the manager Redirect code, I set this flag on the channel
if the channel has a non-null pbx pointer. I did the same for the
second (chan2) channel, which gets run if name2 is set...
and the first succeeds.
3. I restored the ending of the cdr for the pbx loop h-exten
running code. Don't know why it was removed in the first place.
4. The first attempt at the fix for this bug was to place code
directly in the async_goto routine, which was called from a
large number of places, and could affect a large number of
cases, so I tested that fix against a fair number of transfer
scenarios, both with and without the patch. In the process,
I saw that putting the fix in async_goto seemed not to affect
any of the blind or attended scenarios, but still, I was
was highly concerned that some other scenarios I had not tested
might be negatively impacted, so I refined the patch to
its current scope, and jmls tested both. In the process, tho,
I saw that blind xfers in one situation, when the one-touch
blind-xfer feature is used by the peer, we got strange
h-exten behavior. So, I inserted code to swap CDRs and
to set the HANGUP_DONT field, to get uniform behavior.
5. I added code to the bridge to obey the HANGUP_DONT flag,
skipping both publishing the bridge CDR, and running
the h-exten; they will be done at the pbx-loop (higher)
level instead.
6. I removed all the debug logs from the patch before committing.
7. I moved the AUTOLOOP set/reset in the h-exten code in res_features
so it's only done if the h-exten is going to be run. A very
minor performance improvement, but technically correct.
(closes issue #14241)
Reported by: jmls
Patches:
14241_redirect_no_bridgeCDR_or_h_exten_via_transfer uploaded by murf (license 17)
Tested by: murf, jmls
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@172063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-01-28 20:31:06 +00:00
if ( chan2 ) {
2012-02-20 23:43:27 +00:00
if ( ast_channel_pbx ( chan2 ) ) {
Merged revisions 172030 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r172030 | murf | 2009-01-28 11:51:16 -0700 (Wed, 28 Jan 2009) | 46 lines
This patch fixes h-exten running misbehavior in manager-redirected
situations.
What it does:
1. A new Flag value is defined in include/asterisk/channel.h,
AST_FLAG_BRIDGE_HANGUP_DONT, which used as a messenge to the
bridge hangup exten code not to run the h-exten there (nor
publish the bridge cdr there). It will done at the pbx-loop
level instead.
2. In the manager Redirect code, I set this flag on the channel
if the channel has a non-null pbx pointer. I did the same for the
second (chan2) channel, which gets run if name2 is set...
and the first succeeds.
3. I restored the ending of the cdr for the pbx loop h-exten
running code. Don't know why it was removed in the first place.
4. The first attempt at the fix for this bug was to place code
directly in the async_goto routine, which was called from a
large number of places, and could affect a large number of
cases, so I tested that fix against a fair number of transfer
scenarios, both with and without the patch. In the process,
I saw that putting the fix in async_goto seemed not to affect
any of the blind or attended scenarios, but still, I was
was highly concerned that some other scenarios I had not tested
might be negatively impacted, so I refined the patch to
its current scope, and jmls tested both. In the process, tho,
I saw that blind xfers in one situation, when the one-touch
blind-xfer feature is used by the peer, we got strange
h-exten behavior. So, I inserted code to swap CDRs and
to set the HANGUP_DONT field, to get uniform behavior.
5. I added code to the bridge to obey the HANGUP_DONT flag,
skipping both publishing the bridge CDR, and running
the h-exten; they will be done at the pbx-loop (higher)
level instead.
6. I removed all the debug logs from the patch before committing.
7. I moved the AUTOLOOP set/reset in the h-exten code in res_features
so it's only done if the h-exten is going to be run. A very
minor performance improvement, but technically correct.
(closes issue #14241)
Reported by: jmls
Patches:
14241_redirect_no_bridgeCDR_or_h_exten_via_transfer uploaded by murf (license 17)
Tested by: murf, jmls
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@172063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-01-28 20:31:06 +00:00
ast_channel_lock ( chan2 ) ;
ast_set_flag ( chan2 , AST_FLAG_BRIDGE_HANGUP_DONT ) ; /* don't let the after-bridge code run the h-exten */
ast_channel_unlock ( chan2 ) ;
}
2012-02-10 18:08:19 +00:00
if ( ! ast_strlen_zero ( context2 ) ) {
2009-12-16 00:31:53 +00:00
res = ast_async_goto ( chan2 , context2 , exten2 , pi2 ) ;
} else {
res = ast_async_goto ( chan2 , context , exten , pi ) ;
}
Merged revisions 172030 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r172030 | murf | 2009-01-28 11:51:16 -0700 (Wed, 28 Jan 2009) | 46 lines
This patch fixes h-exten running misbehavior in manager-redirected
situations.
What it does:
1. A new Flag value is defined in include/asterisk/channel.h,
AST_FLAG_BRIDGE_HANGUP_DONT, which used as a messenge to the
bridge hangup exten code not to run the h-exten there (nor
publish the bridge cdr there). It will done at the pbx-loop
level instead.
2. In the manager Redirect code, I set this flag on the channel
if the channel has a non-null pbx pointer. I did the same for the
second (chan2) channel, which gets run if name2 is set...
and the first succeeds.
3. I restored the ending of the cdr for the pbx loop h-exten
running code. Don't know why it was removed in the first place.
4. The first attempt at the fix for this bug was to place code
directly in the async_goto routine, which was called from a
large number of places, and could affect a large number of
cases, so I tested that fix against a fair number of transfer
scenarios, both with and without the patch. In the process,
I saw that putting the fix in async_goto seemed not to affect
any of the blind or attended scenarios, but still, I was
was highly concerned that some other scenarios I had not tested
might be negatively impacted, so I refined the patch to
its current scope, and jmls tested both. In the process, tho,
I saw that blind xfers in one situation, when the one-touch
blind-xfer feature is used by the peer, we got strange
h-exten behavior. So, I inserted code to swap CDRs and
to set the HANGUP_DONT field, to get uniform behavior.
5. I added code to the bridge to obey the HANGUP_DONT flag,
skipping both publishing the bridge CDR, and running
the h-exten; they will be done at the pbx-loop (higher)
level instead.
6. I removed all the debug logs from the patch before committing.
7. I moved the AUTOLOOP set/reset in the h-exten code in res_features
so it's only done if the h-exten is going to be run. A very
minor performance improvement, but technically correct.
(closes issue #14241)
Reported by: jmls
Patches:
14241_redirect_no_bridgeCDR_or_h_exten_via_transfer uploaded by murf (license 17)
Tested by: murf, jmls
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@172063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-01-28 20:31:06 +00:00
} else {
2004-05-22 04:11:22 +00:00
res = - 1 ;
Merged revisions 172030 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r172030 | murf | 2009-01-28 11:51:16 -0700 (Wed, 28 Jan 2009) | 46 lines
This patch fixes h-exten running misbehavior in manager-redirected
situations.
What it does:
1. A new Flag value is defined in include/asterisk/channel.h,
AST_FLAG_BRIDGE_HANGUP_DONT, which used as a messenge to the
bridge hangup exten code not to run the h-exten there (nor
publish the bridge cdr there). It will done at the pbx-loop
level instead.
2. In the manager Redirect code, I set this flag on the channel
if the channel has a non-null pbx pointer. I did the same for the
second (chan2) channel, which gets run if name2 is set...
and the first succeeds.
3. I restored the ending of the cdr for the pbx loop h-exten
running code. Don't know why it was removed in the first place.
4. The first attempt at the fix for this bug was to place code
directly in the async_goto routine, which was called from a
large number of places, and could affect a large number of
cases, so I tested that fix against a fair number of transfer
scenarios, both with and without the patch. In the process,
I saw that putting the fix in async_goto seemed not to affect
any of the blind or attended scenarios, but still, I was
was highly concerned that some other scenarios I had not tested
might be negatively impacted, so I refined the patch to
its current scope, and jmls tested both. In the process, tho,
I saw that blind xfers in one situation, when the one-touch
blind-xfer feature is used by the peer, we got strange
h-exten behavior. So, I inserted code to swap CDRs and
to set the HANGUP_DONT field, to get uniform behavior.
5. I added code to the bridge to obey the HANGUP_DONT flag,
skipping both publishing the bridge CDR, and running
the h-exten; they will be done at the pbx-loop (higher)
level instead.
6. I removed all the debug logs from the patch before committing.
7. I moved the AUTOLOOP set/reset in the h-exten code in res_features
so it's only done if the h-exten is going to be run. A very
minor performance improvement, but technically correct.
(closes issue #14241)
Reported by: jmls
Patches:
14241_redirect_no_bridgeCDR_or_h_exten_via_transfer uploaded by murf (license 17)
Tested by: murf, jmls
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@172063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-01-28 20:31:06 +00:00
}
2009-04-23 20:36:35 +00:00
if ( ! res ) {
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Dual Redirect successful " ) ;
2009-04-23 20:36:35 +00:00
} else {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Secondary redirect failed " ) ;
2009-04-23 20:36:35 +00:00
}
} else {
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Redirect successful " ) ;
2009-04-23 20:36:35 +00:00
}
} else {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Redirect failed " ) ;
2009-04-23 20:36:35 +00:00
}
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
2012-02-10 18:08:19 +00:00
chan = ast_channel_unref ( chan ) ;
2009-04-23 20:36:35 +00:00
if ( chan2 ) {
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 ) ;
2009-04-23 20:36:35 +00:00
}
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
2002-09-12 18:32:42 +00:00
return 0 ;
}
2008-03-05 22:33:05 +00:00
static int action_atxfer ( struct mansession * s , const struct message * m )
{
const char * name = astman_get_header ( m , " Channel " ) ;
const char * exten = astman_get_header ( m , " Exten " ) ;
const char * context = astman_get_header ( m , " Context " ) ;
struct ast_channel * chan = NULL ;
struct ast_call_feature * atxfer_feature = NULL ;
char * feature_code = NULL ;
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( name ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
2008-03-05 22:33:05 +00:00
return 0 ;
}
if ( ast_strlen_zero ( exten ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " No extension specified " ) ;
2008-03-05 22:33:05 +00:00
return 0 ;
}
if ( ! ( atxfer_feature = ast_find_call_feature ( " atxfer " ) ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " No attended transfer feature found " ) ;
2008-03-05 22:33:05 +00:00
return 0 ;
}
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 ( name ) ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Channel specified does not exist " ) ;
2008-03-05 22:33:05 +00:00
return 0 ;
}
2008-10-09 23:54:59 +00:00
if ( ! ast_strlen_zero ( context ) ) {
pbx_builtin_setvar_helper ( chan , " TRANSFER_CONTEXT " , context ) ;
}
2008-03-05 22:33:05 +00:00
for ( feature_code = atxfer_feature - > exten ; feature_code & & * feature_code ; + + feature_code ) {
2009-11-04 14:05:12 +00:00
struct ast_frame f = { AST_FRAME_DTMF , . subclass . integer = * feature_code } ;
2008-03-05 22:33:05 +00:00
ast_queue_frame ( chan , & f ) ;
}
for ( feature_code = ( char * ) exten ; feature_code & & * feature_code ; + + feature_code ) {
2009-11-04 14:05:12 +00:00
struct ast_frame f = { AST_FRAME_DTMF , . subclass . integer = * feature_code } ;
2008-03-05 22:33:05 +00:00
ast_queue_frame ( chan , & f ) ;
}
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 ) ;
2008-07-15 18:25:34 +00:00
astman_send_ack ( s , m , " Atxfer successfully queued " ) ;
2008-03-05 22:33:05 +00:00
return 0 ;
}
2008-06-02 14:41:55 +00:00
static int check_blacklist ( const char * cmd )
{
char * cmd_copy , * cur_cmd ;
char * cmd_words [ MAX_BLACKLIST_CMD_LEN ] = { NULL , } ;
int i ;
cmd_copy = ast_strdupa ( cmd ) ;
for ( i = 0 ; i < MAX_BLACKLIST_CMD_LEN & & ( cur_cmd = strsep ( & cmd_copy , " " ) ) ; i + + ) {
cur_cmd = ast_strip ( cur_cmd ) ;
if ( ast_strlen_zero ( cur_cmd ) ) {
i - - ;
continue ;
}
cmd_words [ i ] = cur_cmd ;
}
for ( i = 0 ; i < ARRAY_LEN ( command_blacklist ) ; i + + ) {
int j , match = 1 ;
for ( j = 0 ; command_blacklist [ i ] . words [ j ] ; j + + ) {
if ( ast_strlen_zero ( cmd_words [ j ] ) | | strcasecmp ( cmd_words [ j ] , command_blacklist [ i ] . words [ j ] ) ) {
match = 0 ;
break ;
}
}
if ( match ) {
return 1 ;
}
}
return 0 ;
}
2006-10-18 16:52:13 +00:00
/*! \brief Manager command "command" - execute CLI command */
2007-01-05 22:43:18 +00:00
static int action_command ( struct mansession * s , const struct message * m )
2003-01-28 22:33:41 +00:00
{
2007-01-05 22:43:18 +00:00
const char * cmd = astman_get_header ( m , " Command " ) ;
const char * id = astman_get_header ( m , " ActionID " ) ;
2007-05-10 22:25:54 +00:00
char * buf , * final_buf ;
2006-12-06 18:45:19 +00:00
char template [ ] = " /tmp/ast-ami-XXXXXX " ; /* template for temporary file */
2009-08-18 16:38:36 +00:00
int fd ;
2006-12-06 18:45:19 +00:00
off_t l ;
2008-06-02 14:41:55 +00:00
if ( ast_strlen_zero ( cmd ) ) {
astman_send_error ( s , m , " No command provided " ) ;
return 0 ;
}
if ( check_blacklist ( cmd ) ) {
astman_send_error ( s , m , " Command blacklisted " ) ;
return 0 ;
2007-05-24 15:30:06 +00:00
}
2009-08-18 16:38:36 +00:00
fd = mkstemp ( template ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Follows \r \n Privilege: Command \r \n " ) ;
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-03-25 23:50:09 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
}
2003-09-08 16:44:36 +00:00
/* FIXME: Wedge a ActionID response in here, waiting for later changes */
2006-12-06 18:45:19 +00:00
ast_cli_command ( fd , cmd ) ; /* XXX need to change this to use a FILE * */
l = lseek ( fd , 0 , SEEK_END ) ; /* how many chars available */
2007-06-29 04:56:08 +00:00
/* This has a potential to overflow the stack. Hence, use the heap. */
buf = ast_calloc ( 1 , l + 1 ) ;
final_buf = ast_calloc ( 1 , l + 1 ) ;
if ( buf ) {
lseek ( fd , 0 , SEEK_SET ) ;
2008-11-02 18:52:13 +00:00
if ( read ( fd , buf , l ) < 0 ) {
ast_log ( LOG_WARNING , " read() failed: %s \n " , strerror ( errno ) ) ;
}
2007-06-29 04:56:08 +00:00
buf [ l ] = ' \0 ' ;
if ( final_buf ) {
term_strip ( final_buf , buf , l ) ;
final_buf [ l ] = ' \0 ' ;
}
2008-03-18 15:13:07 +00:00
astman_append ( s , " %s " , S_OR ( final_buf , buf ) ) ;
2007-06-29 04:56:08 +00:00
ast_free ( buf ) ;
}
2006-12-06 18:45:19 +00:00
close ( fd ) ;
unlink ( template ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " --END COMMAND-- \r \n \r \n " ) ;
2009-04-23 20:36:35 +00:00
if ( final_buf ) {
2007-06-29 04:56:08 +00:00
ast_free ( final_buf ) ;
2009-04-23 20:36:35 +00:00
}
2003-01-28 22:33:41 +00:00
return 0 ;
}
2008-05-14 12:32:57 +00:00
/*! \brief helper function for originate */
2006-10-18 17:45:50 +00:00
struct fast_originate_helper {
int timeout ;
2011-02-03 16:22:10 +00:00
struct ast_format_cap * cap ; /*!< Codecs used for a call */
2011-09-13 18:49:26 +00:00
AST_DECLARE_STRING_FIELDS (
2012-01-31 17:26:09 +00:00
AST_STRING_FIELD ( tech ) ;
/*! data can contain a channel name, extension number, username, password, etc. */
AST_STRING_FIELD ( data ) ;
2011-09-13 18:49:26 +00:00
AST_STRING_FIELD ( app ) ;
AST_STRING_FIELD ( appdata ) ;
AST_STRING_FIELD ( cid_name ) ;
AST_STRING_FIELD ( cid_num ) ;
AST_STRING_FIELD ( context ) ;
AST_STRING_FIELD ( exten ) ;
AST_STRING_FIELD ( idtext ) ;
AST_STRING_FIELD ( account ) ;
) ;
2006-10-18 17:45:50 +00:00
int priority ;
struct ast_variable * vars ;
} ;
2012-01-31 17:26:09 +00:00
/*!
* \ internal
*
* \ param doomed Struct to destroy .
*
* \ return Nothing
*/
static void destroy_fast_originate_helper ( struct fast_originate_helper * doomed )
{
ast_format_cap_destroy ( doomed - > cap ) ;
ast_variables_destroy ( doomed - > vars ) ;
ast_string_field_free_memory ( doomed ) ;
ast_free ( doomed ) ;
}
2004-05-01 23:52:27 +00:00
static void * fast_originate ( void * data )
{
struct fast_originate_helper * in = data ;
int res ;
int reason = 0 ;
2009-11-13 20:42:03 +00:00
struct ast_channel * chan = NULL , * chans [ 1 ] ;
Merged revisions 47986,47995,47997,48001,48003-48004,48008-48014,48016,48018-48019 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
................
r47986 | oej | 2006-11-24 07:00:19 -0700 (Fri, 24 Nov 2006) | 6 lines
Doxygen update
- Document cause codes
- Document a bit more on channel variables - global, predefined and local
- Fix some doxygen in channel.h. Adding one comment for two definitions does not
work. They won't be copied to each.
................
r47995 | murf | 2006-11-24 10:40:49 -0700 (Fri, 24 Nov 2006) | 1 line
This fix inspired by a patch supplied in bug 8189, which points out problems with the PLC code
................
r47997 | murf | 2006-11-24 11:17:25 -0700 (Fri, 24 Nov 2006) | 1 line
removed the svnmerge-integrated property from trunk; it's confusing svnmerge in newly created branches
................
r48001 | rizzo | 2006-11-25 02:02:42 -0700 (Sat, 25 Nov 2006) | 5 lines
set pointers to NULL after freeing memory to avoid multiple free()
probably 1.4/1.2 issue as well if someone can look into that.
................
r48003 | oej | 2006-11-25 02:45:57 -0700 (Sat, 25 Nov 2006) | 9 lines
- Adding comment on suspicious memory allocation. Seems like it's never freed, but I don't
have a clear understanding of the frame allocation/deallocation, so I just mark this
for investigation. (Reported by Ed Guy). We're trying to see if a free() hurts...
- Doxygen comments on p2p rtp bridge stuff. I am a bit worried about shortcutting
rtcp this way, but will need feedback from rtcp gurus. This should work for
video calls too, and possibly UDPTL.
................
r48004 | oej | 2006-11-25 02:48:30 -0700 (Sat, 25 Nov 2006) | 2 lines
Changing ERROR to lesser level. Imported from 1.2/1.4
................
r48008 | rizzo | 2006-11-25 10:37:04 -0700 (Sat, 25 Nov 2006) | 7 lines
generalize a bit the functions used to create an tcp socket
and then run a service on it.
The code in manager.c does essentially the same things,
so we will be able to reuse the code in here (probably
moving it to netsock.c or another appropriate library file).
................
r48009 | mattf | 2006-11-25 13:30:04 -0700 (Sat, 25 Nov 2006) | 1 line
Updates to show linkset command
................
r48010 | mattf | 2006-11-25 13:54:38 -0700 (Sat, 25 Nov 2006) | 2 lines
Add ss7 show linkset command
................
r48011 | mattf | 2006-11-25 14:32:33 -0700 (Sat, 25 Nov 2006) | 1 line
Make sure we don't send a group reset on a group larger than 32 CICs
................
r48012 | mattf | 2006-11-25 14:35:23 -0700 (Sat, 25 Nov 2006) | 1 line
bug fix
................
r48013 | mattf | 2006-11-25 14:46:58 -0700 (Sat, 25 Nov 2006) | 1 line
Make compiler happier
................
r48014 | mattf | 2006-11-25 14:50:42 -0700 (Sat, 25 Nov 2006) | 1 line
Little fix so we use the right message
................
r48016 | murf | 2006-11-25 17:15:42 -0700 (Sat, 25 Nov 2006) | 9 lines
Merged revisions 48015 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r48015 | murf | 2006-11-25 17:01:34 -0700 (Sat, 25 Nov 2006) | 1 line
A little bit of func_cdr documentation upgrade-- no bug# involved, although 8221 may have inspired it.
........
................
r48018 | murf | 2006-11-25 17:31:13 -0700 (Sat, 25 Nov 2006) | 9 lines
Merged revisions 48017 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r48017 | murf | 2006-11-25 17:26:16 -0700 (Sat, 25 Nov 2006) | 1 line
might as well also document the raw values of the flag vars
........
................
r48019 | russell | 2006-11-25 23:55:33 -0700 (Sat, 25 Nov 2006) | 6 lines
- Add some comments on thread storage with a brief explanation of what it is
as well as what the motivation is for using it.
- Add a comment by the declaration of ast_inet_ntoa() noting that this function
is not reentrant, and the result of a previous call to the function is no
longer valid after calling it again.
................
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48350 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-12-07 16:03:56 +00:00
char requested_channel [ AST_CHANNEL_NAME ] ;
2005-02-02 02:54:15 +00:00
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( in - > app ) ) {
2012-02-01 19:53:38 +00:00
res = ast_pbx_outgoing_app ( in - > tech , in - > cap , in - > data ,
2012-01-31 17:26:09 +00:00
in - > timeout , in - > app , in - > appdata , & reason , 1 ,
2006-10-18 21:41:09 +00:00
S_OR ( in - > cid_num , NULL ) ,
2006-03-26 16:08:42 +00:00
S_OR ( in - > cid_name , NULL ) ,
2006-02-11 18:31:59 +00:00
in - > vars , in - > account , & chan ) ;
2004-05-01 23:52:27 +00:00
} else {
2012-02-01 19:53:38 +00:00
res = ast_pbx_outgoing_exten ( in - > tech , in - > cap , in - > data ,
2012-01-31 17:26:09 +00:00
in - > timeout , in - > context , in - > exten , in - > priority , & reason , 1 ,
2006-10-18 21:41:09 +00:00
S_OR ( in - > cid_num , NULL ) ,
2006-03-26 16:08:42 +00:00
S_OR ( in - > cid_name , NULL ) ,
2006-02-11 18:31:59 +00:00
in - > vars , in - > account , & chan ) ;
2006-10-18 21:41:09 +00:00
}
2012-01-31 17:26:09 +00:00
/* Any vars memory was passed to the ast_pbx_outgoing_xxx() calls. */
in - > vars = NULL ;
2006-10-18 21:41:09 +00:00
2009-04-23 20:36:35 +00:00
if ( ! chan ) {
snprintf ( requested_channel , AST_CHANNEL_NAME , " %s/%s " , in - > tech , in - > data ) ;
}
2006-01-03 11:31:56 +00:00
/* Tell the manager what happened with the channel */
2009-11-13 20:42:03 +00:00
chans [ 0 ] = chan ;
ast_manager_event_multichan ( EVENT_FLAG_CALL , " OriginateResponse " , chan ? 1 : 0 , chans ,
2012-01-31 17:26:09 +00:00
" %s "
Merged revisions 47986,47995,47997,48001,48003-48004,48008-48014,48016,48018-48019 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
................
r47986 | oej | 2006-11-24 07:00:19 -0700 (Fri, 24 Nov 2006) | 6 lines
Doxygen update
- Document cause codes
- Document a bit more on channel variables - global, predefined and local
- Fix some doxygen in channel.h. Adding one comment for two definitions does not
work. They won't be copied to each.
................
r47995 | murf | 2006-11-24 10:40:49 -0700 (Fri, 24 Nov 2006) | 1 line
This fix inspired by a patch supplied in bug 8189, which points out problems with the PLC code
................
r47997 | murf | 2006-11-24 11:17:25 -0700 (Fri, 24 Nov 2006) | 1 line
removed the svnmerge-integrated property from trunk; it's confusing svnmerge in newly created branches
................
r48001 | rizzo | 2006-11-25 02:02:42 -0700 (Sat, 25 Nov 2006) | 5 lines
set pointers to NULL after freeing memory to avoid multiple free()
probably 1.4/1.2 issue as well if someone can look into that.
................
r48003 | oej | 2006-11-25 02:45:57 -0700 (Sat, 25 Nov 2006) | 9 lines
- Adding comment on suspicious memory allocation. Seems like it's never freed, but I don't
have a clear understanding of the frame allocation/deallocation, so I just mark this
for investigation. (Reported by Ed Guy). We're trying to see if a free() hurts...
- Doxygen comments on p2p rtp bridge stuff. I am a bit worried about shortcutting
rtcp this way, but will need feedback from rtcp gurus. This should work for
video calls too, and possibly UDPTL.
................
r48004 | oej | 2006-11-25 02:48:30 -0700 (Sat, 25 Nov 2006) | 2 lines
Changing ERROR to lesser level. Imported from 1.2/1.4
................
r48008 | rizzo | 2006-11-25 10:37:04 -0700 (Sat, 25 Nov 2006) | 7 lines
generalize a bit the functions used to create an tcp socket
and then run a service on it.
The code in manager.c does essentially the same things,
so we will be able to reuse the code in here (probably
moving it to netsock.c or another appropriate library file).
................
r48009 | mattf | 2006-11-25 13:30:04 -0700 (Sat, 25 Nov 2006) | 1 line
Updates to show linkset command
................
r48010 | mattf | 2006-11-25 13:54:38 -0700 (Sat, 25 Nov 2006) | 2 lines
Add ss7 show linkset command
................
r48011 | mattf | 2006-11-25 14:32:33 -0700 (Sat, 25 Nov 2006) | 1 line
Make sure we don't send a group reset on a group larger than 32 CICs
................
r48012 | mattf | 2006-11-25 14:35:23 -0700 (Sat, 25 Nov 2006) | 1 line
bug fix
................
r48013 | mattf | 2006-11-25 14:46:58 -0700 (Sat, 25 Nov 2006) | 1 line
Make compiler happier
................
r48014 | mattf | 2006-11-25 14:50:42 -0700 (Sat, 25 Nov 2006) | 1 line
Little fix so we use the right message
................
r48016 | murf | 2006-11-25 17:15:42 -0700 (Sat, 25 Nov 2006) | 9 lines
Merged revisions 48015 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r48015 | murf | 2006-11-25 17:01:34 -0700 (Sat, 25 Nov 2006) | 1 line
A little bit of func_cdr documentation upgrade-- no bug# involved, although 8221 may have inspired it.
........
................
r48018 | murf | 2006-11-25 17:31:13 -0700 (Sat, 25 Nov 2006) | 9 lines
Merged revisions 48017 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r48017 | murf | 2006-11-25 17:26:16 -0700 (Sat, 25 Nov 2006) | 1 line
might as well also document the raw values of the flag vars
........
................
r48019 | russell | 2006-11-25 23:55:33 -0700 (Sat, 25 Nov 2006) | 6 lines
- Add some comments on thread storage with a brief explanation of what it is
as well as what the motivation is for using it.
- Add a comment by the declaration of ast_inet_ntoa() noting that this function
is not reentrant, and the result of a previous call to the function is no
longer valid after calling it again.
................
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48350 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-12-07 16:03:56 +00:00
" Response: %s \r \n "
" Channel: %s \r \n "
2006-01-03 11:31:56 +00:00
" Context: %s \r \n "
" Exten: %s \r \n "
" Reason: %d \r \n "
" Uniqueid: %s \r \n "
2006-04-11 23:23:16 +00:00
" CallerIDNum: %s \r \n "
2006-01-03 11:31:56 +00:00
" CallerIDName: %s \r \n " ,
2012-01-31 17:26:09 +00:00
in - > idtext , res ? " Failure " : " Success " ,
2012-01-09 22:15:50 +00:00
chan ? ast_channel_name ( chan ) : requested_channel , in - > context , in - > exten , reason ,
2012-01-24 20:12:09 +00:00
chan ? ast_channel_uniqueid ( chan ) : " <null> " ,
2006-04-21 10:31:23 +00:00
S_OR ( in - > cid_num , " <unknown> " ) ,
S_OR ( in - > cid_name , " <unknown> " )
2006-01-03 11:31:56 +00:00
) ;
2004-09-14 22:15:50 +00:00
2005-02-02 02:54:15 +00:00
/* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2009-04-23 20:36:35 +00:00
if ( chan ) {
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( chan ) ;
2009-04-23 20:36:35 +00:00
}
2012-01-31 17:26:09 +00:00
destroy_fast_originate_helper ( in ) ;
2004-05-01 23:52:27 +00:00
return NULL ;
}
Generic Advice of Charge.
Asterisk Generic AOC Representation
- Generic AOC encode/decode routines.
(Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame)
- AST_CONTROL_AOC frame type to represent generic encoded AOC data
- Manager events for AOC-S, AOC-D, and AOC-E messages
Asterisk App Support
- app_dial AOC-S pass-through support on call setup
- app_queue AOC-S pass-through support on call setup
AOC Unit Tests
- AOC Unit Tests for encode/decode routines
- AOC Unit Test for manager event representation.
SIP AOC Support
- Pass-through of generic AOC-D and AOC-E messages to snom phones via the
snom AOC specification.
- Creation of chan_sip page3 flags for the addition of the new
'snom_aoc_enabled' sip.conf option.
IAX AOC Support
- Natively supports AOC pass-through through the use of the new
AST_CONTROL_AOC frame type
DAHDI AOC Support
- ETSI PRI full AOC Pass-through support
- 'aoc_enable' chan_dahdi.conf option for independently enabling
pass-through of AOC-S, AOC-D, AOC-E.
- 'aoce_delayhangup' option for retrieving AOC-E on disconnect.
- DAHDI A() dial string option for requesting AOC services.
example usage:
;requests AOC-S, AOC-D, and AOC-E on call setup
exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e))
Review: https://reviewboard.asterisk.org/r/552/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-06-02 18:10:15 +00:00
static int aocmessage_get_unit_entry ( const struct message * m , struct ast_aoc_unit_entry * entry , unsigned int entry_num )
{
const char * unitamount ;
const char * unittype ;
struct ast_str * str = ast_str_alloca ( 32 ) ;
memset ( entry , 0 , sizeof ( * entry ) ) ;
ast_str_set ( & str , 0 , " UnitAmount(%u) " , entry_num ) ;
unitamount = astman_get_header ( m , ast_str_buffer ( str ) ) ;
ast_str_set ( & str , 0 , " UnitType(%u) " , entry_num ) ;
unittype = astman_get_header ( m , ast_str_buffer ( str ) ) ;
if ( ! ast_strlen_zero ( unitamount ) & & ( sscanf ( unitamount , " %30u " , & entry - > amount ) = = 1 ) ) {
entry - > valid_amount = 1 ;
}
if ( ! ast_strlen_zero ( unittype ) & & sscanf ( unittype , " %30u " , & entry - > type ) = = 1 ) {
entry - > valid_type = 1 ;
}
return 0 ;
}
static int action_aocmessage ( struct mansession * s , const struct message * m )
{
const char * channel = astman_get_header ( m , " Channel " ) ;
const char * pchannel = astman_get_header ( m , " ChannelPrefix " ) ;
const char * msgtype = astman_get_header ( m , " MsgType " ) ;
const char * chargetype = astman_get_header ( m , " ChargeType " ) ;
const char * currencyname = astman_get_header ( m , " CurrencyName " ) ;
const char * currencyamount = astman_get_header ( m , " CurrencyAmount " ) ;
const char * mult = astman_get_header ( m , " CurrencyMultiplier " ) ;
const char * totaltype = astman_get_header ( m , " TotalType " ) ;
const char * aocbillingid = astman_get_header ( m , " AOCBillingId " ) ;
const char * association_id = astman_get_header ( m , " ChargingAssociationId " ) ;
const char * association_num = astman_get_header ( m , " ChargingAssociationNumber " ) ;
const char * association_plan = astman_get_header ( m , " ChargingAssociationPlan " ) ;
enum ast_aoc_type _msgtype ;
enum ast_aoc_charge_type _chargetype ;
enum ast_aoc_currency_multiplier _mult = AST_AOC_MULT_ONE ;
enum ast_aoc_total_type _totaltype = AST_AOC_TOTAL ;
enum ast_aoc_billing_id _billingid = AST_AOC_BILLING_NA ;
unsigned int _currencyamount = 0 ;
int _association_id = 0 ;
unsigned int _association_plan = 0 ;
struct ast_channel * chan = NULL ;
struct ast_aoc_decoded * decoded = NULL ;
struct ast_aoc_encoded * encoded = NULL ;
size_t encoded_size = 0 ;
if ( ast_strlen_zero ( channel ) & & ast_strlen_zero ( pchannel ) ) {
astman_send_error ( s , m , " Channel and PartialChannel are not specified. Specify at least one of these. " ) ;
goto aocmessage_cleanup ;
}
if ( ! ( chan = ast_channel_get_by_name ( channel ) ) & & ! ast_strlen_zero ( pchannel ) ) {
chan = ast_channel_get_by_name_prefix ( pchannel , strlen ( pchannel ) ) ;
}
if ( ! chan ) {
astman_send_error ( s , m , " No such channel " ) ;
goto aocmessage_cleanup ;
}
if ( ast_strlen_zero ( msgtype ) | | ( strcasecmp ( msgtype , " d " ) & & strcasecmp ( msgtype , " e " ) ) ) {
astman_send_error ( s , m , " Invalid MsgType " ) ;
goto aocmessage_cleanup ;
}
if ( ast_strlen_zero ( chargetype ) ) {
astman_send_error ( s , m , " ChargeType not specified " ) ;
goto aocmessage_cleanup ;
}
_msgtype = strcasecmp ( msgtype , " d " ) ? AST_AOC_E : AST_AOC_D ;
if ( ! strcasecmp ( chargetype , " NA " ) ) {
_chargetype = AST_AOC_CHARGE_NA ;
} else if ( ! strcasecmp ( chargetype , " Free " ) ) {
_chargetype = AST_AOC_CHARGE_FREE ;
} else if ( ! strcasecmp ( chargetype , " Currency " ) ) {
_chargetype = AST_AOC_CHARGE_CURRENCY ;
} else if ( ! strcasecmp ( chargetype , " Unit " ) ) {
_chargetype = AST_AOC_CHARGE_UNIT ;
} else {
astman_send_error ( s , m , " Invalid ChargeType " ) ;
goto aocmessage_cleanup ;
}
if ( _chargetype = = AST_AOC_CHARGE_CURRENCY ) {
if ( ast_strlen_zero ( currencyamount ) | | ( sscanf ( currencyamount , " %30u " , & _currencyamount ) ! = 1 ) ) {
astman_send_error ( s , m , " Invalid CurrencyAmount, CurrencyAmount is a required when ChargeType is Currency " ) ;
goto aocmessage_cleanup ;
}
if ( ast_strlen_zero ( mult ) ) {
astman_send_error ( s , m , " ChargeMultiplier unspecified, ChargeMultiplier is required when ChargeType is Currency. " ) ;
goto aocmessage_cleanup ;
} else if ( ! strcasecmp ( mult , " onethousandth " ) ) {
_mult = AST_AOC_MULT_ONETHOUSANDTH ;
} else if ( ! strcasecmp ( mult , " onehundredth " ) ) {
_mult = AST_AOC_MULT_ONEHUNDREDTH ;
} else if ( ! strcasecmp ( mult , " onetenth " ) ) {
_mult = AST_AOC_MULT_ONETENTH ;
} else if ( ! strcasecmp ( mult , " one " ) ) {
_mult = AST_AOC_MULT_ONE ;
} else if ( ! strcasecmp ( mult , " ten " ) ) {
_mult = AST_AOC_MULT_TEN ;
} else if ( ! strcasecmp ( mult , " hundred " ) ) {
_mult = AST_AOC_MULT_HUNDRED ;
} else if ( ! strcasecmp ( mult , " thousand " ) ) {
_mult = AST_AOC_MULT_THOUSAND ;
} else {
astman_send_error ( s , m , " Invalid ChargeMultiplier " ) ;
goto aocmessage_cleanup ;
}
}
/* create decoded object and start setting values */
if ( ! ( decoded = ast_aoc_create ( _msgtype , _chargetype , 0 ) ) ) {
astman_send_error ( s , m , " Message Creation Failed " ) ;
goto aocmessage_cleanup ;
}
if ( _msgtype = = AST_AOC_D ) {
if ( ! ast_strlen_zero ( totaltype ) & & ! strcasecmp ( totaltype , " subtotal " ) ) {
_totaltype = AST_AOC_SUBTOTAL ;
}
if ( ast_strlen_zero ( aocbillingid ) ) {
/* ignore this is optional */
} else if ( ! strcasecmp ( aocbillingid , " Normal " ) ) {
_billingid = AST_AOC_BILLING_NORMAL ;
} else if ( ! strcasecmp ( aocbillingid , " ReverseCharge " ) ) {
_billingid = AST_AOC_BILLING_REVERSE_CHARGE ;
} else if ( ! strcasecmp ( aocbillingid , " CreditCard " ) ) {
_billingid = AST_AOC_BILLING_CREDIT_CARD ;
} else {
astman_send_error ( s , m , " Invalid AOC-D AOCBillingId " ) ;
goto aocmessage_cleanup ;
}
} else {
if ( ast_strlen_zero ( aocbillingid ) ) {
/* ignore this is optional */
} else if ( ! strcasecmp ( aocbillingid , " Normal " ) ) {
_billingid = AST_AOC_BILLING_NORMAL ;
} else if ( ! strcasecmp ( aocbillingid , " ReverseCharge " ) ) {
_billingid = AST_AOC_BILLING_REVERSE_CHARGE ;
} else if ( ! strcasecmp ( aocbillingid , " CreditCard " ) ) {
_billingid = AST_AOC_BILLING_CREDIT_CARD ;
} else if ( ! strcasecmp ( aocbillingid , " CallFwdUnconditional " ) ) {
_billingid = AST_AOC_BILLING_CALL_FWD_UNCONDITIONAL ;
} else if ( ! strcasecmp ( aocbillingid , " CallFwdBusy " ) ) {
_billingid = AST_AOC_BILLING_CALL_FWD_BUSY ;
} else if ( ! strcasecmp ( aocbillingid , " CallFwdNoReply " ) ) {
_billingid = AST_AOC_BILLING_CALL_FWD_NO_REPLY ;
} else if ( ! strcasecmp ( aocbillingid , " CallDeflection " ) ) {
_billingid = AST_AOC_BILLING_CALL_DEFLECTION ;
} else if ( ! strcasecmp ( aocbillingid , " CallTransfer " ) ) {
_billingid = AST_AOC_BILLING_CALL_TRANSFER ;
} else {
astman_send_error ( s , m , " Invalid AOC-E AOCBillingId " ) ;
goto aocmessage_cleanup ;
}
if ( ! ast_strlen_zero ( association_id ) & & ( sscanf ( association_id , " %30d " , & _association_id ) ! = 1 ) ) {
astman_send_error ( s , m , " Invalid ChargingAssociationId " ) ;
goto aocmessage_cleanup ;
}
if ( ! ast_strlen_zero ( association_plan ) & & ( sscanf ( association_plan , " %30u " , & _association_plan ) ! = 1 ) ) {
astman_send_error ( s , m , " Invalid ChargingAssociationPlan " ) ;
goto aocmessage_cleanup ;
}
if ( _association_id ) {
ast_aoc_set_association_id ( decoded , _association_id ) ;
} else if ( ! ast_strlen_zero ( association_num ) ) {
ast_aoc_set_association_number ( decoded , association_num , _association_plan ) ;
}
}
if ( _chargetype = = AST_AOC_CHARGE_CURRENCY ) {
ast_aoc_set_currency_info ( decoded , _currencyamount , _mult , ast_strlen_zero ( currencyname ) ? NULL : currencyname ) ;
} else if ( _chargetype = = AST_AOC_CHARGE_UNIT ) {
struct ast_aoc_unit_entry entry ;
int i ;
/* multiple unit entries are possible, lets get them all */
for ( i = 0 ; i < 32 ; i + + ) {
if ( aocmessage_get_unit_entry ( m , & entry , i ) ) {
break ; /* that's the end then */
}
ast_aoc_add_unit_entry ( decoded , entry . valid_amount , entry . amount , entry . valid_type , entry . type ) ;
}
/* at least one unit entry is required */
if ( ! i ) {
astman_send_error ( s , m , " Invalid UnitAmount(0), At least one valid unit entry is required when ChargeType is set to Unit " ) ;
goto aocmessage_cleanup ;
}
}
ast_aoc_set_billing_id ( decoded , _billingid ) ;
ast_aoc_set_total_type ( decoded , _totaltype ) ;
if ( ( encoded = ast_aoc_encode ( decoded , & encoded_size , NULL ) ) & & ! ast_indicate_data ( chan , AST_CONTROL_AOC , encoded , encoded_size ) ) {
astman_send_ack ( s , m , " AOC Message successfully queued on channel " ) ;
} else {
astman_send_error ( s , m , " Error encoding AOC message, could not queue onto channel " ) ;
}
aocmessage_cleanup :
ast_aoc_destroy_decoded ( decoded ) ;
ast_aoc_destroy_encoded ( encoded ) ;
if ( chan ) {
chan = ast_channel_unref ( chan ) ;
}
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_originate ( struct mansession * s , const struct message * m )
{
const char * name = astman_get_header ( m , " Channel " ) ;
const char * exten = astman_get_header ( m , " Exten " ) ;
const char * context = astman_get_header ( m , " Context " ) ;
const char * priority = astman_get_header ( m , " Priority " ) ;
const char * timeout = astman_get_header ( m , " Timeout " ) ;
const char * callerid = astman_get_header ( m , " CallerID " ) ;
const char * account = astman_get_header ( m , " Account " ) ;
const char * app = astman_get_header ( m , " Application " ) ;
const char * appdata = astman_get_header ( m , " Data " ) ;
const char * async = astman_get_header ( m , " Async " ) ;
const char * id = astman_get_header ( m , " ActionID " ) ;
2008-05-14 12:32:57 +00:00
const char * codecs = astman_get_header ( m , " Codecs " ) ;
2010-09-19 16:12:08 +00:00
struct ast_variable * vars ;
2002-09-12 18:32:42 +00:00
char * tech , * data ;
2006-04-04 19:03:12 +00:00
char * l = NULL , * n = NULL ;
2002-09-12 18:32:42 +00:00
int pi = 0 ;
int res ;
int to = 30000 ;
int reason = 0 ;
char tmp [ 256 ] ;
2005-07-15 23:24:51 +00:00
char tmp2 [ 256 ] ;
2011-02-03 16:22:10 +00:00
struct ast_format_cap * cap = ast_format_cap_alloc_nolock ( ) ;
struct ast_format tmp_fmt ;
2004-05-01 23:52:27 +00:00
pthread_t th ;
2011-02-03 16:22:10 +00:00
if ( ! cap ) {
astman_send_error ( s , m , " Internal Error. Memory allocation failure. " ) ;
}
ast_format_cap_add ( cap , ast_format_set ( & tmp_fmt , AST_FORMAT_SLINEAR , 0 ) ) ;
2008-08-25 21:48:51 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Channel not specified " ) ;
2011-02-03 16:22:10 +00:00
res = 0 ;
goto fast_orig_cleanup ;
2002-09-12 18:32:42 +00:00
}
2009-08-10 19:20:57 +00:00
if ( ! ast_strlen_zero ( priority ) & & ( sscanf ( priority , " %30d " , & pi ) ! = 1 ) ) {
2005-12-27 19:13:13 +00:00
if ( ( pi = ast_findlabel_extension ( NULL , context , exten , priority , NULL ) ) < 1 ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Invalid priority " ) ;
2011-02-03 16:22:10 +00:00
res = 0 ;
goto fast_orig_cleanup ;
2005-12-27 19:13:13 +00:00
}
2002-09-12 18:32:42 +00:00
}
2009-08-10 19:20:57 +00:00
if ( ! ast_strlen_zero ( timeout ) & & ( sscanf ( timeout , " %30d " , & to ) ! = 1 ) ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Invalid timeout " ) ;
2011-02-03 16:22:10 +00:00
res = 0 ;
goto fast_orig_cleanup ;
2002-09-12 18:32:42 +00:00
}
2005-07-10 22:56:21 +00:00
ast_copy_string ( tmp , name , sizeof ( tmp ) ) ;
2002-09-12 18:32:42 +00:00
tech = tmp ;
data = strchr ( tmp , ' / ' ) ;
if ( ! data ) {
2008-07-15 18:25:34 +00:00
astman_send_error ( s , m , " Invalid channel " ) ;
2011-02-03 16:22:10 +00:00
res = 0 ;
goto fast_orig_cleanup ;
2002-09-12 18:32:42 +00:00
}
2006-03-28 23:52:21 +00:00
* data + + = ' \0 ' ;
2005-07-10 22:56:21 +00:00
ast_copy_string ( tmp2 , callerid , sizeof ( tmp2 ) ) ;
2004-10-02 00:58:31 +00:00
ast_callerid_parse ( tmp2 , & n , & l ) ;
if ( n ) {
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( n ) ) {
2004-10-02 00:58:31 +00:00
n = NULL ;
2009-04-23 20:36:35 +00:00
}
2004-10-02 00:58:31 +00:00
}
if ( l ) {
ast_shrink_phone_number ( l ) ;
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( l ) ) {
2004-10-02 00:58:31 +00:00
l = NULL ;
2009-04-23 20:36:35 +00:00
}
2004-10-02 00:58:31 +00:00
}
2008-05-14 12:32:57 +00:00
if ( ! ast_strlen_zero ( codecs ) ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( cap ) ;
ast_parse_allow_disallow ( NULL , cap , codecs , 1 ) ;
2008-05-14 12:32:57 +00:00
}
2011-04-21 18:32:50 +00:00
if ( ! ast_strlen_zero ( app ) ) {
/* To run the System application (or anything else that goes to
* shell ) , you must have the additional System privilege */
if ( ! ( s - > session - > writeperm & EVENT_FLAG_SYSTEM )
& & (
strcasestr ( app , " system " ) | | /* System(rm -rf /)
TrySystem ( rm - rf / ) */
strcasestr ( app , " exec " ) | | /* Exec(System(rm -rf /))
TryExec ( System ( rm - rf / ) ) */
strcasestr ( app , " agi " ) | | /* AGI(/bin/rm,-rf /)
EAGI ( / bin / rm , - rf / ) */
strstr ( appdata , " SHELL " ) | | /* NoOp(${SHELL(rm -rf /)}) */
strstr ( appdata , " EVAL " ) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
) ) {
astman_send_error ( s , m , " Originate with certain 'Application' arguments requires the additional System privilege, which you do not have. " ) ;
res = 0 ;
goto fast_orig_cleanup ;
}
}
2011-10-04 09:43:03 +00:00
/* Check early if the extension exists. If not, we need to bail out here. */
if ( exten & & context & & pi ) {
if ( ! ast_exists_extension ( NULL , context , exten , pi , l ) ) {
/* The extension does not exist. */
astman_send_error ( s , m , " Extension does not exist. " ) ;
res = 0 ;
goto fast_orig_cleanup ;
}
}
2010-09-19 16:12:08 +00:00
/* Allocate requested channel variables */
vars = astman_get_variables ( m ) ;
2004-09-17 14:15:11 +00:00
if ( ast_true ( async ) ) {
2012-01-31 17:26:09 +00:00
struct fast_originate_helper * fast ;
fast = ast_calloc ( 1 , sizeof ( * fast ) ) ;
2011-09-13 18:49:26 +00:00
if ( ! fast | | ast_string_field_init ( fast , 252 ) ) {
2012-01-31 17:26:09 +00:00
ast_free ( fast ) ;
ast_variables_destroy ( vars ) ;
2004-05-01 23:52:27 +00:00
res = - 1 ;
2004-09-17 14:15:11 +00:00
} else {
2011-09-13 18:49:26 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2012-01-31 17:26:09 +00:00
ast_string_field_build ( fast , idtext , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
}
2012-01-31 17:26:09 +00:00
ast_string_field_set ( fast , tech , tech ) ;
ast_string_field_set ( fast , data , data ) ;
2011-09-13 18:49:26 +00:00
ast_string_field_set ( fast , app , app ) ;
ast_string_field_set ( fast , appdata , appdata ) ;
ast_string_field_set ( fast , cid_num , l ) ;
ast_string_field_set ( fast , cid_name , n ) ;
ast_string_field_set ( fast , context , context ) ;
ast_string_field_set ( fast , exten , exten ) ;
ast_string_field_set ( fast , account , account ) ;
2006-10-18 21:41:09 +00:00
fast - > vars = vars ;
2011-02-03 16:22:10 +00:00
fast - > cap = cap ;
cap = NULL ; /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
2004-05-01 23:52:27 +00:00
fast - > timeout = to ;
fast - > priority = pi ;
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached ( & th , NULL , fast_originate , fast ) ) {
2012-01-31 17:26:09 +00:00
destroy_fast_originate_helper ( fast ) ;
2004-05-01 23:52:27 +00:00
res = - 1 ;
2004-09-17 14:15:11 +00:00
} else {
2004-05-01 23:52:27 +00:00
res = 0 ;
}
}
2004-05-26 19:30:12 +00:00
} else if ( ! ast_strlen_zero ( app ) ) {
2011-02-03 16:22:10 +00:00
res = ast_pbx_outgoing_app ( tech , cap , data , to , app , appdata , & reason , 1 , l , n , vars , account , NULL ) ;
2012-01-31 17:26:09 +00:00
/* Any vars memory was passed to ast_pbx_outgoing_app(). */
2008-02-22 22:55:35 +00:00
} else {
2009-04-23 20:36:35 +00:00
if ( exten & & context & & pi ) {
2011-02-03 16:22:10 +00:00
res = ast_pbx_outgoing_exten ( tech , cap , data , to , context , exten , pi , & reason , 1 , l , n , vars , account , NULL ) ;
2012-01-31 17:26:09 +00:00
/* Any vars memory was passed to ast_pbx_outgoing_exten(). */
2009-04-23 20:36:35 +00:00
} else {
2004-03-09 20:01:46 +00:00
astman_send_error ( s , m , " Originate with 'Exten' requires 'Context' and 'Priority' " ) ;
2012-01-31 17:26:09 +00:00
ast_variables_destroy ( vars ) ;
2011-02-03 16:22:10 +00:00
res = 0 ;
goto fast_orig_cleanup ;
2004-03-09 20:01:46 +00:00
}
2006-10-18 21:41:09 +00:00
}
2009-04-23 20:36:35 +00:00
if ( ! res ) {
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Originate successfully queued " ) ;
2009-04-23 20:36:35 +00:00
} else {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Originate failed " ) ;
2009-04-23 20:36:35 +00:00
}
2011-02-03 16:22:10 +00:00
fast_orig_cleanup :
ast_format_cap_destroy ( cap ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_mailboxstatus ( struct mansession * s , const struct message * m )
2003-02-24 06:00:18 +00:00
{
2007-01-05 22:43:18 +00:00
const char * mailbox = astman_get_header ( m , " Mailbox " ) ;
2004-09-10 15:11:38 +00:00
int ret ;
2006-10-18 16:52:13 +00:00
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( mailbox ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Mailbox not specified " ) ;
2003-02-24 06:00:18 +00:00
return 0 ;
}
2004-10-03 21:18:27 +00:00
ret = ast_app_has_voicemail ( mailbox , NULL ) ;
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
astman_append ( s , " Message: Mailbox Status \r \n "
" Mailbox: %s \r \n "
" Waiting: %d \r \n \r \n " , mailbox , ret ) ;
2003-04-06 18:19:51 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_mailboxcount ( struct mansession * s , const struct message * m )
2003-06-21 20:05:16 +00:00
{
2007-01-05 22:43:18 +00:00
const char * mailbox = astman_get_header ( m , " Mailbox " ) ;
2008-05-09 21:22:42 +00:00
int newmsgs = 0 , oldmsgs = 0 , urgentmsgs = 0 ; ;
2006-10-18 16:52:13 +00:00
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( mailbox ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Mailbox not specified " ) ;
2003-06-21 20:05:16 +00:00
return 0 ;
}
2008-07-02 21:27:53 +00:00
ast_app_inboxcount2 ( mailbox , & urgentmsgs , & newmsgs , & oldmsgs ) ;
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
2006-10-18 16:52:13 +00:00
astman_append ( s , " Message: Mailbox Message Count \r \n "
" Mailbox: %s \r \n "
2008-05-09 21:22:42 +00:00
" UrgMessages: %d \r \n "
2006-10-18 16:52:13 +00:00
" NewMessages: %d \r \n "
2006-10-18 21:41:09 +00:00
" OldMessages: %d \r \n "
2006-10-18 16:52:13 +00:00
" \r \n " ,
2008-05-09 21:22:42 +00:00
mailbox , urgentmsgs , newmsgs , oldmsgs ) ;
2003-06-21 20:05:16 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_extensionstate ( struct mansession * s , const struct message * m )
2003-04-06 18:19:51 +00:00
{
2007-01-05 22:43:18 +00:00
const char * exten = astman_get_header ( m , " Exten " ) ;
const char * context = astman_get_header ( m , " Context " ) ;
2003-04-07 02:04:56 +00:00
char hint [ 256 ] = " " ;
2003-04-06 18:19:51 +00:00
int status ;
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( exten ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Extension not specified " ) ;
2003-04-06 18:19:51 +00:00
return 0 ;
}
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( context ) ) {
2003-04-06 18:19:51 +00:00
context = " default " ;
2009-04-23 20:36:35 +00:00
}
2003-04-06 18:19:51 +00:00
status = ast_extension_state ( NULL , context , exten ) ;
2005-02-01 01:53:25 +00:00
ast_get_hint ( hint , sizeof ( hint ) - 1 , NULL , 0 , NULL , context , exten ) ;
2006-10-18 14:21:15 +00:00
astman_start_ack ( s , m ) ;
astman_append ( s , " Message: Extension Status \r \n "
" Exten: %s \r \n "
" Context: %s \r \n "
" Hint: %s \r \n "
" Status: %d \r \n \r \n " ,
exten , context , hint , status ) ;
2003-02-24 06:00:18 +00:00
return 0 ;
}
2007-01-05 22:43:18 +00:00
static int action_timeout ( struct mansession * s , const struct message * m )
2003-06-09 21:40:20 +00:00
{
2006-10-18 16:52:13 +00:00
struct ast_channel * c ;
2007-01-05 22:43:18 +00:00
const char * name = astman_get_header ( m , " Channel " ) ;
2008-05-01 23:06:23 +00:00
double timeout = atof ( astman_get_header ( m , " Timeout " ) ) ;
2008-08-10 19:35:50 +00:00
struct timeval when = { timeout , 0 } ;
2006-10-18 16:52:13 +00:00
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
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
2008-05-01 23:06:23 +00:00
if ( ! timeout | | timeout < 0 ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No timeout specified " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
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 ( ! ( c = ast_channel_get_by_name ( name ) ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No such channel " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
2008-05-01 23:06:23 +00:00
2008-08-10 19:35:50 +00:00
when . tv_usec = ( timeout - when . tv_sec ) * 1000000.0 ;
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
ast_channel_lock ( c ) ;
2008-08-10 19:35:50 +00:00
ast_channel_setwhentohangup_tv ( c , when ) ;
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( c ) ;
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
c = ast_channel_unref ( c ) ;
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Timeout Set " ) ;
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
2003-06-09 21:40:20 +00:00
return 0 ;
}
2010-06-22 16:29:18 +00:00
static int whitefilter_cmp_fn ( void * obj , void * arg , void * data , int flags )
{
regex_t * regex_filter = obj ;
const char * eventdata = arg ;
int * result = data ;
if ( ! regexec ( regex_filter , eventdata , 0 , NULL , 0 ) ) {
* result = 1 ;
return ( CMP_MATCH | CMP_STOP ) ;
}
return 0 ;
}
static int blackfilter_cmp_fn ( void * obj , void * arg , void * data , int flags )
{
regex_t * regex_filter = obj ;
const char * eventdata = arg ;
int * result = data ;
2011-02-04 22:37:11 +00:00
if ( ! regexec ( regex_filter , eventdata , 0 , NULL , 0 ) ) {
* result = 0 ;
2010-06-22 16:29:18 +00:00
return ( CMP_MATCH | CMP_STOP ) ;
}
2011-02-04 22:37:11 +00:00
* result = 1 ;
2010-06-22 16:29:18 +00:00
return 0 ;
}
2011-07-05 16:46:17 +00:00
/*
* \ brief Manager command to add an event filter to a manager session
* \ see For more details look at manager_add_filter
*/
static int action_filter ( struct mansession * s , const struct message * m )
{
const char * filter = astman_get_header ( m , " Filter " ) ;
const char * operation = astman_get_header ( m , " Operation " ) ;
int res ;
if ( ! strcasecmp ( operation , " Add " ) ) {
res = manager_add_filter ( filter , s - > session - > whitefilters , s - > session - > blackfilters ) ;
if ( res ! = FILTER_SUCCESS ) {
if ( res = = FILTER_ALLOC_FAILED ) {
astman_send_error ( s , m , " Internal Error. Failed to allocate regex for filter " ) ;
return 0 ;
} else if ( res = = FILTER_COMPILE_FAIL ) {
astman_send_error ( s , m , " Filter did not compile. Check the syntax of the filter given. " ) ;
return 0 ;
} else {
astman_send_error ( s , m , " Internal Error. Failed adding filter. " ) ;
return 0 ;
}
}
astman_send_ack ( s , m , " Success " ) ;
return 0 ;
}
astman_send_error ( s , m , " Unknown operation " ) ;
return 0 ;
}
/*
* \ brief Add an event filter to a manager session
*
* \ param s manager session to modify filters on
* \ param filter_pattern Filter syntax to add , see below for syntax
*
* \ return FILTER_ALLOC_FAILED Memory allocation failure
* \ return FILTER_COMPILE_FAIL If the filter did not compile
* \ return FILTER_SUCCESS Success
*
* Filter will be used to match against each line of a manager event
* Filter can be any valid regular expression
* Filter can be a valid regular expression prefixed with ! , which will add the filter as a black filter
*
* \ example filter_pattern = " Event: Newchannel "
* \ example filter_pattern = " Event: New.* "
* \ example filter_pattern = " !Channel: DAHDI.* "
*
*/
static enum add_filter_result manager_add_filter ( const char * filter_pattern , struct ao2_container * whitefilters , struct ao2_container * blackfilters ) {
regex_t * new_filter = ao2_t_alloc ( sizeof ( * new_filter ) , event_filter_destructor , " event_filter allocation " ) ;
int is_blackfilter ;
if ( ! new_filter ) {
return FILTER_ALLOC_FAILED ;
}
if ( filter_pattern [ 0 ] = = ' ! ' ) {
is_blackfilter = 1 ;
filter_pattern + + ;
} else {
is_blackfilter = 0 ;
}
if ( regcomp ( new_filter , filter_pattern , 0 ) ) {
ao2_t_ref ( new_filter , - 1 , " failed to make regx " ) ;
return FILTER_COMPILE_FAIL ;
}
if ( is_blackfilter ) {
ao2_t_link ( blackfilters , new_filter , " link new filter into black user container " ) ;
} else {
ao2_t_link ( whitefilters , new_filter , " link new filter into white user container " ) ;
}
return FILTER_SUCCESS ;
}
2010-06-22 16:29:18 +00:00
static int match_filter ( struct mansession * s , char * eventdata )
{
int result = 0 ;
ast_debug ( 3 , " Examining event: \n %s \n " , eventdata ) ;
if ( ! ao2_container_count ( s - > session - > whitefilters ) & & ! ao2_container_count ( s - > session - > blackfilters ) ) {
return 1 ; /* no filtering means match all */
} else if ( ao2_container_count ( s - > session - > whitefilters ) & & ! ao2_container_count ( s - > session - > blackfilters ) ) {
/* white filters only: implied black all filter processed first, then white filters */
ao2_t_callback_data ( s - > session - > whitefilters , OBJ_NODATA , whitefilter_cmp_fn , eventdata , & result , " find filter in session filter container " ) ;
} else if ( ! ao2_container_count ( s - > session - > whitefilters ) & & ao2_container_count ( s - > session - > blackfilters ) ) {
/* black filters only: implied white all filter processed first, then black filters */
ao2_t_callback_data ( s - > session - > blackfilters , OBJ_NODATA , blackfilter_cmp_fn , eventdata , & result , " find filter in session filter container " ) ;
} else {
/* white and black filters: implied black all filter processed first, then white filters, and lastly black filters */
ao2_t_callback_data ( s - > session - > whitefilters , OBJ_NODATA , whitefilter_cmp_fn , eventdata , & result , " find filter in session filter container " ) ;
if ( result ) {
result = 0 ;
ao2_t_callback_data ( s - > session - > blackfilters , OBJ_NODATA , blackfilter_cmp_fn , eventdata , & result , " find filter in session filter container " ) ;
}
}
return result ;
}
2006-11-18 22:14:20 +00:00
/*!
2006-11-28 10:23:25 +00:00
* Send any applicable events to the client listening on this socket .
* Wait only for a finite time on each event , and drop all events whether
* they are successfully sent or not .
2006-11-18 22:14:20 +00:00
*/
2006-04-02 19:59:55 +00:00
static int process_events ( struct mansession * s )
{
int ret = 0 ;
2006-10-16 11:29:22 +00:00
2009-04-23 20:36:35 +00:00
ao2_lock ( s - > session ) ;
2009-02-10 21:45:14 +00:00
if ( s - > session - > f ! = NULL ) {
2010-06-01 16:41:00 +00:00
struct eventqent * eqe = s - > session - > last_ev ;
2010-10-21 16:46:15 +00:00
2010-06-01 16:41:00 +00:00
while ( ( eqe = advance_event ( eqe ) ) ) {
2009-02-10 21:45:14 +00:00
if ( ! ret & & s - > session - > authenticated & &
( s - > session - > readperm & eqe - > category ) = = eqe - > category & &
( s - > session - > send_events & eqe - > category ) = = eqe - > category ) {
2010-06-22 16:29:18 +00:00
if ( match_filter ( s , eqe - > eventdata ) ) {
if ( send_string ( s , eqe - > eventdata ) < 0 )
ret = - 1 ; /* don't send more */
}
2006-04-02 19:59:55 +00:00
}
2010-06-01 16:41:00 +00:00
s - > session - > last_ev = eqe ;
2006-04-02 19:59:55 +00:00
}
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( s - > session ) ;
2006-04-02 19:59:55 +00:00
return ret ;
}
2007-01-05 22:43:18 +00:00
static int action_userevent ( struct mansession * s , const struct message * m )
2006-05-20 13:29:22 +00:00
{
2007-01-05 22:43:18 +00:00
const char * event = astman_get_header ( m , " UserEvent " ) ;
2009-01-19 20:05:52 +00:00
struct ast_str * body = ast_str_thread_get ( & userevent_buf , 16 ) ;
int x ;
2009-03-10 14:40:38 +00:00
ast_str_reset ( body ) ;
2006-05-20 13:29:22 +00:00
for ( x = 0 ; x < m - > hdrcount ; x + + ) {
if ( strncasecmp ( " UserEvent: " , m - > headers [ x ] , strlen ( " UserEvent: " ) ) ) {
2009-01-19 20:05:52 +00:00
ast_str_append ( & body , 0 , " %s \r \n " , m - > headers [ x ] ) ;
2006-05-20 13:29:22 +00:00
}
}
2009-12-02 22:02:43 +00:00
astman_send_ack ( s , m , " Event Sent " ) ;
2009-01-19 20:05:52 +00:00
manager_event ( EVENT_FLAG_USER , " UserEvent " , " UserEvent: %s \r \n %s " , event , ast_str_buffer ( body ) ) ;
2006-05-20 13:29:22 +00:00
return 0 ;
}
2007-05-04 13:44:50 +00:00
/*! \brief Show PBX core settings information */
static int action_coresettings ( struct mansession * s , const struct message * m )
{
const char * actionid = astman_get_header ( m , " ActionID " ) ;
2008-02-03 17:40:48 +00:00
char idText [ 150 ] ;
2007-05-04 13:44:50 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( actionid ) ) {
2007-05-04 19:48:52 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , actionid ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-03 17:40:48 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2007-05-04 13:44:50 +00:00
astman_append ( s , " Response: Success \r \n "
" %s "
" AMIversion: %s \r \n "
" AsteriskVersion: %s \r \n "
" SystemName: %s \r \n "
" CoreMaxCalls: %d \r \n "
" CoreMaxLoadAvg: %f \r \n "
" CoreRunUser: %s \r \n "
" CoreRunGroup: %s \r \n "
2009-04-23 20:36:35 +00:00
" CoreMaxFilehandles: %d \r \n "
2007-05-04 13:44:50 +00:00
" CoreRealTimeEnabled: %s \r \n "
" CoreCDRenabled: %s \r \n "
" CoreHTTPenabled: %s \r \n "
2008-02-03 17:40:48 +00:00
" \r \n " ,
idText ,
2007-05-04 13:44:50 +00:00
AMI_VERSION ,
2009-04-23 20:36:35 +00:00
ast_get_version ( ) ,
2007-05-04 13:44:50 +00:00
ast_config_AST_SYSTEM_NAME ,
option_maxcalls ,
option_maxload ,
ast_config_AST_RUN_USER ,
ast_config_AST_RUN_GROUP ,
option_maxfiles ,
2010-05-05 00:44:37 +00:00
AST_CLI_YESNO ( ast_realtime_enabled ( ) ) ,
AST_CLI_YESNO ( check_cdr_enabled ( ) ) ,
AST_CLI_YESNO ( check_webmanager_enabled ( ) )
2007-05-04 13:44:50 +00:00
) ;
return 0 ;
}
2007-05-04 13:47:11 +00:00
/*! \brief Show PBX core status information */
static int action_corestatus ( struct mansession * s , const struct message * m )
{
const char * actionid = astman_get_header ( m , " ActionID " ) ;
char idText [ 150 ] ;
2009-05-26 20:20:08 +00:00
char startuptime [ 150 ] , startupdate [ 150 ] ;
char reloadtime [ 150 ] , reloaddate [ 150 ] ;
2007-07-18 19:47:20 +00:00
struct ast_tm tm ;
2007-05-04 13:47:11 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( actionid ) ) {
2007-05-04 19:48:52 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , actionid ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-03 17:40:48 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2007-05-04 19:48:52 +00:00
2007-06-14 22:09:20 +00:00
ast_localtime ( & ast_startuptime , & tm , NULL ) ;
2007-07-18 19:47:20 +00:00
ast_strftime ( startuptime , sizeof ( startuptime ) , " %H:%M:%S " , & tm ) ;
2009-05-26 20:20:08 +00:00
ast_strftime ( startupdate , sizeof ( startupdate ) , " %Y-%m-%d " , & tm ) ;
2007-06-14 22:09:20 +00:00
ast_localtime ( & ast_lastreloadtime , & tm , NULL ) ;
2007-07-18 19:47:20 +00:00
ast_strftime ( reloadtime , sizeof ( reloadtime ) , " %H:%M:%S " , & tm ) ;
2009-05-26 20:20:08 +00:00
ast_strftime ( reloaddate , sizeof ( reloaddate ) , " %Y-%m-%d " , & tm ) ;
2007-05-04 13:47:11 +00:00
astman_append ( s , " Response: Success \r \n "
" %s "
2009-05-26 20:20:08 +00:00
" CoreStartupDate: %s \r \n "
2007-05-04 13:47:11 +00:00
" CoreStartupTime: %s \r \n "
2009-05-26 20:20:08 +00:00
" CoreReloadDate: %s \r \n "
2007-05-04 13:47:11 +00:00
" CoreReloadTime: %s \r \n "
" CoreCurrentCalls: %d \r \n "
2008-02-03 17:40:48 +00:00
" \r \n " ,
2007-05-04 13:47:11 +00:00
idText ,
2009-05-26 20:20:08 +00:00
startupdate ,
2007-05-04 13:47:11 +00:00
startuptime ,
2009-05-26 20:20:08 +00:00
reloaddate ,
2007-05-04 13:47:11 +00:00
reloadtime ,
ast_active_channels ( )
) ;
return 0 ;
}
2007-09-22 14:03:48 +00:00
/*! \brief Send a reload event */
static int action_reload ( struct mansession * s , const struct message * m )
{
const char * module = astman_get_header ( m , " Module " ) ;
int res = ast_module_reload ( S_OR ( module , NULL ) ) ;
2009-04-23 20:36:35 +00:00
if ( res = = 2 ) {
2008-02-03 17:40:48 +00:00
astman_send_ack ( s , m , " Module Reloaded " ) ;
2009-04-23 20:36:35 +00:00
} else {
2007-09-22 14:03:48 +00:00
astman_send_error ( s , m , s = = 0 ? " No such module " : " Module does not support reload " ) ;
2009-04-23 20:36:35 +00:00
}
2007-09-22 14:03:48 +00:00
return 0 ;
}
2007-05-04 13:44:50 +00:00
2009-04-23 20:36:35 +00:00
/*! \brief Manager command "CoreShowChannels" - List currently defined channels
2007-12-06 10:27:54 +00:00
* and some information about them . */
static int action_coreshowchannels ( struct mansession * s , const struct message * m )
{
const char * actionid = astman_get_header ( m , " ActionID " ) ;
2009-05-26 22:38:05 +00:00
char idText [ 256 ] ;
2007-12-06 10:27:54 +00:00
struct ast_channel * c = NULL ;
int numchans = 0 ;
int duration , durh , durm , durs ;
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_iterator * iter ;
2007-12-06 10:27:54 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( actionid ) ) {
2009-05-26 22:38:05 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , actionid ) ;
2009-04-23 20:36:35 +00:00
} else {
2009-05-26 22:38:05 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2007-12-06 10:27:54 +00:00
2009-10-21 21:08:47 +00:00
if ( ! ( iter = ast_channel_iterator_all_new ( ) ) ) {
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
astman_send_error ( s , m , " Memory Allocation Failure " ) ;
return 1 ;
}
2009-04-23 20:36:35 +00:00
astman_send_listack ( s , m , " Channels will follow " , " start " ) ;
2007-12-06 10:27:54 +00:00
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
for ( ; ( c = ast_channel_iterator_next ( iter ) ) ; ast_channel_unref ( c ) ) {
struct ast_channel * bc ;
2007-12-06 10:27:54 +00:00
char durbuf [ 10 ] = " " ;
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
ast_channel_lock ( c ) ;
bc = ast_bridged_channel ( c ) ;
2012-02-20 23:43:27 +00:00
if ( ast_channel_cdr ( c ) & & ! ast_tvzero ( ast_channel_cdr ( c ) - > start ) ) {
duration = ( int ) ( ast_tvdiff_ms ( ast_tvnow ( ) , ast_channel_cdr ( c ) - > start ) / 1000 ) ;
2007-12-06 10:27:54 +00:00
durh = duration / 3600 ;
durm = ( duration % 3600 ) / 60 ;
durs = duration % 60 ;
snprintf ( durbuf , sizeof ( durbuf ) , " %02d:%02d:%02d " , durh , durm , durs ) ;
}
astman_append ( s ,
2008-11-21 19:40:57 +00:00
" Event: CoreShowChannel \r \n "
2009-05-26 22:38:05 +00:00
" %s "
2007-12-06 10:27:54 +00:00
" Channel: %s \r \n "
" UniqueID: %s \r \n "
" Context: %s \r \n "
" Extension: %s \r \n "
" Priority: %d \r \n "
" ChannelState: %d \r \n "
" ChannelStateDesc: %s \r \n "
" Application: %s \r \n "
" ApplicationData: %s \r \n "
" CallerIDnum: %s \r \n "
2011-05-25 17:14:11 +00:00
" CallerIDname: %s \r \n "
" ConnectedLineNum: %s \r \n "
" ConnectedLineName: %s \r \n "
2007-12-06 10:27:54 +00:00
" Duration: %s \r \n "
" AccountCode: %s \r \n "
" BridgedChannel: %s \r \n "
" BridgedUniqueID: %s \r \n "
2012-02-20 23:43:27 +00:00
" \r \n " , idText , ast_channel_name ( c ) , ast_channel_uniqueid ( c ) , ast_channel_context ( c ) , ast_channel_exten ( c ) , ast_channel_priority ( c ) , ast_channel_state ( c ) ,
ast_state2str ( ast_channel_state ( c ) ) , ast_channel_appl ( c ) ? ast_channel_appl ( c ) : " " , ast_channel_data ( c ) ? S_OR ( ast_channel_data ( c ) , " " ) : " " ,
2012-02-29 16:52:47 +00:00
S_COR ( ast_channel_caller ( c ) - > id . number . valid , ast_channel_caller ( c ) - > id . number . str , " " ) ,
S_COR ( ast_channel_caller ( c ) - > id . name . valid , ast_channel_caller ( c ) - > id . name . str , " " ) ,
S_COR ( ast_channel_connected ( c ) - > id . number . valid , ast_channel_connected ( c ) - > id . number . str , " " ) ,
S_COR ( ast_channel_connected ( c ) - > id . name . valid , ast_channel_connected ( c ) - > id . name . str , " " ) ,
2012-01-24 20:12:09 +00:00
durbuf , S_OR ( ast_channel_accountcode ( c ) , " " ) , bc ? ast_channel_name ( bc ) : " " , bc ? ast_channel_uniqueid ( bc ) : " " ) ;
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
2007-12-06 10:27:54 +00:00
ast_channel_unlock ( c ) ;
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
2007-12-06 10:27:54 +00:00
numchans + + ;
}
astman_append ( s ,
2008-02-03 17:40:48 +00:00
" Event: CoreShowChannelsComplete \r \n "
" EventList: Complete \r \n "
" ListItems: %d \r \n "
" %s "
2009-05-26 22:38:05 +00:00
" \r \n " , numchans , idText ) ;
2007-12-06 10:27:54 +00:00
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
ast_channel_iterator_destroy ( iter ) ;
2007-12-06 10:27:54 +00:00
return 0 ;
}
2010-08-27 14:01:21 +00:00
/*! \brief Manager function to check if module is loaded */
2008-01-07 15:52:55 +00:00
static int manager_modulecheck ( struct mansession * s , const struct message * m )
{
int res ;
const char * module = astman_get_header ( m , " Module " ) ;
2008-02-03 17:40:48 +00:00
const char * id = astman_get_header ( m , " ActionID " ) ;
2008-03-04 23:24:56 +00:00
char idText [ 256 ] ;
2008-04-10 22:02:32 +00:00
# if !defined(LOW_MEMORY)
2008-01-07 15:52:55 +00:00
const char * version ;
2008-04-10 22:02:32 +00:00
# endif
2008-03-04 23:24:56 +00:00
char filename [ PATH_MAX ] ;
2008-01-07 15:52:55 +00:00
char * cut ;
2008-03-04 23:24:56 +00:00
ast_copy_string ( filename , module , sizeof ( filename ) ) ;
2008-01-07 15:52:55 +00:00
if ( ( cut = strchr ( filename , ' . ' ) ) ) {
* cut = ' \0 ' ;
} else {
cut = filename + strlen ( filename ) ;
}
2008-03-13 21:47:55 +00:00
snprintf ( cut , ( sizeof ( filename ) - strlen ( filename ) ) - 1 , " .so " ) ;
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " **** ModuleCheck .so file %s \n " , filename ) ;
2008-01-07 15:52:55 +00:00
res = ast_module_check ( filename ) ;
if ( ! res ) {
astman_send_error ( s , m , " Module not loaded " ) ;
return 0 ;
}
2008-03-13 21:47:55 +00:00
snprintf ( cut , ( sizeof ( filename ) - strlen ( filename ) ) - 1 , " .c " ) ;
2011-02-04 16:55:39 +00:00
ast_debug ( 1 , " **** ModuleCheck .c file %s \n " , filename ) ;
2008-04-10 22:02:32 +00:00
# if !defined(LOW_MEMORY)
2008-01-07 15:52:55 +00:00
version = ast_file_version_find ( filename ) ;
2008-04-10 22:02:32 +00:00
# endif
2008-01-07 15:52:55 +00:00
2009-04-23 20:36:35 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2008-01-07 15:52:55 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-02-03 17:40:48 +00:00
idText [ 0 ] = ' \0 ' ;
2009-04-23 20:36:35 +00:00
}
2008-01-07 15:52:55 +00:00
astman_append ( s , " Response: Success \r \n %s " , idText ) ;
2008-04-10 22:02:32 +00:00
# if !defined(LOW_MEMORY)
2008-01-07 15:52:55 +00:00
astman_append ( s , " Version: %s \r \n \r \n " , version ? version : " " ) ;
2008-04-10 22:02:32 +00:00
# endif
2008-01-07 15:52:55 +00:00
return 0 ;
}
static int manager_moduleload ( struct mansession * s , const struct message * m )
{
int res ;
const char * module = astman_get_header ( m , " Module " ) ;
const char * loadtype = astman_get_header ( m , " LoadType " ) ;
2009-04-23 20:36:35 +00:00
if ( ! loadtype | | strlen ( loadtype ) = = 0 ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Incomplete ModuleLoad action. " ) ;
2009-04-23 20:36:35 +00:00
}
if ( ( ! module | | strlen ( module ) = = 0 ) & & strcasecmp ( loadtype , " reload " ) ! = 0 ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Need module name " ) ;
2009-04-23 20:36:35 +00:00
}
2008-01-07 15:52:55 +00:00
if ( ! strcasecmp ( loadtype , " load " ) ) {
res = ast_load_resource ( module ) ;
2009-04-23 20:36:35 +00:00
if ( res ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Could not load module. " ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-01-07 15:52:55 +00:00
astman_send_ack ( s , m , " Module loaded. " ) ;
2009-04-23 20:36:35 +00:00
}
2008-01-07 15:52:55 +00:00
} else if ( ! strcasecmp ( loadtype , " unload " ) ) {
res = ast_unload_resource ( module , AST_FORCE_SOFT ) ;
2009-04-23 20:36:35 +00:00
if ( res ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Could not unload module. " ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-01-07 15:52:55 +00:00
astman_send_ack ( s , m , " Module unloaded. " ) ;
2009-04-23 20:36:35 +00:00
}
2008-01-07 15:52:55 +00:00
} else if ( ! strcasecmp ( loadtype , " reload " ) ) {
2011-08-10 13:49:31 +00:00
if ( ! ast_strlen_zero ( module ) ) {
2008-01-07 15:52:55 +00:00
res = ast_module_reload ( module ) ;
2009-04-23 20:36:35 +00:00
if ( res = = 0 ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " No such module. " ) ;
2009-04-23 20:36:35 +00:00
} else if ( res = = 1 ) {
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Module does not support reload action. " ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-01-07 15:52:55 +00:00
astman_send_ack ( s , m , " Module reloaded. " ) ;
2009-04-23 20:36:35 +00:00
}
2008-01-07 15:52:55 +00:00
} else {
ast_module_reload ( NULL ) ; /* Reload all modules */
astman_send_ack ( s , m , " All modules reloaded " ) ;
}
2009-04-23 20:36:35 +00:00
} else
2008-01-07 15:52:55 +00:00
astman_send_error ( s , m , " Incomplete ModuleLoad action. " ) ;
return 0 ;
}
2007-12-06 10:27:54 +00:00
2006-10-18 17:45:50 +00:00
/*
* Done with the action handlers here , we start with the code in charge
* of accepting connections and serving them .
* accept_thread ( ) forks a new thread for each connection , session_do ( ) ,
* which in turn calls get_input ( ) repeatedly until a full message has
* been accumulated , and then invokes process_message ( ) to pass it to
* the appropriate handler .
*/
2010-08-27 14:01:21 +00:00
/*! \brief
2006-10-18 16:52:13 +00:00
* Process an AMI message , performing desired action .
2006-10-16 14:00:53 +00:00
* Return 0 on success , - 1 on error that require the session to be destroyed .
*/
2007-01-05 22:43:18 +00:00
static int process_message ( struct mansession * s , const struct message * m )
2002-09-12 18:32:42 +00:00
{
2006-04-02 19:59:55 +00:00
int ret = 0 ;
2011-10-11 18:57:47 +00:00
struct manager_action * act_found ;
const char * user ;
const char * action ;
2003-01-28 22:33:41 +00:00
2011-10-11 18:57:47 +00:00
action = __astman_get_header ( m , " Action " , GET_HEADER_SKIP_EMPTY ) ;
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( action ) ) {
2009-07-11 19:15:03 +00:00
report_req_bad_format ( s , " NONE " ) ;
2009-05-12 22:49:13 +00:00
mansession_lock ( s ) ;
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Missing action in request " ) ;
2009-05-12 22:49:13 +00:00
mansession_unlock ( s ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2006-10-18 12:55:12 +00:00
2011-10-11 18:57:47 +00:00
if ( ! s - > session - > authenticated
& & strcasecmp ( action , " Login " )
& & strcasecmp ( action , " Logoff " )
& & strcasecmp ( action , " Challenge " ) ) {
2009-07-11 19:15:03 +00:00
if ( ! s - > session - > authenticated ) {
report_req_not_allowed ( s , action ) ;
}
2009-05-12 22:49:13 +00:00
mansession_lock ( s ) ;
2006-11-22 05:49:06 +00:00
astman_send_error ( s , m , " Permission denied " ) ;
2009-05-12 22:49:13 +00:00
mansession_unlock ( s ) ;
2006-11-22 05:49:06 +00:00
return 0 ;
}
2007-05-17 17:12:23 +00:00
2011-10-11 18:57:47 +00:00
if ( ! allowmultiplelogin
& & ! s - > session - > authenticated
& & ( ! strcasecmp ( action , " Login " )
| | ! strcasecmp ( action , " Challenge " ) ) ) {
user = astman_get_header ( m , " Username " ) ;
2007-05-17 17:12:23 +00:00
if ( check_manager_session_inuse ( user ) ) {
2009-07-11 19:15:03 +00:00
report_session_limit ( s ) ;
2007-05-17 17:12:23 +00:00
sleep ( 1 ) ;
2009-05-12 22:49:13 +00:00
mansession_lock ( s ) ;
2007-05-17 17:12:23 +00:00
astman_send_error ( s , m , " Login Already In Use " ) ;
2009-05-12 22:49:13 +00:00
mansession_unlock ( s ) ;
2007-05-17 17:12:23 +00:00
return - 1 ;
}
}
2011-10-11 18:57:47 +00:00
act_found = action_find ( action ) ;
if ( act_found ) {
/* Found the requested AMI action. */
int acted = 0 ;
2007-08-07 22:13:40 +00:00
2011-10-11 18:57:47 +00:00
if ( ( s - > session - > writeperm & act_found - > authority )
| | act_found - > authority = = 0 ) {
/* We have the authority to execute the action. */
ao2_lock ( act_found ) ;
if ( act_found - > registered & & act_found - > func ) {
ast_debug ( 1 , " Running action '%s' \n " , act_found - > action ) ;
ret = act_found - > func ( s , m ) ;
acted = 1 ;
}
ao2_unlock ( act_found ) ;
}
if ( ! acted ) {
/*
* We did not execute the action because access was denied , it
* was no longer registered , or no action was really registered .
* Complain about it and leave .
2011-05-04 14:40:08 +00:00
*/
report_req_not_allowed ( s , action ) ;
mansession_lock ( s ) ;
astman_send_error ( s , m , " Permission denied " ) ;
mansession_unlock ( s ) ;
}
2011-10-11 18:57:47 +00:00
ao2_t_ref ( act_found , - 1 , " done with found action object " ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-03-04 23:24:56 +00:00
char buf [ 512 ] ;
2011-10-11 18:57:47 +00:00
report_req_bad_format ( s , action ) ;
2007-12-06 15:50:43 +00:00
snprintf ( buf , sizeof ( buf ) , " Invalid/unknown command: %s. Use Action: ListCommands to show available commands. " , action ) ;
2009-05-12 22:49:13 +00:00
mansession_lock ( s ) ;
2007-12-06 15:50:43 +00:00
astman_send_error ( s , m , buf ) ;
2009-05-12 22:49:13 +00:00
mansession_unlock ( s ) ;
2007-01-23 22:09:23 +00:00
}
2009-04-23 20:36:35 +00:00
if ( ret ) {
2006-04-02 19:59:55 +00:00
return ret ;
2009-04-23 20:36:35 +00:00
}
2008-11-26 21:09:58 +00:00
/* Once done with our message, deliver any pending events unless the
requester doesn ' t want them as part of this response .
*/
if ( ast_strlen_zero ( astman_get_header ( m , " SuppressEvents " ) ) ) {
return process_events ( s ) ;
} else {
return ret ;
}
2002-09-12 18:32:42 +00:00
}
2006-10-26 12:47:23 +00:00
/*!
2006-10-18 16:52:13 +00:00
* Read one full line ( including crlf ) from the manager socket .
2007-02-24 19:49:11 +00:00
* \ note \ verbatim
2006-10-26 12:47:23 +00:00
* \ r \ n is the only valid terminator for the line .
* ( Note that , later , ' \0 ' will be considered as the end - of - line marker ,
* so everything between the ' \0 ' and the ' \ r \ n ' will not be used ) .
* Also note that we assume output to have at least " maxlen " space .
2007-02-24 19:49:11 +00:00
* \ endverbatim
2006-10-18 16:52:13 +00:00
*/
2002-09-12 18:32:42 +00:00
static int get_input ( struct mansession * s , char * output )
{
2006-10-26 12:47:23 +00:00
int res , x ;
2009-02-10 21:45:14 +00:00
int maxlen = sizeof ( s - > session - > inbuf ) - 1 ;
char * src = s - > session - > inbuf ;
2011-04-05 14:16:21 +00:00
int timeout = - 1 ;
time_t now ;
2006-10-18 16:52:13 +00:00
2006-10-26 12:47:23 +00:00
/*
* Look for \ r \ n within the buffer . If found , copy to the output
* buffer and return , trimming the \ r \ n ( not used afterwards ) .
*/
2009-02-10 21:45:14 +00:00
for ( x = 0 ; x < s - > session - > inlen ; x + + ) {
2006-12-07 16:42:29 +00:00
int cr ; /* set if we have \r */
2009-04-23 20:36:35 +00:00
if ( src [ x ] = = ' \r ' & & x + 1 < s - > session - > inlen & & src [ x + 1 ] = = ' \n ' ) {
2006-12-07 16:42:29 +00:00
cr = 2 ; /* Found. Update length to include \r\n */
2009-04-23 20:36:35 +00:00
} else if ( src [ x ] = = ' \n ' ) {
2006-12-07 16:42:29 +00:00
cr = 1 ; /* also accept \n only */
2009-04-23 20:36:35 +00:00
} else {
2006-10-26 12:47:23 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
2006-12-07 16:42:29 +00:00
memmove ( output , src , x ) ; /*... but trim \r\n */
output [ x ] = ' \0 ' ; /* terminate the string */
x + = cr ; /* number of bytes used */
2009-02-10 21:45:14 +00:00
s - > session - > inlen - = x ; /* remaining size */
memmove ( src , src + x , s - > session - > inlen ) ; /* remove used bytes */
2006-10-18 16:52:13 +00:00
return 1 ;
2006-10-18 21:41:09 +00:00
}
2009-02-10 21:45:14 +00:00
if ( s - > session - > inlen > = maxlen ) {
2006-10-26 12:47:23 +00:00
/* no crlf found, and buffer full - sorry, too long for us */
2009-02-10 21:45:14 +00:00
ast_log ( LOG_WARNING , " Dumping long line with no return from %s: %s \n " , ast_inet_ntoa ( s - > session - > sin . sin_addr ) , src ) ;
s - > session - > inlen = 0 ;
2006-10-26 12:47:23 +00:00
}
res = 0 ;
while ( res = = 0 ) {
2011-04-05 14:16:21 +00:00
/* calculate a timeout if we are not authenticated */
if ( ! s - > session - > authenticated ) {
if ( time ( & now ) = = - 1 ) {
ast_log ( LOG_ERROR , " error executing time(): %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
timeout = ( authtimeout - ( now - s - > session - > authstart ) ) * 1000 ;
if ( timeout < 0 ) {
/* we have timed out */
return 0 ;
}
}
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-02-10 21:45:14 +00:00
if ( s - > session - > pending_event ) {
s - > session - > pending_event = 0 ;
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2008-04-02 17:36:49 +00:00
return 0 ;
}
2009-02-10 21:45:14 +00:00
s - > session - > waiting_thread = pthread_self ( ) ;
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-04-02 19:59:55 +00:00
2011-04-05 14:16:21 +00:00
res = ast_wait_for_input ( s - > session - > fd , timeout ) ;
2006-04-02 19:59:55 +00:00
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-02-10 21:45:14 +00:00
s - > session - > waiting_thread = AST_PTHREADT_NULL ;
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-10-18 16:52:13 +00:00
}
2006-10-26 12:47:23 +00:00
if ( res < 0 ) {
2006-11-18 22:14:20 +00:00
/* If we get a signal from some other thread (typically because
* there are new events queued ) , return 0 to notify the caller .
*/
2009-04-23 20:36:35 +00:00
if ( errno = = EINTR | | errno = = EAGAIN ) {
2006-10-26 12:47:23 +00:00
return 0 ;
2009-04-23 20:36:35 +00:00
}
2006-10-26 12:47:23 +00:00
ast_log ( LOG_WARNING , " poll() returned error: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
2009-04-23 20:36:35 +00:00
2010-10-12 16:00:06 +00:00
ao2_lock ( s - > session ) ;
2009-02-10 21:45:14 +00:00
res = fread ( src + s - > session - > inlen , 1 , maxlen - s - > session - > inlen , s - > session - > f ) ;
2009-04-23 20:36:35 +00:00
if ( res < 1 ) {
2006-10-26 12:47:23 +00:00
res = - 1 ; /* error return */
2009-04-23 20:36:35 +00:00
} else {
2009-02-10 21:45:14 +00:00
s - > session - > inlen + = res ;
src [ s - > session - > inlen ] = ' \0 ' ;
2006-10-26 12:47:23 +00:00
res = 0 ;
}
2010-10-12 16:00:06 +00:00
ao2_unlock ( s - > session ) ;
2006-10-26 12:47:23 +00:00
return res ;
2002-09-12 18:32:42 +00:00
}
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Read and process an AMI action request .
*
* \ param s AMI session to process action request .
*
* \ retval 0 Retain AMI connection for next command .
* \ retval - 1 Drop AMI connection due to logoff or connection error .
*/
2007-01-05 22:43:18 +00:00
static int do_message ( struct mansession * s )
{
struct message m = { 0 } ;
2009-02-10 21:45:14 +00:00
char header_buf [ sizeof ( s - > session - > inbuf ) ] = { ' \0 ' } ;
2007-01-05 22:43:18 +00:00
int res ;
2011-10-11 18:57:47 +00:00
int idx ;
int hdr_loss ;
2011-04-05 14:16:21 +00:00
time_t now ;
2007-01-05 22:43:18 +00:00
2011-10-11 18:57:47 +00:00
hdr_loss = 0 ;
2007-01-05 22:43:18 +00:00
for ( ; ; ) {
2007-01-15 16:40:48 +00:00
/* Check if any events are pending and do them if needed */
2009-04-23 20:36:35 +00:00
if ( process_events ( s ) ) {
2011-10-11 18:57:47 +00:00
res = - 1 ;
break ;
2009-04-23 20:36:35 +00:00
}
2007-01-05 22:43:18 +00:00
res = get_input ( s , header_buf ) ;
2007-01-12 16:47:20 +00:00
if ( res = = 0 ) {
2011-10-11 18:57:47 +00:00
/* No input line received. */
2011-04-05 14:16:21 +00:00
if ( ! s - > session - > authenticated ) {
2011-10-11 18:57:47 +00:00
if ( time ( & now ) = = - 1 ) {
2011-04-05 14:16:21 +00:00
ast_log ( LOG_ERROR , " error executing time(): %s \n " , strerror ( errno ) ) ;
2011-10-11 18:57:47 +00:00
res = - 1 ;
break ;
2011-04-05 14:16:21 +00:00
}
if ( now - s - > session - > authstart > authtimeout ) {
if ( displayconnects ) {
ast_verb ( 2 , " Client from %s, failed to authenticate in %d seconds \n " , ast_inet_ntoa ( s - > session - > sin . sin_addr ) , authtimeout ) ;
}
2011-10-11 18:57:47 +00:00
res = - 1 ;
break ;
2011-04-05 14:16:21 +00:00
}
}
2007-01-12 16:47:20 +00:00
continue ;
} else if ( res > 0 ) {
2011-10-11 18:57:47 +00:00
/* Input line received. */
2009-04-23 20:36:35 +00:00
if ( ast_strlen_zero ( header_buf ) ) {
2011-10-11 18:57:47 +00:00
if ( hdr_loss ) {
mansession_lock ( s ) ;
astman_send_error ( s , & m , " Too many lines in message or allocation failure " ) ;
mansession_unlock ( s ) ;
res = 0 ;
} else {
res = process_message ( s , & m ) ? - 1 : 0 ;
}
break ;
} else if ( m . hdrcount < ARRAY_LEN ( m . headers ) ) {
m . headers [ m . hdrcount ] = ast_strdup ( header_buf ) ;
if ( ! m . headers [ m . hdrcount ] ) {
/* Allocation failure. */
hdr_loss = 1 ;
} else {
+ + m . hdrcount ;
}
} else {
/* Too many lines in message. */
hdr_loss = 1 ;
2009-04-23 20:36:35 +00:00
}
2007-01-05 22:43:18 +00:00
} else {
2011-10-11 18:57:47 +00:00
/* Input error. */
break ;
2007-01-05 22:43:18 +00:00
}
}
2011-10-11 18:57:47 +00:00
/* Free AMI request headers. */
for ( idx = 0 ; idx < m . hdrcount ; + + idx ) {
ast_free ( ( void * ) m . headers [ idx ] ) ;
}
return res ;
2007-01-05 22:43:18 +00:00
}
2006-10-18 16:52:13 +00:00
/*! \brief The body of the individual manager session.
2006-11-18 22:14:20 +00:00
* Call get_input ( ) to read one line at a time
* ( or be woken up on new events ) , collect the lines in a
* message until found an empty line , and execute the request .
* In any case , deliver events asynchronously through process_events ( )
* ( called from here if no line is available , or at the end of
* process_message ( ) . )
2006-10-18 16:52:13 +00:00
*/
2002-09-12 18:32:42 +00:00
static void * session_do ( void * data )
{
2008-03-12 22:13:18 +00:00
struct ast_tcptls_session_instance * ser = data ;
2010-07-08 22:08:07 +00:00
struct mansession_session * session ;
2009-07-11 19:15:03 +00:00
struct mansession s = {
. tcptls_session = data ,
} ;
2006-12-06 20:46:01 +00:00
int flags ;
2007-01-05 22:43:18 +00:00
int res ;
2010-07-08 22:08:07 +00:00
struct sockaddr_in ser_remote_address_tmp ;
2010-07-01 14:37:37 +00:00
struct protoent * p ;
2006-12-06 20:46:01 +00:00
2011-04-05 14:16:21 +00:00
if ( ast_atomic_fetchadd_int ( & unauth_sessions , + 1 ) > = authlimit ) {
fclose ( ser - > f ) ;
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
goto done ;
}
2010-07-08 22:08:07 +00:00
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
session = build_mansession ( ser_remote_address_tmp ) ;
2009-04-23 20:36:35 +00:00
if ( session = = NULL ) {
2011-04-05 14:16:21 +00:00
fclose ( ser - > f ) ;
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
2006-12-06 20:46:01 +00:00
goto done ;
2009-04-23 20:36:35 +00:00
}
2006-12-06 20:46:01 +00:00
2010-07-01 14:34:31 +00:00
/* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
* This is necessary to prevent delays ( caused by buffering ) as we
* write to the socket in bits and peices . */
2010-07-01 14:37:37 +00:00
p = getprotobyname ( " tcp " ) ;
if ( p ) {
int arg = 1 ;
if ( setsockopt ( ser - > fd , p - > p_proto , TCP_NODELAY , ( char * ) & arg , sizeof ( arg ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to set manager tcp connection to TCP_NODELAY mode: %s \n Some manager actions may be slow to respond. \n " , strerror ( errno ) ) ;
}
} else {
ast_log ( LOG_WARNING , " Failed to set manager tcp connection to TCP_NODELAY, getprotobyname( \" tcp \" ) failed \n Some manager actions may be slow to respond. \n " ) ;
}
2010-06-30 18:48:21 +00:00
2006-12-06 20:46:01 +00:00
flags = fcntl ( ser - > fd , F_GETFL ) ;
2009-04-23 20:36:35 +00:00
if ( ! block_sockets ) { /* make sure socket is non-blocking */
2006-12-06 20:46:01 +00:00
flags | = O_NONBLOCK ;
2009-04-23 20:36:35 +00:00
} else {
2006-12-06 20:46:01 +00:00
flags & = ~ O_NONBLOCK ;
2009-04-23 20:36:35 +00:00
}
2006-12-06 20:46:01 +00:00
fcntl ( ser - > fd , F_SETFL , flags ) ;
2009-05-13 15:02:10 +00:00
ao2_lock ( session ) ;
2008-08-05 16:56:11 +00:00
/* Hook to the tail of the event queue */
2009-02-10 21:45:14 +00:00
session - > last_ev = grab_last ( ) ;
2008-08-05 16:56:11 +00:00
2009-05-12 22:49:13 +00:00
ast_mutex_init ( & s . lock ) ;
2006-12-06 20:46:01 +00:00
/* these fields duplicate those in the 'ser' structure */
2009-04-23 20:36:35 +00:00
session - > fd = s . fd = ser - > fd ;
session - > f = s . f = ser - > f ;
2010-07-08 22:08:07 +00:00
session - > sin = ser_remote_address_tmp ;
2009-02-10 21:45:14 +00:00
s . session = session ;
2006-10-18 21:41:09 +00:00
2009-02-10 21:45:14 +00:00
AST_LIST_HEAD_INIT_NOLOCK ( & session - > datastores ) ;
2008-08-05 16:56:11 +00:00
2011-04-05 14:16:21 +00:00
if ( time ( & session - > authstart ) = = - 1 ) {
ast_log ( LOG_ERROR , " error executing time(): %s; disconnecting client \n " , strerror ( errno ) ) ;
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
ao2_unlock ( session ) ;
session_destroy ( session ) ;
goto done ;
}
2009-05-13 15:02:10 +00:00
ao2_unlock ( session ) ;
2011-04-05 14:16:21 +00:00
2009-02-10 21:45:14 +00:00
astman_append ( & s , " Asterisk Call Manager/%s \r \n " , AMI_VERSION ) ; /* welcome prompt */
2002-09-12 18:32:42 +00:00
for ( ; ; ) {
2011-03-16 19:51:04 +00:00
if ( ( res = do_message ( & s ) ) < 0 | | s . write_error ) {
2006-10-24 17:14:12 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
}
2006-10-18 16:52:13 +00:00
/* session is over, explain why and terminate */
2009-02-10 21:45:14 +00:00
if ( session - > authenticated ) {
2009-04-23 20:36:35 +00:00
if ( manager_displayconnects ( session ) ) {
2009-02-10 21:45:14 +00:00
ast_verb ( 2 , " Manager '%s' logged off from %s \n " , session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
} else {
2011-04-05 14:16:21 +00:00
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
2009-04-23 20:36:35 +00:00
if ( displayconnects ) {
2009-02-10 21:45:14 +00:00
ast_verb ( 2 , " Connect attempt from '%s' unable to authenticate \n " , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
}
2007-12-26 20:49:35 +00:00
2009-05-12 22:49:13 +00:00
session_destroy ( session ) ;
2006-12-06 20:46:01 +00:00
2009-05-12 22:49:13 +00:00
ast_mutex_destroy ( & s . lock ) ;
2006-12-06 20:46:01 +00:00
done :
2008-06-17 21:46:57 +00:00
ao2_ref ( ser , - 1 ) ;
ser = NULL ;
2002-09-12 18:32:42 +00:00
return NULL ;
}
2006-11-28 11:20:39 +00:00
/*! \brief remove at most n_max stale session from the list. */
static void purge_sessions ( int n_max )
{
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2006-11-28 11:20:39 +00:00
time_t now = time ( NULL ) ;
2009-04-23 20:36:35 +00:00
struct ao2_iterator i ;
2006-11-28 11:20:39 +00:00
2009-04-23 20:36:35 +00:00
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) & & n_max > 0 ) {
ao2_lock ( session ) ;
2009-02-10 21:45:14 +00:00
if ( session - > sessiontimeout & & ( now > session - > sessiontimeout ) & & ! session - > inuse ) {
2012-02-14 20:27:16 +00:00
if ( session - > authenticated & & manager_displayconnects ( session ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , " HTTP Manager '%s' timed out from %s \n " ,
2009-02-10 21:45:14 +00:00
session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
2006-11-28 11:20:39 +00:00
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
session_destroy ( session ) ;
n_max - - ;
} else {
ao2_unlock ( session ) ;
2009-05-12 22:49:13 +00:00
unref_mansession ( session ) ;
2006-11-28 11:20:39 +00:00
}
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2006-11-28 11:20:39 +00:00
}
2010-08-27 14:01:21 +00:00
/*! \brief
2006-10-18 17:45:50 +00:00
* events are appended to a queue from where they
* can be dispatched to clients .
*/
2006-04-02 19:59:55 +00:00
static int append_event ( const char * str , int category )
2005-09-28 23:10:14 +00:00
{
2006-10-19 17:26:20 +00:00
struct eventqent * tmp = ast_malloc ( sizeof ( * tmp ) + strlen ( str ) ) ;
2006-10-24 17:14:12 +00:00
static int seq ; /* sequence number */
2006-07-23 02:41:02 +00:00
2009-04-23 20:36:35 +00:00
if ( ! tmp ) {
2006-07-23 02:41:02 +00:00
return - 1 ;
2009-04-23 20:36:35 +00:00
}
2006-07-23 02:41:02 +00:00
2006-10-19 17:26:20 +00:00
/* need to init all fields, because ast_malloc() does not */
2006-10-24 17:14:12 +00:00
tmp - > usecount = 0 ;
2006-07-23 02:41:02 +00:00
tmp - > category = category ;
2006-10-24 17:14:12 +00:00
tmp - > seq = ast_atomic_fetchadd_int ( & seq , 1 ) ;
2010-06-01 16:41:00 +00:00
tmp - > tv = ast_tvnow ( ) ;
AST_RWLIST_NEXT ( tmp , eq_next ) = NULL ;
2006-07-23 02:41:02 +00:00
strcpy ( tmp - > eventdata , str ) ;
2006-10-18 21:41:09 +00:00
2010-06-01 16:41:00 +00:00
AST_RWLIST_WRLOCK ( & all_events ) ;
AST_RWLIST_INSERT_TAIL ( & all_events , tmp , eq_next ) ;
AST_RWLIST_UNLOCK ( & all_events ) ;
2006-10-18 21:41:09 +00:00
2006-07-23 02:41:02 +00:00
return 0 ;
2005-09-28 23:10:14 +00:00
}
2009-11-13 20:42:03 +00:00
AST_THREADSTORAGE ( manager_event_funcbuf ) ;
static void append_channel_vars ( struct ast_str * * pbuf , struct ast_channel * chan )
{
struct manager_channel_variable * var ;
2011-10-11 18:57:47 +00:00
2009-11-13 20:42:03 +00:00
AST_RWLIST_RDLOCK ( & channelvars ) ;
AST_LIST_TRAVERSE ( & channelvars , var , entry ) {
2011-10-11 18:57:47 +00:00
const char * val ;
struct ast_str * res ;
2009-11-13 20:42:03 +00:00
if ( var - > isfunc ) {
2011-10-11 18:57:47 +00:00
res = ast_str_thread_get ( & manager_event_funcbuf , 16 ) ;
if ( res & & ast_func_read2 ( chan , var - > name , & res , 0 ) = = 0 ) {
2009-11-13 20:42:03 +00:00
val = ast_str_buffer ( res ) ;
2011-10-11 18:57:47 +00:00
} else {
val = NULL ;
2009-11-13 20:42:03 +00:00
}
} else {
val = pbx_builtin_getvar_helper ( chan , var - > name ) ;
}
2012-01-09 22:15:50 +00:00
ast_str_append ( pbuf , 0 , " ChanVariable(%s): %s=%s \r \n " , ast_channel_name ( chan ) , var - > name , val ? val : " " ) ;
2009-11-13 20:42:03 +00:00
}
AST_RWLIST_UNLOCK ( & channelvars ) ;
}
2006-12-18 11:28:37 +00:00
/* XXX see if can be moved inside the function */
AST_THREADSTORAGE ( manager_event_buf ) ;
# define MANAGER_EVENT_BUF_INITSIZE 256
2009-11-13 20:42:03 +00:00
int __ast_manager_event_multichan ( int category , const char * event , int chancount , struct
ast_channel * * chans , const char * file , int line , const char * func , const char * fmt , . . . )
2002-09-12 18:32:42 +00:00
{
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2006-11-06 17:05:04 +00:00
struct manager_custom_hook * hook ;
2006-12-18 11:28:37 +00:00
struct ast_str * auth = ast_str_alloca ( 80 ) ;
const char * cat_str ;
2002-09-12 18:32:42 +00:00
va_list ap ;
2006-04-02 19:59:55 +00:00
struct timeval now ;
2006-12-15 23:10:42 +00:00
struct ast_str * buf ;
2009-11-13 20:42:03 +00:00
int i ;
2002-09-12 18:32:42 +00:00
2011-01-19 23:57:27 +00:00
if ( ! ( sessions & & ao2_container_count ( sessions ) ) & & AST_RWLIST_EMPTY ( & manager_hooks ) ) {
2010-01-28 22:37:15 +00:00
return 0 ;
}
2009-04-23 20:36:35 +00:00
if ( ! ( buf = ast_str_thread_get ( & manager_event_buf , MANAGER_EVENT_BUF_INITSIZE ) ) ) {
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
return - 1 ;
2009-04-23 20:36:35 +00:00
}
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
2006-12-18 11:28:37 +00:00
cat_str = authority_to_str ( category , & auth ) ;
2006-12-15 23:10:42 +00:00
ast_str_set ( & buf , 0 ,
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
" Event: %s \r \n Privilege: %s \r \n " ,
2006-12-18 11:28:37 +00:00
event , cat_str ) ;
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
2006-04-02 19:59:55 +00:00
if ( timestampevents ) {
now = ast_tvnow ( ) ;
2006-12-15 23:10:42 +00:00
ast_str_append ( & buf , 0 ,
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
" Timestamp: %ld.%06lu \r \n " ,
2008-05-15 10:56:29 +00:00
( long ) now . tv_sec , ( unsigned long ) now . tv_usec ) ;
2006-04-02 19:59:55 +00:00
}
2006-11-03 18:53:26 +00:00
if ( manager_debug ) {
2006-10-24 17:14:12 +00:00
static int seq ;
2006-12-15 23:10:42 +00:00
ast_str_append ( & buf , 0 ,
2006-10-24 17:14:12 +00:00
" SequenceNumber: %d \r \n " ,
ast_atomic_fetchadd_int ( & seq , 1 ) ) ;
2006-12-15 23:10:42 +00:00
ast_str_append ( & buf , 0 ,
2006-11-03 18:53:26 +00:00
" File: %s \r \n Line: %d \r \n Func: %s \r \n " , file , line , func ) ;
2006-10-24 17:14:12 +00:00
}
Merge team/russell/ast_verbose_threadstorage
- instead of defining a free() wrapper in a bunch of files, define it as
ast_free() in utils.h and remove the copies from all the files.
- centralize and abstract the code used for doing thread storage. The code
lives in threadstorage.h, with one function being implemented in utils.c.
This new API includes generic thread storage as well as special functions
for handling thread local dynamic length string buffers.
- update ast_inet_ntoa() to use the new threadstorage API
- update ast_state2str() to use the new threadstorage API
- update ast_cli() to use the new threadstorage API
- Modify manager_event() to use thread storage. Instead of using a buffer of
4096 characters as the workspace for building the manager event, use a thread
local dynamic string. Now there is no length limitation on the length of the
body of a manager event.
- Significantly simplify the handling of ast_verbose() ...
- Instead of using a static char buffer and a lock to make sure only one
thread can be using ast_verbose() at a time, use a thread local dynamic
string as the workspace for preparing the verbose message. Instead of
locking around the entire function, the only locking done now is when the
message has been built and is being deliviered to the list of registered
verbose message handlers.
- This function was doing a strdup() on every message passed to it and
keeping a queue of the last 200 messages in memory. This has been
completely removed. The only place this was used was that if there were
any messages in the verbose queue when a verbose handler was registered,
all of the messages in the queue would be fed to it. So, I just made sure
that the console verbose handler and the network verbose handler (for
remote asterisk consoles) were registered before any verbose messages.
pbx_gtkconsole and pbx_kdeconsole will now lose a few verbose messages at
startup, but I didn't feel the performance hit of this message queue was
worth saving the initial verbose output for these very rarely used modules.
- I have removed the last three arguments to the verbose handlers, leaving
only the string itself because they aren't needed anymore. For example,
ast_verbose had some logic for telling the verbose handler to add
a newline if the buffer was completely full. Now that the buffer can grow
as needed, this doesn't matter anymore.
- remove unused function, ast_verbose_dmesg() which was to dispatch the
message queue
- Convert the list of verbose handlers to use the linked list macros.
- add missing newline characters to a few ast_verbose() calls
- convert the list of log channels to use the linked list macros in logger.c
- fix close_logger() to close all of the files it opened for logging
- update ast_log() to use a thread local dynamic string for its workspace
for preparing log messages instead of a buffer of size BUFSIZ (8kB on my
system) allocated on the stack. The dynamic string in this case is limited
to only growing to a maximum size of BUFSIZ.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-08-08 06:32:04 +00:00
2006-04-02 19:59:55 +00:00
va_start ( ap , fmt ) ;
2006-12-15 23:10:42 +00:00
ast_str_append_va ( & buf , 0 , fmt , ap ) ;
2006-04-02 19:59:55 +00:00
va_end ( ap ) ;
2009-11-13 20:42:03 +00:00
for ( i = 0 ; i < chancount ; i + + ) {
append_channel_vars ( & buf , chans [ i ] ) ;
}
2006-10-18 21:41:09 +00:00
2006-12-15 23:10:42 +00:00
ast_str_append ( & buf , 0 , " \r \n " ) ;
2006-10-18 21:41:09 +00:00
2008-12-13 08:36:35 +00:00
append_event ( ast_str_buffer ( buf ) , category ) ;
2006-10-20 11:24:43 +00:00
/* Wake up any sleeping sessions */
2009-04-27 15:18:47 +00:00
if ( sessions ) {
struct ao2_iterator i ;
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
if ( session - > waiting_thread ! = AST_PTHREADT_NULL ) {
pthread_kill ( session - > waiting_thread , SIGURG ) ;
} else {
/* We have an event to process, but the mansession is
* not waiting for it . We still need to indicate that there
* is an event waiting so that get_input processes the pending
* event instead of polling .
*/
session - > pending_event = 1 ;
}
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2009-04-23 20:36:35 +00:00
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2002-09-12 18:32:42 +00:00
}
2005-09-30 23:52:04 +00:00
2010-01-28 22:37:15 +00:00
if ( ! AST_RWLIST_EMPTY ( & manager_hooks ) ) {
AST_RWLIST_RDLOCK ( & manager_hooks ) ;
AST_RWLIST_TRAVERSE ( & manager_hooks , hook , list ) {
hook - > helper ( category , event , ast_str_buffer ( buf ) ) ;
}
AST_RWLIST_UNLOCK ( & manager_hooks ) ;
2006-11-06 17:05:04 +00:00
}
2002-09-12 18:32:42 +00:00
return 0 ;
}
2010-08-27 14:01:21 +00:00
/*! \brief
2006-10-18 17:45:50 +00:00
* support functions to register / unregister AMI action handlers ,
*/
2006-10-18 21:41:09 +00:00
int ast_manager_unregister ( char * action )
2005-09-28 23:10:14 +00:00
{
2007-08-07 22:13:40 +00:00
struct manager_action * cur ;
2003-01-28 22:33:41 +00:00
2011-10-11 18:57:47 +00:00
AST_RWLIST_WRLOCK ( & actions ) ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & actions , cur , list ) {
2003-01-28 22:33:41 +00:00
if ( ! strcasecmp ( action , cur - > action ) ) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list ) ;
2006-10-16 09:33:00 +00:00
break ;
2003-01-28 22:33:41 +00:00
}
}
2009-04-10 03:55:27 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2011-10-11 18:57:47 +00:00
if ( cur ) {
/*
* We have removed the action object from the container so we
* are no longer in a hurry .
*/
ao2_lock ( cur ) ;
cur - > registered = 0 ;
ao2_unlock ( cur ) ;
ao2_t_ref ( cur , - 1 , " action object removed from list " ) ;
ast_verb ( 2 , " Manager unregistered action %s \n " , action ) ;
}
2003-01-28 22:33:41 +00:00
return 0 ;
}
2011-07-15 00:23:14 +00:00
static int manager_state_cb ( const char * context , const char * exten , enum ast_extension_states state , void * data )
2003-04-06 23:32:31 +00:00
{
/* Notify managers of change */
2008-03-04 23:24:56 +00:00
char hint [ 512 ] ;
2007-04-09 19:05:40 +00:00
ast_get_hint ( hint , sizeof ( hint ) , NULL , 0 , NULL , context , exten ) ;
manager_event ( EVENT_FLAG_CALL , " ExtensionStatus " , " Exten: %s \r \n Context: %s \r \n Hint: %s \r \n Status: %d \r \n " , exten , context , hint , state ) ;
2003-04-06 23:32:31 +00:00
return 0 ;
}
2004-06-02 20:08:08 +00:00
static int ast_manager_register_struct ( struct manager_action * act )
2003-01-28 22:33:41 +00:00
{
2006-10-16 09:33:00 +00:00
struct manager_action * cur , * prev = NULL ;
2003-01-28 22:33:41 +00:00
2011-10-11 18:57:47 +00:00
AST_RWLIST_WRLOCK ( & actions ) ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_TRAVERSE ( & actions , cur , list ) {
2011-10-11 18:57:47 +00:00
int ret ;
ret = strcasecmp ( cur - > action , act - > action ) ;
2004-06-02 20:08:08 +00:00
if ( ret = = 0 ) {
ast_log ( LOG_WARNING , " Manager: Action '%s' already registered \n " , act - > action ) ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2004-01-14 06:31:18 +00:00
return - 1 ;
}
2007-08-07 22:13:40 +00:00
if ( ret > 0 ) { /* Insert these alphabetically */
prev = cur ;
2006-10-16 09:33:00 +00:00
break ;
2007-08-07 22:13:40 +00:00
}
2004-06-02 20:08:08 +00:00
}
2009-04-09 18:40:01 +00:00
2011-10-11 18:57:47 +00:00
ao2_t_ref ( act , + 1 , " action object added to list " ) ;
act - > registered = 1 ;
2009-04-23 20:36:35 +00:00
if ( prev ) {
2007-08-07 22:13:40 +00:00
AST_RWLIST_INSERT_AFTER ( & actions , prev , act , list ) ;
2009-04-23 20:36:35 +00:00
} else {
2007-08-07 22:13:40 +00:00
AST_RWLIST_INSERT_HEAD ( & actions , act , list ) ;
2009-04-23 20:36:35 +00:00
}
2004-06-02 20:08:08 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , " Manager registered action %s \n " , act - > action ) ;
2007-08-07 22:13:40 +00:00
AST_RWLIST_UNLOCK ( & actions ) ;
2004-06-02 20:08:08 +00:00
return 0 ;
}
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Destroy the registered AMI action object .
*
* \ param obj Object to destroy .
*
* \ return Nothing
*/
static void action_destroy ( void * obj )
{
struct manager_action * doomed = obj ;
if ( doomed - > synopsis ) {
/* The string fields were initialized. */
ast_string_field_free_memory ( doomed ) ;
}
}
2006-10-18 21:41:09 +00:00
/*! \brief register a new command with manager, including online help. This is
2005-11-14 19:00:38 +00:00
the preferred way to register a manager command */
2007-01-05 22:43:18 +00:00
int ast_manager_register2 ( const char * action , int auth , int ( * func ) ( struct mansession * s , const struct message * m ) , const char * synopsis , const char * description )
2004-06-02 20:08:08 +00:00
{
2011-10-11 18:57:47 +00:00
struct manager_action * cur ;
2004-06-02 20:08:08 +00:00
2011-10-11 18:57:47 +00:00
cur = ao2_alloc ( sizeof ( * cur ) , action_destroy ) ;
if ( ! cur ) {
return - 1 ;
}
if ( ast_string_field_init ( cur , 128 ) ) {
ao2_t_ref ( cur , - 1 , " action object creation failed " ) ;
2009-05-22 17:52:35 +00:00
return - 1 ;
}
2004-06-02 20:08:08 +00:00
cur - > action = action ;
2003-01-28 22:33:41 +00:00
cur - > authority = auth ;
cur - > func = func ;
2009-05-22 17:52:35 +00:00
# ifdef AST_XML_DOCS
if ( ast_strlen_zero ( synopsis ) & & ast_strlen_zero ( description ) ) {
2011-10-11 18:57:47 +00:00
char * tmpxml ;
2011-10-10 14:16:27 +00:00
tmpxml = ast_xmldoc_build_synopsis ( " manager " , action , NULL ) ;
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , synopsis , tmpxml ) ;
ast_free ( tmpxml ) ;
2011-10-10 14:16:27 +00:00
tmpxml = ast_xmldoc_build_syntax ( " manager " , action , NULL ) ;
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , syntax , tmpxml ) ;
ast_free ( tmpxml ) ;
2011-10-10 14:16:27 +00:00
tmpxml = ast_xmldoc_build_description ( " manager " , action , NULL ) ;
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , description , tmpxml ) ;
ast_free ( tmpxml ) ;
2003-01-28 22:33:41 +00:00
2011-10-10 14:16:27 +00:00
tmpxml = ast_xmldoc_build_seealso ( " manager " , action , NULL ) ;
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , seealso , tmpxml ) ;
ast_free ( tmpxml ) ;
2011-10-10 14:16:27 +00:00
tmpxml = ast_xmldoc_build_arguments ( " manager " , action , NULL ) ;
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , arguments , tmpxml ) ;
ast_free ( tmpxml ) ;
cur - > docsrc = AST_XML_DOC ;
2011-10-11 18:57:47 +00:00
} else
2009-05-22 17:52:35 +00:00
# endif
2011-10-11 18:57:47 +00:00
{
2009-05-22 17:52:35 +00:00
ast_string_field_set ( cur , synopsis , synopsis ) ;
ast_string_field_set ( cur , description , description ) ;
# ifdef AST_XML_DOCS
cur - > docsrc = AST_STATIC_DOC ;
# endif
2011-10-11 18:57:47 +00:00
}
2009-04-09 18:40:01 +00:00
if ( ast_manager_register_struct ( cur ) ) {
2011-10-11 18:57:47 +00:00
ao2_t_ref ( cur , - 1 , " action object registration failed " ) ;
2009-04-09 18:40:01 +00:00
return - 1 ;
}
2003-01-28 22:33:41 +00:00
2011-10-11 18:57:47 +00:00
ao2_t_ref ( cur , - 1 , " action object registration successful " ) ;
2003-01-28 22:33:41 +00:00
return 0 ;
}
2005-11-14 19:00:38 +00:00
/*! @}
END Doxygen group */
2003-01-28 22:33:41 +00:00
2006-10-18 17:45:50 +00:00
/*
* The following are support functions for AMI - over - http .
* The common entry point is generic_http_callback ( ) ,
* which extracts HTTP header and URI fields and reformats
* them into AMI messages , locates a proper session
* ( using the mansession_id Cookie or GET variable ) ,
* and calls process_message ( ) as for regular AMI clients .
* When done , the output ( which goes to a temporary file )
* is read back into a buffer and reformatted as desired ,
* then fed back to the client over the original socket .
*/
2006-10-18 21:30:21 +00:00
enum output_format {
FORMAT_RAW ,
FORMAT_HTML ,
FORMAT_XML ,
} ;
2009-05-21 21:13:09 +00:00
static const char * const contenttype [ ] = {
2006-10-18 21:30:21 +00:00
[ FORMAT_RAW ] = " plain " ,
[ FORMAT_HTML ] = " html " ,
[ FORMAT_XML ] = " xml " ,
} ;
2006-11-28 09:27:37 +00:00
/*!
* locate an http session in the list . The search key ( ident ) is
* the value of the mansession_id cookie ( 0 is not valid and means
* a session on the AMI socket ) .
*/
2009-02-10 21:45:14 +00:00
static struct mansession_session * find_session ( uint32_t ident , int incinuse )
2006-04-01 08:49:54 +00:00
{
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2009-04-23 20:36:35 +00:00
struct ao2_iterator i ;
2006-08-21 19:42:29 +00:00
2009-04-23 20:36:35 +00:00
if ( ident = = 0 ) {
2006-10-18 21:30:21 +00:00
return NULL ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 21:30:21 +00:00
2009-04-23 20:36:35 +00:00
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
2009-02-10 21:45:14 +00:00
if ( session - > managerid = = ident & & ! session - > needdestroy ) {
ast_atomic_fetchadd_int ( & session - > inuse , incinuse ? 1 : 0 ) ;
2006-04-01 08:49:54 +00:00
break ;
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2009-04-23 20:36:35 +00:00
return session ;
}
/*!
* locate an http session in the list .
* The search keys ( nonce ) and ( username ) is value from received
* " Authorization " http header .
* As well as in find_session ( ) function , the value of the nonce can ' t be zero .
* ( 0 meansi , that the session used for AMI socket connection ) .
* Flag ( stale ) is set , if client used valid , but old , nonce value .
*
*/
static struct mansession_session * find_session_by_nonce ( const char * username , unsigned long nonce , int * stale )
{
struct mansession_session * session ;
struct ao2_iterator i ;
if ( nonce = = 0 | | username = = NULL | | stale = = NULL ) {
return NULL ;
2006-04-01 08:49:54 +00:00
}
2006-08-21 19:42:29 +00:00
2009-04-23 20:36:35 +00:00
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
if ( ! strcasecmp ( session - > username , username ) & & session - > managerid = = nonce ) {
* stale = 0 ;
break ;
} else if ( ! strcasecmp ( session - > username , username ) & & session - > oldnonce = = nonce ) {
* stale = 1 ;
break ;
}
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2009-02-10 21:45:14 +00:00
return session ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
int astman_is_authed ( uint32_t ident )
2008-05-23 21:19:42 +00:00
{
int authed ;
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2008-05-23 21:19:42 +00:00
2009-02-10 21:45:14 +00:00
if ( ! ( session = find_session ( ident , 0 ) ) )
2008-05-23 21:19:42 +00:00
return 0 ;
2009-02-10 21:45:14 +00:00
authed = ( session - > authenticated ! = 0 ) ;
2008-05-23 21:19:42 +00:00
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
2009-05-12 22:49:13 +00:00
unref_mansession ( session ) ;
2008-05-23 21:19:42 +00:00
return authed ;
}
2008-04-23 18:01:00 +00:00
int astman_verify_session_readpermissions ( uint32_t ident , int perm )
2007-04-06 21:16:38 +00:00
{
int result = 0 ;
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2009-04-23 20:36:35 +00:00
struct ao2_iterator i ;
2007-04-06 21:16:38 +00:00
2009-04-23 20:36:35 +00:00
if ( ident = = 0 ) {
return 0 ;
}
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
if ( ( session - > managerid = = ident ) & & ( session - > readperm & perm ) ) {
2007-04-06 21:16:38 +00:00
result = 1 ;
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2007-04-06 21:16:38 +00:00
break ;
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2007-04-06 21:16:38 +00:00
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2007-04-06 21:16:38 +00:00
return result ;
}
2008-04-23 18:01:00 +00:00
int astman_verify_session_writepermissions ( uint32_t ident , int perm )
2007-04-06 21:16:38 +00:00
{
int result = 0 ;
2009-02-10 21:45:14 +00:00
struct mansession_session * session ;
2009-04-23 20:36:35 +00:00
struct ao2_iterator i ;
2007-04-06 21:16:38 +00:00
2009-04-23 20:36:35 +00:00
if ( ident = = 0 ) {
return 0 ;
}
i = ao2_iterator_init ( sessions , 0 ) ;
while ( ( session = ao2_iterator_next ( & i ) ) ) {
ao2_lock ( session ) ;
2009-02-10 21:45:14 +00:00
if ( ( session - > managerid = = ident ) & & ( session - > writeperm & perm ) ) {
2007-04-06 21:16:38 +00:00
result = 1 ;
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2007-04-06 21:16:38 +00:00
break ;
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
unref_mansession ( session ) ;
2007-04-06 21:16:38 +00:00
}
2009-11-04 08:22:00 +00:00
ao2_iterator_destroy ( & i ) ;
2007-04-06 21:16:38 +00:00
return result ;
}
2006-10-18 17:45:50 +00:00
/*
* convert to xml with various conversion :
* mode & 1 - > lowercase ;
* mode & 2 - > replace non - alphanumeric chars with underscore
*/
2006-12-16 09:33:31 +00:00
static void xml_copy_escape ( struct ast_str * * out , const char * src , int mode )
{
/* store in a local buffer to avoid calling ast_str_append too often */
char buf [ 256 ] ;
char * dst = buf ;
int space = sizeof ( buf ) ;
/* repeat until done and nothing to flush */
for ( ; * src | | dst ! = buf ; src + + ) {
if ( * src = = ' \0 ' | | space < 10 ) { /* flush */
* dst + + = ' \0 ' ;
ast_str_append ( out , 0 , " %s " , buf ) ;
dst = buf ;
space = sizeof ( buf ) ;
2009-04-23 20:36:35 +00:00
if ( * src = = ' \0 ' ) {
2006-12-16 09:33:31 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2006-12-16 09:33:31 +00:00
}
2009-04-23 20:36:35 +00:00
2006-10-18 17:45:50 +00:00
if ( ( mode & 2 ) & & ! isalnum ( * src ) ) {
2006-12-16 09:33:31 +00:00
* dst + + = ' _ ' ;
space - - ;
2006-10-18 17:45:50 +00:00
continue ;
}
switch ( * src ) {
case ' < ' :
2006-12-16 09:33:31 +00:00
strcpy ( dst , " < " ) ;
dst + = 4 ;
space - = 4 ;
2006-10-18 17:45:50 +00:00
break ;
case ' > ' :
2006-12-16 09:33:31 +00:00
strcpy ( dst , " > " ) ;
dst + = 4 ;
space - = 4 ;
2006-10-18 17:45:50 +00:00
break ;
case ' \" ' :
2006-12-16 09:33:31 +00:00
strcpy ( dst , " " " ) ;
dst + = 6 ;
space - = 6 ;
2006-10-18 17:45:50 +00:00
break ;
case ' \' ' :
2006-12-16 09:33:31 +00:00
strcpy ( dst , " ' " ) ;
dst + = 6 ;
space - = 6 ;
2006-10-18 17:45:50 +00:00
break ;
case ' & ' :
2006-12-16 09:33:31 +00:00
strcpy ( dst , " & " ) ;
dst + = 5 ;
space - = 5 ;
2006-10-18 21:41:09 +00:00
break ;
2006-10-18 17:45:50 +00:00
default :
2006-12-16 09:33:31 +00:00
* dst + + = mode ? tolower ( * src ) : * src ;
space - - ;
2006-10-18 17:45:50 +00:00
}
}
}
2007-11-23 17:56:56 +00:00
struct variable_count {
char * varname ;
int count ;
} ;
static int variable_count_hash_fn ( const void * vvc , const int flags )
{
const struct variable_count * vc = vvc ;
2009-04-23 20:36:35 +00:00
return ast_str_hash ( vc - > varname ) ;
2007-11-23 17:56:56 +00:00
}
2008-11-25 01:01:49 +00:00
static int variable_count_cmp_fn ( void * obj , void * vstr , int flags )
2007-11-23 17:56:56 +00:00
{
/* Due to the simplicity of struct variable_count, it makes no difference
* if you pass in objects or strings , the same operation applies . This is
* due to the fact that the hash occurs on the first element , which means
* the address of both the struct and the string are exactly the same . */
struct variable_count * vc = obj ;
char * str = vstr ;
2008-08-29 17:47:17 +00:00
return ! strcmp ( vc - > varname , str ) ? CMP_MATCH | CMP_STOP : 0 ;
2007-11-23 17:56:56 +00:00
}
2006-10-18 17:45:50 +00:00
/*! \brief Convert the input into XML or HTML.
* The input is supposed to be a sequence of lines of the form
* Name : value
* optionally followed by a blob of unformatted text .
* A blank line is a section separator . Basically , this is a
* mixture of the format of Manager Interface and CLI commands .
* The unformatted text is considered as a single value of a field
* named ' Opaque - data ' .
*
* At the moment the output format is the following ( but it may
* change depending on future requirements so don ' t count too
* much on it when writing applications ) :
*
2006-10-18 21:41:09 +00:00
* General : the unformatted text is used as a value of
2006-10-18 17:45:50 +00:00
* XML output : to be completed
2009-04-23 20:36:35 +00:00
*
2007-06-07 23:07:25 +00:00
* \ verbatim
2006-10-18 17:45:50 +00:00
* Each section is within < response type = " object " id = " xxx " >
* where xxx is taken from ajaxdest variable or defaults to unknown
* Each row is reported as an attribute Name = " value " of an XML
* entity named from the variable ajaxobjtype , default to " generic "
2007-06-07 23:07:25 +00:00
* \ endverbatim
2006-10-18 17:45:50 +00:00
*
* HTML output :
* each Name - value pair is output as a single row of a two - column table .
* Sections ( blank lines in the input ) are separated by a < HR >
*
*/
2009-04-23 20:36:35 +00:00
static void xml_translate ( struct ast_str * * out , char * in , struct ast_variable * get_vars , enum output_format format )
2006-10-18 17:45:50 +00:00
{
struct ast_variable * v ;
2007-11-14 13:18:40 +00:00
const char * dest = NULL ;
2006-12-16 09:33:31 +00:00
char * var , * val ;
2007-11-14 13:18:40 +00:00
const char * objtype = NULL ;
2006-10-18 17:45:50 +00:00
int in_data = 0 ; /* parsing data */
int inobj = 0 ;
int xml = ( format = = FORMAT_XML ) ;
2007-11-23 17:56:56 +00:00
struct variable_count * vc = NULL ;
struct ao2_container * vco = NULL ;
2006-10-18 17:45:50 +00:00
2009-04-23 20:36:35 +00:00
if ( xml ) {
/* dest and objtype need only for XML format */
for ( v = get_vars ; v ; v = v - > next ) {
if ( ! strcasecmp ( v - > name , " ajaxdest " ) ) {
dest = v - > value ;
} else if ( ! strcasecmp ( v - > name , " ajaxobjtype " ) ) {
objtype = v - > value ;
}
}
if ( ast_strlen_zero ( dest ) ) {
dest = " unknown " ;
}
if ( ast_strlen_zero ( objtype ) ) {
objtype = " generic " ;
}
2006-10-18 17:45:50 +00:00
}
2007-11-23 17:56:56 +00:00
2006-10-18 17:45:50 +00:00
/* we want to stop when we find an empty line */
while ( in & & * in ) {
val = strsep ( & in , " \r \n " ) ; /* mark start and end of line */
2009-04-23 20:36:35 +00:00
if ( in & & * in = = ' \n ' ) { /* remove trailing \n if any */
2006-10-19 17:07:08 +00:00
in + + ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 17:45:50 +00:00
ast_trim_blanks ( val ) ;
2007-11-23 17:56:56 +00:00
ast_debug ( 5 , " inobj %d in_data %d line <%s> \n " , inobj , in_data , val ) ;
2006-10-18 17:45:50 +00:00
if ( ast_strlen_zero ( val ) ) {
2009-04-23 20:36:35 +00:00
/* empty line */
if ( in_data ) {
/* close data in Opaque mode */
2006-12-16 09:33:31 +00:00
ast_str_append ( out , 0 , xml ? " ' " : " </td></tr> \n " ) ;
2006-10-18 17:45:50 +00:00
in_data = 0 ;
}
2009-04-23 20:36:35 +00:00
2008-04-22 15:46:01 +00:00
if ( inobj ) {
2009-04-23 20:36:35 +00:00
/* close block */
2008-04-22 15:46:01 +00:00
ast_str_append ( out , 0 , xml ? " /></response> \n " :
" <tr><td colspan= \" 2 \" ><hr></td></tr> \r \n " ) ;
inobj = 0 ;
ao2_ref ( vco , - 1 ) ;
vco = NULL ;
}
2006-10-18 17:45:50 +00:00
continue ;
}
2007-11-23 17:56:56 +00:00
2006-10-18 17:45:50 +00:00
if ( ! inobj ) {
2009-04-23 20:36:35 +00:00
/* start new block */
if ( xml ) {
2006-12-16 09:33:31 +00:00
ast_str_append ( out , 0 , " <response type='object' id='%s'><%s " , dest , objtype ) ;
2009-04-23 20:36:35 +00:00
}
2007-11-23 17:56:56 +00:00
vco = ao2_container_alloc ( 37 , variable_count_hash_fn , variable_count_cmp_fn ) ;
2006-10-18 17:45:50 +00:00
inobj = 1 ;
}
2007-11-23 17:56:56 +00:00
2009-04-23 20:36:35 +00:00
if ( in_data ) {
2011-11-11 21:33:54 +00:00
/* Process data field in Opaque mode. This is a
* followup , so we re - add line feeds . */
2009-04-23 20:36:35 +00:00
ast_str_append ( out , 0 , xml ? " \n " : " <br> \n " ) ;
2011-11-11 21:33:54 +00:00
xml_copy_escape ( out , val , 0 ) ; /* data field */
2009-04-23 20:36:35 +00:00
continue ;
}
/* We expect "Name: value" line here */
var = strsep ( & val , " : " ) ;
if ( val ) {
/* found the field name */
val = ast_skip_blanks ( val ) ;
ast_trim_blanks ( var ) ;
} else {
/* field name not found, switch to opaque mode */
val = var ;
var = " Opaque-data " ;
in_data = 1 ;
}
ast_str_append ( out , 0 , xml ? " " : " <tr><td> " ) ;
if ( ( vc = ao2_find ( vco , var , 0 ) ) ) {
vc - > count + + ;
} else {
/* Create a new entry for this one */
vc = ao2_alloc ( sizeof ( * vc ) , NULL ) ;
vc - > varname = var ;
vc - > count = 1 ;
ao2_link ( vco , vc ) ;
}
xml_copy_escape ( out , var , xml ? 1 | 2 : 0 ) ; /* data name */
if ( vc - > count > 1 ) {
ast_str_append ( out , 0 , " -%d " , vc - > count ) ;
2006-10-18 17:45:50 +00:00
}
2009-04-23 20:36:35 +00:00
ao2_ref ( vc , - 1 ) ;
ast_str_append ( out , 0 , xml ? " =' " : " </td><td> " ) ;
2006-12-16 09:33:31 +00:00
xml_copy_escape ( out , val , 0 ) ; /* data field */
2011-11-11 21:33:54 +00:00
if ( ! in_data | | ! * in ) {
ast_str_append ( out , 0 , xml ? " ' " : " </td></tr> \n " ) ;
}
2006-10-18 17:45:50 +00:00
}
2009-04-23 20:36:35 +00:00
2007-11-23 17:56:56 +00:00
if ( inobj ) {
2006-12-16 09:33:31 +00:00
ast_str_append ( out , 0 , xml ? " /></response> \n " :
2006-10-18 17:45:50 +00:00
" <tr><td colspan= \" 2 \" ><hr></td></tr> \r \n " ) ;
2007-11-23 17:56:56 +00:00
ao2_ref ( vco , - 1 ) ;
}
2006-10-18 17:45:50 +00:00
}
2006-04-01 08:49:54 +00:00
2011-07-12 23:02:31 +00:00
static void process_output ( struct mansession * s , struct ast_str * * out , struct ast_variable * params , enum output_format format )
2011-06-15 15:33:57 +00:00
{
char * buf ;
size_t l ;
if ( ! s - > f )
return ;
/* Ensure buffer is NULL-terminated */
fprintf ( s - > f , " %c " , 0 ) ;
fflush ( s - > f ) ;
if ( ( l = ftell ( s - > f ) ) ) {
if ( MAP_FAILED = = ( buf = mmap ( NULL , l , PROT_READ | PROT_WRITE , MAP_PRIVATE , s - > fd , 0 ) ) ) {
ast_log ( LOG_WARNING , " mmap failed. Manager output was not processed \n " ) ;
} else {
if ( format = = FORMAT_XML | | format = = FORMAT_HTML ) {
2011-07-12 23:02:31 +00:00
xml_translate ( out , buf , params , format ) ;
2011-06-15 15:33:57 +00:00
} else {
2011-07-12 23:02:31 +00:00
ast_str_append ( out , 0 , " %s " , buf ) ;
2011-06-15 15:33:57 +00:00
}
munmap ( buf , l ) ;
}
} else if ( format = = FORMAT_XML | | format = = FORMAT_HTML ) {
2011-07-12 23:02:31 +00:00
xml_translate ( out , " " , params , format ) ;
2011-06-15 15:33:57 +00:00
}
2012-03-05 19:06:46 +00:00
if ( s - > f ) {
if ( fclose ( s - > f ) ) {
ast_log ( LOG_ERROR , " fclose() failed: %s \n " , strerror ( errno ) ) ;
}
s - > f = NULL ;
s - > fd = - 1 ;
} else if ( s - > fd ! = - 1 ) {
if ( close ( s - > fd ) ) {
ast_log ( LOG_ERROR , " close() failed: %s \n " , strerror ( errno ) ) ;
}
s - > fd = - 1 ;
} else {
ast_log ( LOG_ERROR , " process output attempted to close file/file descriptor on mansession without a valid file or file descriptor. \n " ) ;
}
2011-06-15 15:33:57 +00:00
}
2009-04-23 20:36:35 +00:00
static int generic_http_callback ( struct ast_tcptls_session_instance * ser ,
enum ast_http_method method ,
enum output_format format ,
struct sockaddr_in * remote_address , const char * uri ,
struct ast_variable * get_params ,
struct ast_variable * headers )
2006-04-01 08:49:54 +00:00
{
2009-08-31 21:45:00 +00:00
struct mansession s = { . session = NULL , . tcptls_session = ser } ;
2009-02-10 21:45:14 +00:00
struct mansession_session * session = NULL ;
2008-04-23 18:01:00 +00:00
uint32_t ident = 0 ;
2006-04-01 08:49:54 +00:00
int blastaway = 0 ;
2009-04-23 20:36:35 +00:00
struct ast_variable * v , * cookies , * params = get_params ;
2006-10-18 21:36:20 +00:00
char template [ ] = " /tmp/ast-http-XXXXXX " ; /* template for temporary file */
2009-04-23 20:36:35 +00:00
struct ast_str * http_header = NULL , * out = NULL ;
2007-01-05 22:43:18 +00:00
struct message m = { 0 } ;
2011-10-11 18:57:47 +00:00
unsigned int idx ;
2007-01-05 22:43:18 +00:00
size_t hdrlen ;
2006-04-04 19:03:12 +00:00
2009-04-23 20:36:35 +00:00
if ( method ! = AST_HTTP_GET & & method ! = AST_HTTP_HEAD & & method ! = AST_HTTP_POST ) {
ast_http_error ( ser , 501 , " Not Implemented " , " Attempt to use unimplemented / unsupported method " ) ;
return - 1 ;
}
cookies = ast_http_get_cookies ( headers ) ;
for ( v = cookies ; v ; v = v - > next ) {
2006-04-01 08:49:54 +00:00
if ( ! strcasecmp ( v - > name , " mansession_id " ) ) {
2009-08-10 19:20:57 +00:00
sscanf ( v - > value , " %30x " , & ident ) ;
2006-04-01 08:49:54 +00:00
break ;
}
}
2009-04-23 20:36:35 +00:00
if ( cookies ) {
ast_variables_destroy ( cookies ) ;
}
2006-10-18 21:30:21 +00:00
2009-02-10 21:45:14 +00:00
if ( ! ( session = find_session ( ident , 1 ) ) ) {
2009-04-23 20:36:35 +00:00
/**/
2006-10-18 21:30:21 +00:00
/* Create new session.
* While it is not in the list we don ' t need any locking
*/
2009-04-23 20:36:35 +00:00
if ( ! ( session = build_mansession ( * remote_address ) ) ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (out of memory) \n " ) ;
return - 1 ;
2006-07-04 00:16:33 +00:00
}
2009-04-23 20:36:35 +00:00
ao2_lock ( session ) ;
2009-02-10 21:45:14 +00:00
session - > sin = * remote_address ;
session - > fd = - 1 ;
session - > waiting_thread = AST_PTHREADT_NULL ;
session - > send_events = 0 ;
session - > inuse = 1 ;
2008-02-27 18:20:35 +00:00
/*!\note There is approximately a 1 in 1.8E19 chance that the following
* calculation will produce 0 , which is an invalid ID , but due to the
* properties of the rand ( ) function ( and the constantcy of s ) , that
* won ' t happen twice in a row .
*/
2009-03-27 18:04:43 +00:00
while ( ( session - > managerid = ast_random ( ) ^ ( unsigned long ) session ) = = 0 ) ;
2009-02-10 21:45:14 +00:00
session - > last_ev = grab_last ( ) ;
AST_LIST_HEAD_INIT_NOLOCK ( & session - > datastores ) ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
ao2_unlock ( session ) ;
2006-04-01 08:49:54 +00:00
2009-04-23 20:36:35 +00:00
http_header = ast_str_create ( 128 ) ;
out = ast_str_create ( 2048 ) ;
2006-10-18 13:42:14 +00:00
2009-05-12 22:49:13 +00:00
ast_mutex_init ( & s . lock ) ;
2009-04-23 20:36:35 +00:00
if ( http_header = = NULL | | out = = NULL ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (ast_str_create() out of memory) \n " ) ;
2006-12-16 09:33:31 +00:00
goto generic_callback_out ;
2006-10-18 13:42:14 +00:00
}
2007-01-05 22:43:18 +00:00
2009-04-23 20:36:35 +00:00
s . session = session ;
2009-02-10 21:45:14 +00:00
s . fd = mkstemp ( template ) ; /* create a temporary file for command output */
2007-01-05 22:43:18 +00:00
unlink ( template ) ;
2009-04-23 20:36:35 +00:00
if ( s . fd < = - 1 ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (mkstemp failed) \n " ) ;
goto generic_callback_out ;
}
2009-02-10 21:45:14 +00:00
s . f = fdopen ( s . fd , " w+ " ) ;
2009-04-23 20:36:35 +00:00
if ( ! s . f ) {
ast_log ( LOG_WARNING , " HTTP Manager, fdopen failed: %s! \n " , strerror ( errno ) ) ;
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (fdopen failed) \n " ) ;
close ( s . fd ) ;
goto generic_callback_out ;
}
if ( method = = AST_HTTP_POST ) {
params = ast_http_get_post_vars ( ser , headers ) ;
}
2007-01-05 22:43:18 +00:00
2011-10-11 18:57:47 +00:00
for ( v = params ; v & & m . hdrcount < ARRAY_LEN ( m . headers ) ; v = v - > next ) {
2007-01-05 22:53:38 +00:00
hdrlen = strlen ( v - > name ) + strlen ( v - > value ) + 3 ;
2011-10-11 18:57:47 +00:00
m . headers [ m . hdrcount ] = ast_malloc ( hdrlen ) ;
if ( ! m . headers [ m . hdrcount ] ) {
/* Allocation failure */
continue ;
}
2007-01-05 22:53:38 +00:00
snprintf ( ( char * ) m . headers [ m . hdrcount ] , hdrlen , " %s: %s " , v - > name , v - > value ) ;
2011-01-19 23:07:22 +00:00
ast_debug ( 1 , " HTTP Manager add header %s \n " , m . headers [ m . hdrcount ] ) ;
2011-10-11 18:57:47 +00:00
+ + m . hdrcount ;
2007-01-05 22:43:18 +00:00
}
2009-02-10 21:45:14 +00:00
if ( process_message ( & s , & m ) ) {
if ( session - > authenticated ) {
if ( manager_displayconnects ( session ) ) {
ast_verb ( 2 , " HTTP Manager '%s' logged off from %s \n " , session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
2008-05-20 18:07:24 +00:00
}
2007-01-05 22:43:18 +00:00
} else {
2008-05-20 18:07:24 +00:00
if ( displayconnects ) {
2009-02-10 21:45:14 +00:00
ast_verb ( 2 , " HTTP Connect attempt from '%s' unable to authenticate \n " , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
2008-05-20 18:07:24 +00:00
}
2007-01-05 22:43:18 +00:00
}
2009-02-10 21:45:14 +00:00
session - > needdestroy = 1 ;
2007-01-05 22:43:18 +00:00
}
2011-10-11 18:57:47 +00:00
/* Free request headers. */
for ( idx = 0 ; idx < m . hdrcount ; + + idx ) {
ast_free ( ( void * ) m . headers [ idx ] ) ;
m . headers [ idx ] = NULL ;
}
2009-04-23 20:36:35 +00:00
ast_str_append ( & http_header , 0 ,
" Content-type: text/%s \r \n "
" Cache-Control: no-cache; \r \n "
2010-05-17 15:14:22 +00:00
" Set-Cookie: mansession_id= \" %08x \" ; Version=1; Max-Age=%d \r \n "
2009-04-23 20:36:35 +00:00
" Pragma: SuppressEvents \r \n " ,
contenttype [ format ] ,
session - > managerid , httptimeout ) ;
2006-10-18 13:42:14 +00:00
if ( format = = FORMAT_XML ) {
2006-12-16 09:33:31 +00:00
ast_str_append ( & out , 0 , " <ajax-response> \n " ) ;
2006-10-18 13:42:14 +00:00
} else if ( format = = FORMAT_HTML ) {
2008-05-20 18:07:24 +00:00
/*
* When handling AMI - over - HTTP in HTML format , we provide a simple form for
* debugging purposes . This HTML code should not be here , we
* should read from some config file . . .
*/
2006-10-18 13:42:14 +00:00
2006-10-18 05:31:54 +00:00
# define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s< / td>< / tr>\r\n"
# define TEST_STRING \
2009-04-23 20:36:35 +00:00
" <form action= \" manager \" method= \" post \" > \n \
2008-05-20 18:07:24 +00:00
Action : < select name = \ " action \" > \n \
< option value = \ " \" >-----></option> \n \
< option value = \ " login \" >login</option> \n \
< option value = \ " command \" >Command</option> \n \
< option value = \ " waitevent \" >waitevent</option> \n \
< option value = \ " listcommands \" >listcommands</option> \n \
< / select > \ n \
or < input name = \ " action \" ><br/> \n \
CLI Command < input name = \ " command \" ><br> \n \
user < input name = \ " username \" > pass <input type= \" password \" name= \" secret \" ><br> \n \
< input type = \ " submit \" > \n </form> \n "
2006-10-18 13:42:14 +00:00
2007-01-05 22:52:16 +00:00
ast_str_append ( & out , 0 , " <title>Asterisk™ Manager Interface</title> " ) ;
2006-12-16 09:33:31 +00:00
ast_str_append ( & out , 0 , " <body bgcolor= \" #ffffff \" ><table align=center bgcolor= \" #f1f1f1 \" width= \" 500 \" > \r \n " ) ;
ast_str_append ( & out , 0 , ROW_FMT , " <h1>Manager Tester</h1> " ) ;
ast_str_append ( & out , 0 , ROW_FMT , TEST_STRING ) ;
2006-10-18 13:42:14 +00:00
}
2006-10-18 21:36:20 +00:00
2011-07-12 23:02:31 +00:00
process_output ( & s , & out , params , format ) ;
2006-10-17 17:41:59 +00:00
2006-10-18 13:42:14 +00:00
if ( format = = FORMAT_XML ) {
2006-12-16 09:33:31 +00:00
ast_str_append ( & out , 0 , " </ajax-response> \n " ) ;
2009-04-23 20:36:35 +00:00
} else if ( format = = FORMAT_HTML ) {
2006-12-16 09:33:31 +00:00
ast_str_append ( & out , 0 , " </table></body> \r \n " ) ;
2009-04-23 20:36:35 +00:00
}
2006-10-18 13:42:14 +00:00
2009-04-23 20:36:35 +00:00
ao2_lock ( session ) ;
2006-10-18 21:30:21 +00:00
/* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
2009-02-10 21:45:14 +00:00
session - > sessiontimeout = time ( NULL ) + ( ( session - > authenticated | | httptimeout < 5 ) ? httptimeout : 5 ) ;
2007-01-05 22:43:18 +00:00
2009-02-10 21:45:14 +00:00
if ( session - > needdestroy ) {
if ( session - > inuse = = 1 ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Need destroy, doing it now! \n " ) ;
2006-04-01 08:49:54 +00:00
blastaway = 1 ;
} else {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Need destroy, but can't do it yet! \n " ) ;
2009-04-23 20:36:35 +00:00
if ( session - > waiting_thread ! = AST_PTHREADT_NULL ) {
2009-02-10 21:45:14 +00:00
pthread_kill ( session - > waiting_thread , SIGURG ) ;
2009-04-23 20:36:35 +00:00
}
2009-02-10 21:45:14 +00:00
session - > inuse - - ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
} else {
2009-02-10 21:45:14 +00:00
session - > inuse - - ;
2009-04-23 20:36:35 +00:00
}
ao2_unlock ( session ) ;
ast_http_send ( ser , method , 200 , NULL , http_header , out , 0 , 0 ) ;
http_header = out = NULL ;
2006-10-18 21:41:09 +00:00
2006-07-04 00:16:33 +00:00
generic_callback_out :
2009-05-12 22:49:13 +00:00
ast_mutex_destroy ( & s . lock ) ;
2009-04-23 20:36:35 +00:00
/* Clear resource */
if ( method = = AST_HTTP_POST & & params ) {
ast_variables_destroy ( params ) ;
}
if ( http_header ) {
ast_free ( http_header ) ;
}
if ( out ) {
ast_free ( out ) ;
}
2009-05-12 22:49:13 +00:00
if ( session & & blastaway ) {
2009-04-23 20:36:35 +00:00
session_destroy ( session ) ;
2009-05-12 22:49:13 +00:00
} else if ( session & & session - > f ) {
fclose ( session - > f ) ;
session - > f = NULL ;
2009-04-23 20:36:35 +00:00
}
2009-05-12 22:49:13 +00:00
2009-04-23 20:36:35 +00:00
return 0 ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
static int auth_http_callback ( struct ast_tcptls_session_instance * ser ,
enum ast_http_method method ,
enum output_format format ,
struct sockaddr_in * remote_address , const char * uri ,
struct ast_variable * get_params ,
struct ast_variable * headers )
2006-04-01 08:49:54 +00:00
{
2009-04-23 20:36:35 +00:00
struct mansession_session * session = NULL ;
2011-05-05 02:34:29 +00:00
struct mansession s = { . session = NULL , . tcptls_session = ser } ;
2009-04-23 20:36:35 +00:00
struct ast_variable * v , * params = get_params ;
char template [ ] = " /tmp/ast-http-XXXXXX " ; /* template for temporary file */
struct ast_str * http_header = NULL , * out = NULL ;
size_t result_size = 512 ;
struct message m = { 0 } ;
2011-10-11 18:57:47 +00:00
unsigned int idx ;
2009-04-23 20:36:35 +00:00
size_t hdrlen ;
time_t time_now = time ( NULL ) ;
unsigned long nonce = 0 , nc ;
struct ast_http_digest d = { NULL , } ;
struct ast_manager_user * user = NULL ;
int stale = 0 ;
char resp_hash [ 256 ] = " " ;
/* Cache for user data */
char u_username [ 80 ] ;
int u_readperm ;
int u_writeperm ;
int u_writetimeout ;
int u_displayconnects ;
2010-07-19 14:17:16 +00:00
struct ast_sockaddr addr ;
2009-04-23 20:36:35 +00:00
if ( method ! = AST_HTTP_GET & & method ! = AST_HTTP_HEAD & & method ! = AST_HTTP_POST ) {
ast_http_error ( ser , 501 , " Not Implemented " , " Attempt to use unimplemented / unsupported method " ) ;
return - 1 ;
}
/* Find "Authorization: " header */
for ( v = headers ; v ; v = v - > next ) {
if ( ! strcasecmp ( v - > name , " Authorization " ) ) {
break ;
}
}
if ( ! v | | ast_strlen_zero ( v - > value ) ) {
goto out_401 ; /* Authorization Header not present - send auth request */
}
/* Digest found - parse */
if ( ast_string_field_init ( & d , 128 ) ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (out of memory) \n " ) ;
return - 1 ;
}
if ( ast_parse_digest ( v - > value , & d , 0 , 1 ) ) {
/* Error in Digest - send new one */
nonce = 0 ;
goto out_401 ;
}
2009-08-10 19:20:57 +00:00
if ( sscanf ( d . nonce , " %30lx " , & nonce ) ! = 1 ) {
2009-04-23 20:36:35 +00:00
ast_log ( LOG_WARNING , " Received incorrect nonce in Digest <%s> \n " , d . nonce ) ;
nonce = 0 ;
goto out_401 ;
}
AST_RWLIST_WRLOCK ( & users ) ;
user = get_manager_by_name_locked ( d . username ) ;
if ( ! user ) {
AST_RWLIST_UNLOCK ( & users ) ;
ast_log ( LOG_NOTICE , " %s tried to authenticate with nonexistent user '%s' \n " , ast_inet_ntoa ( remote_address - > sin_addr ) , d . username ) ;
nonce = 0 ;
goto out_401 ;
}
2010-07-19 14:17:16 +00:00
ast_sockaddr_from_sin ( & addr , remote_address ) ;
2009-04-23 20:36:35 +00:00
/* --- We have User for this auth, now check ACL */
2010-07-19 14:17:16 +00:00
if ( user - > ha & & ! ast_apply_ha ( user - > ha , & addr ) ) {
2009-04-23 20:36:35 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
ast_log ( LOG_NOTICE , " %s failed to pass IP ACL as '%s' \n " , ast_inet_ntoa ( remote_address - > sin_addr ) , d . username ) ;
ast_http_error ( ser , 403 , " Permission denied " , " Permission denied \n " ) ;
return - 1 ;
}
/* --- We have auth, so check it */
/* compute the expected response to compare with what we received */
{
char a2 [ 256 ] ;
char a2_hash [ 256 ] ;
char resp [ 256 ] ;
/* XXX Now request method are hardcoded in A2 */
snprintf ( a2 , sizeof ( a2 ) , " %s:%s " , ast_get_http_method ( method ) , d . uri ) ;
ast_md5_hash ( a2_hash , a2 ) ;
if ( d . qop ) {
/* RFC 2617 */
snprintf ( resp , sizeof ( resp ) , " %s:%08lx:%s:%s:auth:%s " , user - > a1_hash , nonce , d . nc , d . cnonce , a2_hash ) ;
} else {
/* RFC 2069 */
snprintf ( resp , sizeof ( resp ) , " %s:%08lx:%s " , user - > a1_hash , nonce , a2_hash ) ;
}
ast_md5_hash ( resp_hash , resp ) ;
}
if ( ! d . nonce | | strncasecmp ( d . response , resp_hash , strlen ( resp_hash ) ) ) {
/* Something was wrong, so give the client to try with a new challenge */
AST_RWLIST_UNLOCK ( & users ) ;
nonce = 0 ;
goto out_401 ;
}
/*
* User are pass Digest authentication .
* Now , cache the user data and unlock user list .
*/
ast_copy_string ( u_username , user - > username , sizeof ( u_username ) ) ;
u_readperm = user - > readperm ;
u_writeperm = user - > writeperm ;
u_displayconnects = user - > displayconnects ;
u_writetimeout = user - > writetimeout ;
AST_RWLIST_UNLOCK ( & users ) ;
if ( ! ( session = find_session_by_nonce ( d . username , nonce , & stale ) ) ) {
/*
* Create new session .
* While it is not in the list we don ' t need any locking
*/
if ( ! ( session = build_mansession ( * remote_address ) ) ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (out of memory) \n " ) ;
return - 1 ;
}
ao2_lock ( session ) ;
ast_copy_string ( session - > username , u_username , sizeof ( session - > username ) ) ;
session - > managerid = nonce ;
session - > last_ev = grab_last ( ) ;
AST_LIST_HEAD_INIT_NOLOCK ( & session - > datastores ) ;
session - > readperm = u_readperm ;
session - > writeperm = u_writeperm ;
session - > writetimeout = u_writetimeout ;
if ( u_displayconnects ) {
ast_verb ( 2 , " HTTP Manager '%s' logged in from %s \n " , session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
}
session - > noncetime = session - > sessionstart = time_now ;
session - > authenticated = 1 ;
} else if ( stale ) {
/*
* Session found , but nonce is stale .
*
* This could be because an old request ( w / old nonce ) arrived .
*
* This may be as the result of http proxy usage ( separate delay or
* multipath ) or in a situation where a page was refreshed too quickly
* ( seen in Firefox ) .
*
* In this situation , we repeat the 401 auth with the current nonce
* value .
*/
nonce = session - > managerid ;
ao2_unlock ( session ) ;
stale = 1 ;
goto out_401 ;
} else {
2009-08-10 19:20:57 +00:00
sscanf ( d . nc , " %30lx " , & nc ) ;
2009-04-23 20:36:35 +00:00
if ( session - > nc > = nc | | ( ( time_now - session - > noncetime ) > 62 ) ) {
/*
* Nonce time expired ( > 2 minutes ) or something wrong with nonce
* counter .
*
* Create new nonce key and resend Digest auth request . Old nonce
* is saved for stale checking . . .
*/
session - > nc = 0 ; /* Reset nonce counter */
session - > oldnonce = session - > managerid ;
nonce = session - > managerid = ast_random ( ) ;
session - > noncetime = time_now ;
ao2_unlock ( session ) ;
stale = 1 ;
goto out_401 ;
} else {
session - > nc = nc ; /* All OK, save nonce counter */
}
}
/* Reset session timeout. */
session - > sessiontimeout = time ( NULL ) + ( httptimeout > 5 ? httptimeout : 5 ) ;
ao2_unlock ( session ) ;
2009-05-12 22:49:13 +00:00
ast_mutex_init ( & s . lock ) ;
2009-04-23 20:36:35 +00:00
s . session = session ;
s . fd = mkstemp ( template ) ; /* create a temporary file for command output */
unlink ( template ) ;
if ( s . fd < = - 1 ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (mkstemp failed) \n " ) ;
goto auth_callback_out ;
}
s . f = fdopen ( s . fd , " w+ " ) ;
if ( ! s . f ) {
ast_log ( LOG_WARNING , " HTTP Manager, fdopen failed: %s! \n " , strerror ( errno ) ) ;
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (fdopen failed) \n " ) ;
close ( s . fd ) ;
goto auth_callback_out ;
}
if ( method = = AST_HTTP_POST ) {
params = ast_http_get_post_vars ( ser , headers ) ;
}
2011-10-11 18:57:47 +00:00
for ( v = params ; v & & m . hdrcount < ARRAY_LEN ( m . headers ) ; v = v - > next ) {
2009-04-23 20:36:35 +00:00
hdrlen = strlen ( v - > name ) + strlen ( v - > value ) + 3 ;
2011-10-11 18:57:47 +00:00
m . headers [ m . hdrcount ] = ast_malloc ( hdrlen ) ;
if ( ! m . headers [ m . hdrcount ] ) {
/* Allocation failure */
continue ;
}
2009-04-23 20:36:35 +00:00
snprintf ( ( char * ) m . headers [ m . hdrcount ] , hdrlen , " %s: %s " , v - > name , v - > value ) ;
ast_verb ( 4 , " HTTP Manager add header %s \n " , m . headers [ m . hdrcount ] ) ;
2011-10-11 18:57:47 +00:00
+ + m . hdrcount ;
2009-04-23 20:36:35 +00:00
}
if ( process_message ( & s , & m ) ) {
if ( u_displayconnects ) {
ast_verb ( 2 , " HTTP Manager '%s' logged off from %s \n " , session - > username , ast_inet_ntoa ( session - > sin . sin_addr ) ) ;
}
session - > needdestroy = 1 ;
}
2011-10-11 18:57:47 +00:00
/* Free request headers. */
for ( idx = 0 ; idx < m . hdrcount ; + + idx ) {
ast_free ( ( void * ) m . headers [ idx ] ) ;
m . headers [ idx ] = NULL ;
}
2009-04-23 20:36:35 +00:00
if ( s . f ) {
result_size = ftell ( s . f ) ; /* Calculate approx. size of result */
}
http_header = ast_str_create ( 80 ) ;
out = ast_str_create ( result_size * 2 + 512 ) ;
if ( http_header = = NULL | | out = = NULL ) {
ast_http_error ( ser , 500 , " Server Error " , " Internal Server Error (ast_str_create() out of memory) \n " ) ;
goto auth_callback_out ;
}
2011-03-10 16:09:09 +00:00
ast_str_append ( & http_header , 0 , " Content-type: text/%s \r \n " , contenttype [ format ] ) ;
2009-04-23 20:36:35 +00:00
if ( format = = FORMAT_XML ) {
ast_str_append ( & out , 0 , " <ajax-response> \n " ) ;
} else if ( format = = FORMAT_HTML ) {
ast_str_append ( & out , 0 ,
" <!DOCTYPE HTML PUBLIC \" -//IETF//DTD HTML 2.0//EN \" > \r \n "
" <html><head> \r \n "
" <title>Asterisk™ Manager Interface</title> \r \n "
" </head><body style= \" background-color: #ffffff; \" > \r \n "
" <form method= \" POST \" > \r \n "
" <table align= \" center \" style= \" background-color: #f1f1f1; \" width= \" 500 \" > \r \n "
" <tr><th colspan= \" 2 \" style= \" background-color: #f1f1ff; \" ><h1>Manager Tester</h1></th></tr> \r \n "
" <tr><th colspan= \" 2 \" style= \" background-color: #f1f1ff; \" >Action: <input name= \" action \" /> Cmd: <input name= \" command \" /><br> "
" <input type= \" submit \" value= \" Send request \" /></th></tr> \r \n " ) ;
}
2011-07-12 23:02:31 +00:00
process_output ( & s , & out , params , format ) ;
2009-04-23 20:36:35 +00:00
if ( format = = FORMAT_XML ) {
ast_str_append ( & out , 0 , " </ajax-response> \n " ) ;
} else if ( format = = FORMAT_HTML ) {
ast_str_append ( & out , 0 , " </table></form></body></html> \r \n " ) ;
}
ast_http_send ( ser , method , 200 , NULL , http_header , out , 0 , 0 ) ;
http_header = out = NULL ;
auth_callback_out :
2009-05-12 22:49:13 +00:00
ast_mutex_destroy ( & s . lock ) ;
2009-04-23 20:36:35 +00:00
/* Clear resources and unlock manager session */
if ( method = = AST_HTTP_POST & & params ) {
ast_variables_destroy ( params ) ;
}
ast_free ( http_header ) ;
ast_free ( out ) ;
ao2_lock ( session ) ;
if ( session - > f ) {
fclose ( session - > f ) ;
}
session - > f = NULL ;
session - > fd = - 1 ;
ao2_unlock ( session ) ;
if ( session - > needdestroy ) {
ast_debug ( 1 , " Need destroy, doing it now! \n " ) ;
session_destroy ( session ) ;
}
ast_string_field_free_memory ( & d ) ;
return 0 ;
out_401 :
if ( ! nonce ) {
nonce = ast_random ( ) ;
}
ast_http_auth ( ser , global_realm , nonce , nonce , stale , NULL ) ;
ast_string_field_free_memory ( & d ) ;
return 0 ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
static int manager_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
2006-04-01 08:49:54 +00:00
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = generic_http_callback ( ser , method , FORMAT_HTML , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2006-04-01 08:49:54 +00:00
}
2009-04-23 20:36:35 +00:00
static int mxml_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
2006-04-01 08:49:54 +00:00
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = generic_http_callback ( ser , method , FORMAT_XML , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2009-04-23 20:36:35 +00:00
}
static int rawman_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = generic_http_callback ( ser , method , FORMAT_RAW , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2006-04-01 08:49:54 +00:00
}
2009-06-15 17:34:30 +00:00
static struct ast_http_uri rawmanuri = {
2006-04-01 08:49:54 +00:00
. description = " Raw HTTP Manager Event Interface " ,
. uri = " rawman " ,
. callback = rawman_http_callback ,
2008-04-02 15:25:48 +00:00
. data = NULL ,
. key = __FILE__ ,
2006-04-01 08:49:54 +00:00
} ;
2009-06-15 17:34:30 +00:00
static struct ast_http_uri manageruri = {
2006-04-01 08:49:54 +00:00
. description = " HTML Manager Event Interface " ,
. uri = " manager " ,
. callback = manager_http_callback ,
2008-04-02 15:25:48 +00:00
. data = NULL ,
. key = __FILE__ ,
2006-04-01 08:49:54 +00:00
} ;
2009-06-15 17:34:30 +00:00
static struct ast_http_uri managerxmluri = {
2006-04-01 08:49:54 +00:00
. description = " XML Manager Event Interface " ,
. uri = " mxml " ,
. callback = mxml_http_callback ,
2009-04-23 20:36:35 +00:00
. data = NULL ,
. key = __FILE__ ,
} ;
/* Callback with Digest authentication */
static int auth_manager_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = auth_http_callback ( ser , method , FORMAT_HTML , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2009-04-23 20:36:35 +00:00
}
static int auth_mxml_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = auth_http_callback ( ser , method , FORMAT_XML , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2009-04-23 20:36:35 +00:00
}
static int auth_rawman_http_callback ( struct ast_tcptls_session_instance * ser , const struct ast_http_uri * urih , const char * uri , enum ast_http_method method , struct ast_variable * get_params , struct ast_variable * headers )
{
2010-07-08 22:08:07 +00:00
int retval ;
struct sockaddr_in ser_remote_address_tmp ;
ast_sockaddr_to_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
retval = auth_http_callback ( ser , method , FORMAT_RAW , & ser_remote_address_tmp , uri , get_params , headers ) ;
ast_sockaddr_from_sin ( & ser - > remote_address , & ser_remote_address_tmp ) ;
return retval ;
2009-04-23 20:36:35 +00:00
}
2009-06-15 17:34:30 +00:00
static struct ast_http_uri arawmanuri = {
2009-04-23 20:36:35 +00:00
. description = " Raw HTTP Manager Event Interface w/Digest authentication " ,
. uri = " arawman " ,
. has_subtree = 0 ,
. callback = auth_rawman_http_callback ,
. data = NULL ,
. key = __FILE__ ,
} ;
2009-06-15 17:34:30 +00:00
static struct ast_http_uri amanageruri = {
2009-04-23 20:36:35 +00:00
. description = " HTML Manager Event Interface w/Digest authentication " ,
. uri = " amanager " ,
. has_subtree = 0 ,
. callback = auth_manager_http_callback ,
. data = NULL ,
. key = __FILE__ ,
} ;
2009-06-15 17:34:30 +00:00
static struct ast_http_uri amanagerxmluri = {
2009-04-23 20:36:35 +00:00
. description = " XML Manager Event Interface w/Digest authentication " ,
. uri = " amxml " ,
. has_subtree = 0 ,
. callback = auth_mxml_http_callback ,
2008-04-02 15:25:48 +00:00
. data = NULL ,
. key = __FILE__ ,
2006-04-01 08:49:54 +00:00
} ;
2003-01-28 22:33:41 +00:00
static int registered = 0 ;
2006-04-01 08:49:54 +00:00
static int webregged = 0 ;
2003-01-28 22:33:41 +00:00
2006-12-06 20:46:01 +00:00
/*! \brief cleanup code called at each iteration of server_root,
* guaranteed to happen every 5 seconds at most
*/
static void purge_old_stuff ( void * data )
{
purge_sessions ( 1 ) ;
purge_events ( ) ;
}
2009-06-15 17:34:30 +00:00
static struct ast_tls_config ami_tls_cfg ;
2008-10-19 19:11:28 +00:00
static struct ast_tcptls_session_args ami_desc = {
2008-02-03 17:40:48 +00:00
. accept_fd = - 1 ,
. master = AST_PTHREADT_NULL ,
2009-04-23 20:36:35 +00:00
. tls_cfg = NULL ,
2008-02-03 17:40:48 +00:00
. poll_timeout = 5000 , /* wake up every 5 seconds */
2006-12-06 20:46:01 +00:00
. periodic_fn = purge_old_stuff ,
2008-02-03 17:40:48 +00:00
. name = " AMI server " ,
2008-03-04 22:23:21 +00:00
. accept_fn = ast_tcptls_server_root , /* thread doing the accept() */
2008-02-03 17:40:48 +00:00
. worker_fn = session_do , /* thread handling the session */
2006-12-06 20:46:01 +00:00
} ;
2008-10-19 19:11:28 +00:00
static struct ast_tcptls_session_args amis_desc = {
2008-02-03 17:40:48 +00:00
. accept_fd = - 1 ,
. master = AST_PTHREADT_NULL ,
2009-04-23 20:36:35 +00:00
. tls_cfg = & ami_tls_cfg ,
2008-02-03 17:40:48 +00:00
. poll_timeout = - 1 , /* the other does the periodic cleanup */
. name = " AMI TLS server " ,
2008-03-04 22:23:21 +00:00
. accept_fn = ast_tcptls_server_root , /* thread doing the accept() */
2008-02-03 17:40:48 +00:00
. worker_fn = session_do , /* thread handling the session */
2006-12-07 16:42:29 +00:00
} ;
2010-05-05 00:44:37 +00:00
/*! \brief CLI command manager show settings */
static char * handle_manager_show_settings ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
switch ( cmd ) {
case CLI_INIT :
e - > command = " manager show settings " ;
e - > usage =
" Usage: manager show settings \n "
" Provides detailed list of the configuration of the Manager. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
# define FORMAT " %-25.25s %-15.15s\n"
# define FORMAT2 " %-25.25s %-15d\n"
if ( a - > argc ! = 3 ) {
return CLI_SHOWUSAGE ;
}
ast_cli ( a - > fd , " \n Global Settings: \n " ) ;
ast_cli ( a - > fd , " ---------------- \n " ) ;
ast_cli ( a - > fd , FORMAT , " Manager (AMI): " , AST_CLI_YESNO ( manager_enabled ) ) ;
ast_cli ( a - > fd , FORMAT , " Web Manager (AMI/HTTP): " , AST_CLI_YESNO ( webmanager_enabled ) ) ;
2010-11-02 20:47:37 +00:00
ast_cli ( a - > fd , FORMAT , " TCP Bindaddress: " , manager_enabled ! = 0 ? ast_sockaddr_stringify ( & ami_desc . local_address ) : " Disabled " ) ;
2010-05-05 00:44:37 +00:00
ast_cli ( a - > fd , FORMAT2 , " HTTP Timeout (minutes): " , httptimeout ) ;
ast_cli ( a - > fd , FORMAT , " TLS Enable: " , AST_CLI_YESNO ( ami_tls_cfg . enabled ) ) ;
2010-11-02 20:47:37 +00:00
ast_cli ( a - > fd , FORMAT , " TLS Bindaddress: " , ami_tls_cfg . enabled ! = 0 ? ast_sockaddr_stringify ( & amis_desc . local_address ) : " Disabled " ) ;
2010-05-05 00:44:37 +00:00
ast_cli ( a - > fd , FORMAT , " TLS Certfile: " , ami_tls_cfg . certfile ) ;
ast_cli ( a - > fd , FORMAT , " TLS Privatekey: " , ami_tls_cfg . pvtfile ) ;
ast_cli ( a - > fd , FORMAT , " TLS Cipher: " , ami_tls_cfg . cipher ) ;
ast_cli ( a - > fd , FORMAT , " Allow multiple login: " , AST_CLI_YESNO ( allowmultiplelogin ) ) ;
ast_cli ( a - > fd , FORMAT , " Display connects: " , AST_CLI_YESNO ( displayconnects ) ) ;
ast_cli ( a - > fd , FORMAT , " Timestamp events: " , AST_CLI_YESNO ( timestampevents ) ) ;
ast_cli ( a - > fd , FORMAT , " Channel vars: " , S_OR ( manager_channelvars , " " ) ) ;
ast_cli ( a - > fd , FORMAT , " Debug: " , AST_CLI_YESNO ( manager_debug ) ) ;
ast_cli ( a - > fd , FORMAT , " Block sockets: " , AST_CLI_YESNO ( block_sockets ) ) ;
# undef FORMAT
# undef FORMAT2
return CLI_SUCCESS ;
}
static struct ast_cli_entry cli_manager [ ] = {
AST_CLI_DEFINE ( handle_showmancmd , " Show a manager interface command " ) ,
AST_CLI_DEFINE ( handle_showmancmds , " List manager interface commands " ) ,
AST_CLI_DEFINE ( handle_showmanconn , " List connected manager interface users " ) ,
AST_CLI_DEFINE ( handle_showmaneventq , " List manager interface queued events " ) ,
AST_CLI_DEFINE ( handle_showmanagers , " List configured manager users " ) ,
AST_CLI_DEFINE ( handle_showmanager , " Display information on a specific manager user " ) ,
AST_CLI_DEFINE ( handle_mandebug , " Show, enable, disable debugging of the manager code " ) ,
AST_CLI_DEFINE ( handle_manager_reload , " Reload manager configurations " ) ,
AST_CLI_DEFINE ( handle_manager_show_settings , " Show manager global settings " ) ,
} ;
2011-10-11 18:57:47 +00:00
/*!
* \ internal
* \ brief Load the config channelvars variable .
*
* \ param var Config variable to load .
*
* \ return Nothing
*/
static void load_channelvars ( struct ast_variable * var )
{
struct manager_channel_variable * mcv ;
char * remaining = ast_strdupa ( var - > value ) ;
char * next ;
ast_free ( manager_channelvars ) ;
manager_channelvars = ast_strdup ( var - > value ) ;
/*
* XXX TODO : To allow dialplan functions to have more than one
* parameter requires eliminating the ' | ' as a separator so we
* could use AST_STANDARD_APP_ARGS ( ) to separate items .
*/
free_channelvars ( ) ;
AST_RWLIST_WRLOCK ( & channelvars ) ;
while ( ( next = strsep ( & remaining , " ,| " ) ) ) {
if ( ! ( mcv = ast_calloc ( 1 , sizeof ( * mcv ) + strlen ( next ) + 1 ) ) ) {
break ;
}
strcpy ( mcv - > name , next ) ; /* SAFE */
if ( strchr ( next , ' ( ' ) ) {
mcv - > isfunc = 1 ;
}
AST_RWLIST_INSERT_TAIL ( & channelvars , mcv , entry ) ;
}
AST_RWLIST_UNLOCK ( & channelvars ) ;
}
2007-08-16 21:09:46 +00:00
static int __init_manager ( int reload )
2002-09-12 18:32:42 +00:00
{
2007-12-16 13:32:48 +00:00
struct ast_config * ucfg = NULL , * cfg = NULL ;
2006-09-20 20:40:39 +00:00
const char * val ;
char * cat = NULL ;
2006-04-01 08:49:54 +00:00
int newhttptimeout = 60 ;
2006-09-19 22:01:23 +00:00
struct ast_manager_user * user = NULL ;
2006-12-12 10:35:10 +00:00
struct ast_variable * var ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 } ;
2009-04-23 20:36:35 +00:00
char a1 [ 256 ] ;
char a1_hash [ 256 ] ;
2010-07-08 22:08:07 +00:00
struct sockaddr_in ami_desc_local_address_tmp = { 0 , } ;
struct sockaddr_in amis_desc_local_address_tmp = { 0 , } ;
2012-02-02 18:55:05 +00:00
int tls_was_enabled = 0 ;
2006-09-19 22:01:23 +00:00
2008-03-26 00:02:31 +00:00
manager_enabled = 0 ;
2003-01-28 22:33:41 +00:00
if ( ! registered ) {
/* Register default actions */
2009-05-22 17:52:35 +00:00
ast_manager_register_xml ( " Ping " , 0 , action_ping ) ;
ast_manager_register_xml ( " Events " , 0 , action_events ) ;
ast_manager_register_xml ( " Logoff " , 0 , action_logoff ) ;
ast_manager_register_xml ( " Login " , 0 , action_login ) ;
ast_manager_register_xml ( " Challenge " , 0 , action_challenge ) ;
ast_manager_register_xml ( " Hangup " , EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL , action_hangup ) ;
ast_manager_register_xml ( " Status " , EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING , action_status ) ;
ast_manager_register_xml ( " Setvar " , EVENT_FLAG_CALL , action_setvar ) ;
ast_manager_register_xml ( " Getvar " , EVENT_FLAG_CALL | EVENT_FLAG_REPORTING , action_getvar ) ;
ast_manager_register_xml ( " GetConfig " , EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG , action_getconfig ) ;
ast_manager_register_xml ( " GetConfigJSON " , EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG , action_getconfigjson ) ;
ast_manager_register_xml ( " UpdateConfig " , EVENT_FLAG_CONFIG , action_updateconfig ) ;
ast_manager_register_xml ( " CreateConfig " , EVENT_FLAG_CONFIG , action_createconfig ) ;
ast_manager_register_xml ( " ListCategories " , EVENT_FLAG_CONFIG , action_listcategories ) ;
ast_manager_register_xml ( " Redirect " , EVENT_FLAG_CALL , action_redirect ) ;
ast_manager_register_xml ( " Atxfer " , EVENT_FLAG_CALL , action_atxfer ) ;
ast_manager_register_xml ( " Originate " , EVENT_FLAG_ORIGINATE , action_originate ) ;
ast_manager_register_xml ( " Command " , EVENT_FLAG_COMMAND , action_command ) ;
ast_manager_register_xml ( " ExtensionState " , EVENT_FLAG_CALL | EVENT_FLAG_REPORTING , action_extensionstate ) ;
ast_manager_register_xml ( " AbsoluteTimeout " , EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL , action_timeout ) ;
ast_manager_register_xml ( " MailboxStatus " , EVENT_FLAG_CALL | EVENT_FLAG_REPORTING , action_mailboxstatus ) ;
ast_manager_register_xml ( " MailboxCount " , EVENT_FLAG_CALL | EVENT_FLAG_REPORTING , action_mailboxcount ) ;
ast_manager_register_xml ( " ListCommands " , 0 , action_listcommands ) ;
ast_manager_register_xml ( " SendText " , EVENT_FLAG_CALL , action_sendtext ) ;
ast_manager_register_xml ( " UserEvent " , EVENT_FLAG_USER , action_userevent ) ;
ast_manager_register_xml ( " WaitEvent " , 0 , action_waitevent ) ;
ast_manager_register_xml ( " CoreSettings " , EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING , action_coresettings ) ;
ast_manager_register_xml ( " CoreStatus " , EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING , action_corestatus ) ;
ast_manager_register_xml ( " Reload " , EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM , action_reload ) ;
ast_manager_register_xml ( " CoreShowChannels " , EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING , action_coreshowchannels ) ;
ast_manager_register_xml ( " ModuleLoad " , EVENT_FLAG_SYSTEM , manager_moduleload ) ;
ast_manager_register_xml ( " ModuleCheck " , EVENT_FLAG_SYSTEM , manager_modulecheck ) ;
Generic Advice of Charge.
Asterisk Generic AOC Representation
- Generic AOC encode/decode routines.
(Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame)
- AST_CONTROL_AOC frame type to represent generic encoded AOC data
- Manager events for AOC-S, AOC-D, and AOC-E messages
Asterisk App Support
- app_dial AOC-S pass-through support on call setup
- app_queue AOC-S pass-through support on call setup
AOC Unit Tests
- AOC Unit Tests for encode/decode routines
- AOC Unit Test for manager event representation.
SIP AOC Support
- Pass-through of generic AOC-D and AOC-E messages to snom phones via the
snom AOC specification.
- Creation of chan_sip page3 flags for the addition of the new
'snom_aoc_enabled' sip.conf option.
IAX AOC Support
- Natively supports AOC pass-through through the use of the new
AST_CONTROL_AOC frame type
DAHDI AOC Support
- ETSI PRI full AOC Pass-through support
- 'aoc_enable' chan_dahdi.conf option for independently enabling
pass-through of AOC-S, AOC-D, AOC-E.
- 'aoce_delayhangup' option for retrieving AOC-E on disconnect.
- DAHDI A() dial string option for requesting AOC services.
example usage:
;requests AOC-S, AOC-D, and AOC-E on call setup
exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e))
Review: https://reviewboard.asterisk.org/r/552/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@267096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-06-02 18:10:15 +00:00
ast_manager_register_xml ( " AOCMessage " , EVENT_FLAG_AOC , action_aocmessage ) ;
2011-07-05 16:46:17 +00:00
ast_manager_register_xml ( " Filter " , EVENT_FLAG_SYSTEM , action_filter ) ;
2002-09-12 18:32:42 +00:00
2008-12-05 10:31:25 +00:00
ast_cli_register_multiple ( cli_manager , ARRAY_LEN ( cli_manager ) ) ;
2003-04-06 23:32:31 +00:00
ast_extension_state_add ( NULL , NULL , manager_state_cb , NULL ) ;
2003-01-28 22:33:41 +00:00
registered = 1 ;
2006-04-02 19:59:55 +00:00
/* Append placeholder event so master_eventq never runs dry */
append_event ( " Event: Placeholder \r \n \r \n " , 0 ) ;
2003-01-28 22:33:41 +00:00
}
2009-04-23 20:36:35 +00:00
if ( ( cfg = ast_config_load2 ( " manager.conf " , " manager " , config_flags ) ) = = CONFIG_STATUS_FILEUNCHANGED ) {
2007-08-16 21:09:46 +00:00
return 0 ;
2009-04-23 20:36:35 +00:00
}
2007-08-16 21:09:46 +00:00
2005-01-05 06:24:59 +00:00
displayconnects = 1 ;
2010-04-13 18:10:30 +00:00
broken_events_action = 0 ;
2011-04-05 14:16:21 +00:00
authtimeout = 30 ;
authlimit = 50 ;
2011-09-19 12:20:44 +00:00
manager_debug = 0 ; /* Debug disabled by default */
2009-08-27 21:26:37 +00:00
if ( ! cfg | | cfg = = CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_NOTICE , " Unable to open AMI configuration manager.conf, or configuration is invalid. Asterisk management interface (AMI) disabled. \n " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2006-12-07 16:42:29 +00:00
/* default values */
2009-04-23 20:36:35 +00:00
ast_copy_string ( global_realm , S_OR ( ast_config_AST_SYSTEM_NAME , DEFAULT_REALM ) , sizeof ( global_realm ) ) ;
2012-02-02 18:55:05 +00:00
ast_sockaddr_setnull ( & ami_desc . local_address ) ;
ast_sockaddr_setnull ( & amis_desc . local_address ) ;
ami_desc_local_address_tmp . sin_family = AF_INET ;
amis_desc_local_address_tmp . sin_family = AF_INET ;
2010-07-08 22:08:07 +00:00
ami_desc_local_address_tmp . sin_port = htons ( DEFAULT_MANAGER_PORT ) ;
2006-12-07 16:42:29 +00:00
2012-02-02 18:55:05 +00:00
tls_was_enabled = ( reload & & ami_tls_cfg . enabled ) ;
2006-12-07 16:42:29 +00:00
ami_tls_cfg . enabled = 0 ;
2009-04-23 20:36:35 +00:00
if ( ami_tls_cfg . certfile ) {
2007-06-06 21:20:11 +00:00
ast_free ( ami_tls_cfg . certfile ) ;
2009-04-23 20:36:35 +00:00
}
2006-12-07 16:42:29 +00:00
ami_tls_cfg . certfile = ast_strdup ( AST_CERTFILE ) ;
2009-04-24 21:22:31 +00:00
if ( ami_tls_cfg . pvtfile ) {
ast_free ( ami_tls_cfg . pvtfile ) ;
}
ami_tls_cfg . pvtfile = ast_strdup ( " " ) ;
2009-04-23 20:36:35 +00:00
if ( ami_tls_cfg . cipher ) {
2007-06-06 21:20:11 +00:00
ast_free ( ami_tls_cfg . cipher ) ;
2009-04-23 20:36:35 +00:00
}
2006-12-07 16:42:29 +00:00
ami_tls_cfg . cipher = ast_strdup ( " " ) ;
2009-11-13 20:42:03 +00:00
free_channelvars ( ) ;
2006-12-12 10:35:10 +00:00
for ( var = ast_variable_browse ( cfg , " general " ) ; var ; var = var - > next ) {
val = var - > value ;
2009-04-29 14:39:48 +00:00
if ( ! ast_tls_read_conf ( & ami_tls_cfg , & amis_desc , var - > name , val ) ) {
continue ;
}
if ( ! strcasecmp ( var - > name , " enabled " ) ) {
2007-02-14 20:22:20 +00:00
manager_enabled = ast_true ( val ) ;
2006-12-12 10:35:10 +00:00
} else if ( ! strcasecmp ( var - > name , " block-sockets " ) ) {
block_sockets = ast_true ( val ) ;
} else if ( ! strcasecmp ( var - > name , " webenabled " ) ) {
2007-02-14 20:22:20 +00:00
webmanager_enabled = ast_true ( val ) ;
2006-12-12 10:35:10 +00:00
} else if ( ! strcasecmp ( var - > name , " port " ) ) {
2010-07-08 22:08:07 +00:00
ami_desc_local_address_tmp . sin_port = htons ( atoi ( val ) ) ;
2006-12-12 10:35:10 +00:00
} else if ( ! strcasecmp ( var - > name , " bindaddr " ) ) {
2010-07-08 22:08:07 +00:00
if ( ! inet_aton ( val , & ami_desc_local_address_tmp . sin_addr ) ) {
2006-12-12 10:35:10 +00:00
ast_log ( LOG_WARNING , " Invalid address '%s' specified, using 0.0.0.0 \n " , val ) ;
2010-07-08 22:08:07 +00:00
memset ( & ami_desc_local_address_tmp . sin_addr , 0 ,
sizeof ( ami_desc_local_address_tmp . sin_addr ) ) ;
2006-12-12 10:35:10 +00:00
}
2010-04-13 18:10:30 +00:00
} else if ( ! strcasecmp ( var - > name , " brokeneventsaction " ) ) {
broken_events_action = ast_true ( val ) ;
2009-04-23 20:36:35 +00:00
} else if ( ! strcasecmp ( var - > name , " allowmultiplelogin " ) ) {
2007-05-17 17:12:23 +00:00
allowmultiplelogin = ast_true ( val ) ;
2006-12-12 10:35:10 +00:00
} else if ( ! strcasecmp ( var - > name , " displayconnects " ) ) {
displayconnects = ast_true ( val ) ;
} else if ( ! strcasecmp ( var - > name , " timestampevents " ) ) {
timestampevents = ast_true ( val ) ;
} else if ( ! strcasecmp ( var - > name , " debug " ) ) {
manager_debug = ast_true ( val ) ;
} else if ( ! strcasecmp ( var - > name , " httptimeout " ) ) {
newhttptimeout = atoi ( val ) ;
2011-04-05 14:16:21 +00:00
} else if ( ! strcasecmp ( var - > name , " authtimeout " ) ) {
int timeout = atoi ( var - > value ) ;
if ( timeout < 1 ) {
ast_log ( LOG_WARNING , " Invalid authtimeout value '%s', using default value \n " , var - > value ) ;
} else {
authtimeout = timeout ;
}
} else if ( ! strcasecmp ( var - > name , " authlimit " ) ) {
int limit = atoi ( var - > value ) ;
if ( limit < 1 ) {
ast_log ( LOG_WARNING , " Invalid authlimit value '%s', using default value \n " , var - > value ) ;
} else {
authlimit = limit ;
}
2009-11-13 20:42:03 +00:00
} else if ( ! strcasecmp ( var - > name , " channelvars " ) ) {
2011-10-11 18:57:47 +00:00
load_channelvars ( var ) ;
2006-12-07 16:42:29 +00:00
} else {
2006-12-12 10:35:10 +00:00
ast_log ( LOG_NOTICE , " Invalid keyword <%s> = <%s> in manager.conf [general] \n " ,
var - > name , val ) ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
}
2006-01-03 22:07:12 +00:00
2012-02-02 18:55:05 +00:00
ast_sockaddr_to_sin ( & amis_desc . local_address , & amis_desc_local_address_tmp ) ;
2010-07-24 17:54:03 +00:00
2009-04-29 14:39:48 +00:00
/* if the amis address has not been set, default is the same as non secure ami */
2010-07-08 22:08:07 +00:00
if ( ! amis_desc_local_address_tmp . sin_addr . s_addr ) {
amis_desc_local_address_tmp . sin_addr =
ami_desc_local_address_tmp . sin_addr ;
2009-04-23 20:36:35 +00:00
}
2010-07-24 17:54:03 +00:00
2012-02-02 18:55:05 +00:00
if ( ! amis_desc_local_address_tmp . sin_port ) {
amis_desc_local_address_tmp . sin_port = htons ( DEFAULT_MANAGER_TLS_PORT ) ;
}
2010-09-23 18:08:23 +00:00
if ( manager_enabled ) {
ast_sockaddr_from_sin ( & ami_desc . local_address , & ami_desc_local_address_tmp ) ;
ast_sockaddr_from_sin ( & amis_desc . local_address , & amis_desc_local_address_tmp ) ;
}
2006-10-18 21:41:09 +00:00
2007-07-24 02:59:49 +00:00
AST_RWLIST_WRLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
2007-12-16 13:32:48 +00:00
/* First, get users from users.conf */
2008-03-26 18:39:06 +00:00
ucfg = ast_config_load2 ( " users.conf " , " manager " , config_flags ) ;
2009-08-27 21:26:37 +00:00
if ( ucfg & & ( ucfg ! = CONFIG_STATUS_FILEUNCHANGED ) & & ucfg ! = CONFIG_STATUS_FILEINVALID ) {
2007-12-16 13:32:48 +00:00
const char * hasmanager ;
int genhasmanager = ast_true ( ast_variable_retrieve ( ucfg , " general " , " hasmanager " ) ) ;
while ( ( cat = ast_category_browse ( ucfg , cat ) ) ) {
2009-04-23 20:36:35 +00:00
if ( ! strcasecmp ( cat , " general " ) ) {
2007-12-16 13:32:48 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
hasmanager = ast_variable_retrieve ( ucfg , cat , " hasmanager " ) ;
if ( ( ! hasmanager & & genhasmanager ) | | ast_true ( hasmanager ) ) {
const char * user_secret = ast_variable_retrieve ( ucfg , cat , " secret " ) ;
const char * user_read = ast_variable_retrieve ( ucfg , cat , " read " ) ;
const char * user_write = ast_variable_retrieve ( ucfg , cat , " write " ) ;
const char * user_displayconnects = ast_variable_retrieve ( ucfg , cat , " displayconnects " ) ;
const char * user_writetimeout = ast_variable_retrieve ( ucfg , cat , " writetimeout " ) ;
2009-04-23 20:36:35 +00:00
2007-12-16 13:32:48 +00:00
/* Look for an existing entry,
* if none found - create one and add it to the list
*/
if ( ! ( user = get_manager_by_name_locked ( cat ) ) ) {
2009-04-23 20:36:35 +00:00
if ( ! ( user = ast_calloc ( 1 , sizeof ( * user ) ) ) ) {
2007-12-16 13:32:48 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
/* Copy name over */
ast_copy_string ( user - > username , cat , sizeof ( user - > username ) ) ;
/* Insert into list */
AST_LIST_INSERT_TAIL ( & users , user , list ) ;
user - > ha = NULL ;
2008-07-18 22:19:56 +00:00
user - > keep = 1 ;
2007-12-16 13:32:48 +00:00
user - > readperm = - 1 ;
user - > writeperm = - 1 ;
/* Default displayconnect from [general] */
user - > displayconnects = displayconnects ;
user - > writetimeout = 100 ;
}
2009-04-23 20:36:35 +00:00
if ( ! user_secret ) {
2007-12-16 13:32:48 +00:00
user_secret = ast_variable_retrieve ( ucfg , " general " , " secret " ) ;
2009-04-23 20:36:35 +00:00
}
if ( ! user_read ) {
2007-12-16 13:32:48 +00:00
user_read = ast_variable_retrieve ( ucfg , " general " , " read " ) ;
2009-04-23 20:36:35 +00:00
}
if ( ! user_write ) {
2007-12-16 13:32:48 +00:00
user_write = ast_variable_retrieve ( ucfg , " general " , " write " ) ;
2009-04-23 20:36:35 +00:00
}
if ( ! user_displayconnects ) {
2007-12-16 13:32:48 +00:00
user_displayconnects = ast_variable_retrieve ( ucfg , " general " , " displayconnects " ) ;
2009-04-23 20:36:35 +00:00
}
if ( ! user_writetimeout ) {
2007-12-16 13:32:48 +00:00
user_writetimeout = ast_variable_retrieve ( ucfg , " general " , " writetimeout " ) ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
if ( ! ast_strlen_zero ( user_secret ) ) {
2009-04-23 20:36:35 +00:00
if ( user - > secret ) {
2007-12-16 13:32:48 +00:00
ast_free ( user - > secret ) ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
user - > secret = ast_strdup ( user_secret ) ;
}
2009-04-23 20:36:35 +00:00
if ( user_read ) {
2007-12-16 13:32:48 +00:00
user - > readperm = get_perm ( user_read ) ;
2009-04-23 20:36:35 +00:00
}
if ( user_write ) {
2007-12-16 13:32:48 +00:00
user - > writeperm = get_perm ( user_write ) ;
2009-04-23 20:36:35 +00:00
}
if ( user_displayconnects ) {
2007-12-16 13:32:48 +00:00
user - > displayconnects = ast_true ( user_displayconnects ) ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
if ( user_writetimeout ) {
2008-08-10 19:35:50 +00:00
int value = atoi ( user_writetimeout ) ;
2009-04-23 20:36:35 +00:00
if ( value < 100 ) {
2007-12-16 13:32:48 +00:00
ast_log ( LOG_WARNING , " Invalid writetimeout value '%s' at users.conf line %d \n " , var - > value , var - > lineno ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-08-10 19:35:50 +00:00
user - > writetimeout = value ;
2009-04-23 20:36:35 +00:00
}
2007-12-16 13:32:48 +00:00
}
}
}
ast_config_destroy ( ucfg ) ;
}
/* cat is NULL here in any case */
2006-09-19 22:01:23 +00:00
while ( ( cat = ast_category_browse ( cfg , cat ) ) ) {
2007-12-16 13:32:48 +00:00
struct ast_ha * oldha ;
2006-09-19 22:01:23 +00:00
2009-04-23 20:36:35 +00:00
if ( ! strcasecmp ( cat , " general " ) ) {
2006-09-19 22:01:23 +00:00
continue ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
/* Look for an existing entry, if none found - create one and add it to the list */
2006-10-19 07:43:43 +00:00
if ( ! ( user = get_manager_by_name_locked ( cat ) ) ) {
2009-04-23 20:36:35 +00:00
if ( ! ( user = ast_calloc ( 1 , sizeof ( * user ) ) ) ) {
2006-09-19 22:01:23 +00:00
break ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
/* Copy name over */
ast_copy_string ( user - > username , cat , sizeof ( user - > username ) ) ;
2007-12-16 13:32:48 +00:00
user - > ha = NULL ;
user - > readperm = 0 ;
user - > writeperm = 0 ;
/* Default displayconnect from [general] */
user - > displayconnects = displayconnects ;
user - > writetimeout = 100 ;
2010-06-22 16:29:18 +00:00
user - > whitefilters = ao2_container_alloc ( 1 , NULL , NULL ) ;
user - > blackfilters = ao2_container_alloc ( 1 , NULL , NULL ) ;
2007-12-16 13:32:48 +00:00
2006-09-19 22:01:23 +00:00
/* Insert into list */
2007-07-24 02:59:49 +00:00
AST_RWLIST_INSERT_TAIL ( & users , user , list ) ;
2010-06-22 16:29:18 +00:00
} else {
ao2_t_callback ( user - > whitefilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all white filters " ) ;
ao2_t_callback ( user - > blackfilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all black filters " ) ;
2006-09-19 22:01:23 +00:00
}
/* Make sure we keep this user and don't destroy it during cleanup */
user - > keep = 1 ;
2007-12-16 13:32:48 +00:00
oldha = user - > ha ;
user - > ha = NULL ;
2006-09-19 22:01:23 +00:00
var = ast_variable_browse ( cfg , cat ) ;
2007-12-16 13:32:48 +00:00
for ( ; var ; var = var - > next ) {
2006-09-19 22:01:23 +00:00
if ( ! strcasecmp ( var - > name , " secret " ) ) {
2009-04-23 20:36:35 +00:00
if ( user - > secret ) {
2007-06-06 21:20:11 +00:00
ast_free ( user - > secret ) ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
user - > secret = ast_strdup ( var - > value ) ;
2007-12-16 13:32:48 +00:00
} else if ( ! strcasecmp ( var - > name , " deny " ) | |
! strcasecmp ( var - > name , " permit " ) ) {
user - > ha = ast_append_ha ( var - > name , var - > value , user - > ha , NULL ) ;
2006-09-19 22:01:23 +00:00
} else if ( ! strcasecmp ( var - > name , " read " ) ) {
2007-12-16 13:32:48 +00:00
user - > readperm = get_perm ( var - > value ) ;
2006-09-19 22:01:23 +00:00
} else if ( ! strcasecmp ( var - > name , " write " ) ) {
2007-12-16 13:32:48 +00:00
user - > writeperm = get_perm ( var - > value ) ;
} else if ( ! strcasecmp ( var - > name , " displayconnects " ) ) {
2006-09-19 22:01:23 +00:00
user - > displayconnects = ast_true ( var - > value ) ;
2007-12-16 13:32:48 +00:00
} else if ( ! strcasecmp ( var - > name , " writetimeout " ) ) {
2008-08-10 19:35:50 +00:00
int value = atoi ( var - > value ) ;
2009-04-23 20:36:35 +00:00
if ( value < 100 ) {
2007-12-16 13:32:48 +00:00
ast_log ( LOG_WARNING , " Invalid writetimeout value '%s' at line %d \n " , var - > value , var - > lineno ) ;
2009-04-23 20:36:35 +00:00
} else {
2008-08-10 19:35:50 +00:00
user - > writetimeout = value ;
2009-04-23 20:36:35 +00:00
}
2010-06-22 16:29:18 +00:00
} else if ( ! strcasecmp ( var - > name , " eventfilter " ) ) {
const char * value = var - > value ;
2011-07-05 16:46:17 +00:00
manager_add_filter ( value , user - > whitefilters , user - > blackfilters ) ;
2009-04-23 20:36:35 +00:00
} else {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " %s is an unknown option. \n " , var - > name ) ;
2009-04-23 20:36:35 +00:00
}
2006-09-19 22:01:23 +00:00
}
2007-12-16 13:32:48 +00:00
ast_free_ha ( oldha ) ;
2006-09-19 22:01:23 +00:00
}
2007-12-16 13:32:48 +00:00
ast_config_destroy ( cfg ) ;
2006-09-19 22:01:23 +00:00
/* Perform cleanup - essentially prune out old users that no longer exist */
2007-07-24 02:59:49 +00:00
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & users , user , list ) {
2006-10-19 07:43:43 +00:00
if ( user - > keep ) { /* valid record. clear flag for the next round */
2006-09-19 22:01:23 +00:00
user - > keep = 0 ;
2009-04-23 20:36:35 +00:00
/* Calculate A1 for Digest auth */
snprintf ( a1 , sizeof ( a1 ) , " %s:%s:%s " , user - > username , global_realm , user - > secret ) ;
ast_md5_hash ( a1_hash , a1 ) ;
if ( user - > a1_hash ) {
ast_free ( user - > a1_hash ) ;
}
user - > a1_hash = ast_strdup ( a1_hash ) ;
2006-09-19 22:01:23 +00:00
continue ;
}
/* We do not need to keep this user so take them out of the list */
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list ) ;
2010-06-22 16:29:18 +00:00
ast_debug ( 4 , " Pruning user '%s' \n " , user - > username ) ;
2006-09-19 22:01:23 +00:00
/* Free their memory now */
2009-04-23 20:36:35 +00:00
if ( user - > a1_hash ) {
ast_free ( user - > a1_hash ) ;
}
if ( user - > secret ) {
2007-06-06 21:20:11 +00:00
ast_free ( user - > secret ) ;
2009-04-23 20:36:35 +00:00
}
2010-06-22 16:29:18 +00:00
ao2_t_callback ( user - > whitefilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all white filters " ) ;
ao2_t_callback ( user - > blackfilters , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , NULL , NULL , " unlink all black filters " ) ;
ao2_t_ref ( user - > whitefilters , - 1 , " decrement ref for white container, should be last one " ) ;
ao2_t_ref ( user - > blackfilters , - 1 , " decrement ref for black container, should be last one " ) ;
2007-12-16 13:32:48 +00:00
ast_free_ha ( user - > ha ) ;
2007-06-06 21:20:11 +00:00
ast_free ( user ) ;
2006-09-19 22:01:23 +00:00
}
2007-11-08 05:28:47 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
2006-09-19 22:01:23 +00:00
2007-07-24 02:59:49 +00:00
AST_RWLIST_UNLOCK ( & users ) ;
2006-09-19 22:01:23 +00:00
2009-04-23 20:36:35 +00:00
if ( ! reload ) {
/* If you have a NULL hash fn, you only need a single bucket */
sessions = ao2_container_alloc ( 1 , NULL , mansession_cmp_fn ) ;
}
2007-02-14 20:22:20 +00:00
if ( webmanager_enabled & & manager_enabled ) {
2006-04-01 08:49:54 +00:00
if ( ! webregged ) {
2009-04-23 20:36:35 +00:00
2006-04-01 08:49:54 +00:00
ast_http_uri_link ( & rawmanuri ) ;
ast_http_uri_link ( & manageruri ) ;
ast_http_uri_link ( & managerxmluri ) ;
2009-04-23 20:36:35 +00:00
ast_http_uri_link ( & arawmanuri ) ;
ast_http_uri_link ( & amanageruri ) ;
ast_http_uri_link ( & amanagerxmluri ) ;
2006-04-01 08:49:54 +00:00
webregged = 1 ;
}
} else {
if ( webregged ) {
ast_http_uri_unlink ( & rawmanuri ) ;
ast_http_uri_unlink ( & manageruri ) ;
ast_http_uri_unlink ( & managerxmluri ) ;
2009-04-23 20:36:35 +00:00
ast_http_uri_unlink ( & arawmanuri ) ;
ast_http_uri_unlink ( & amanageruri ) ;
ast_http_uri_unlink ( & amanagerxmluri ) ;
2006-04-01 08:49:54 +00:00
webregged = 0 ;
}
}
2009-04-23 20:36:35 +00:00
if ( newhttptimeout > 0 ) {
2006-04-01 08:49:54 +00:00
httptimeout = newhttptimeout ;
2009-04-23 20:36:35 +00:00
}
2006-04-04 19:03:12 +00:00
2007-12-06 15:50:43 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " Reload " , " Module: Manager \r \n Status: %s \r \n Message: Manager reload Requested \r \n " , manager_enabled ? " Enabled " : " Disabled " ) ;
2008-03-04 22:23:21 +00:00
ast_tcptls_server_start ( & ami_desc ) ;
2012-02-02 18:55:05 +00:00
if ( tls_was_enabled & & ! ami_tls_cfg . enabled ) {
ast_tcptls_server_stop ( & amis_desc ) ;
} else if ( ast_ssl_setup ( amis_desc . tls_cfg ) ) {
2008-03-04 22:23:21 +00:00
ast_tcptls_server_start ( & amis_desc ) ;
2009-04-23 20:36:35 +00:00
}
2002-09-12 18:32:42 +00:00
return 0 ;
}
2009-11-13 20:42:03 +00:00
/* clear out every entry in the channelvar list */
static void free_channelvars ( void )
{
struct manager_channel_variable * var ;
AST_RWLIST_WRLOCK ( & channelvars ) ;
while ( ( var = AST_RWLIST_REMOVE_HEAD ( & channelvars , entry ) ) ) {
ast_free ( var ) ;
}
AST_RWLIST_UNLOCK ( & channelvars ) ;
}
2007-08-16 21:09:46 +00:00
int init_manager ( void )
{
return __init_manager ( 0 ) ;
}
2002-09-12 18:32:42 +00:00
int reload_manager ( void )
{
2007-08-16 21:09:46 +00:00
return __init_manager ( 1 ) ;
2002-09-12 18:32:42 +00:00
}
2008-08-05 16:56:11 +00:00
int astman_datastore_add ( struct mansession * s , struct ast_datastore * datastore )
{
2009-02-10 21:45:14 +00:00
AST_LIST_INSERT_HEAD ( & s - > session - > datastores , datastore , entry ) ;
2008-08-05 16:56:11 +00:00
return 0 ;
}
int astman_datastore_remove ( struct mansession * s , struct ast_datastore * datastore )
{
2009-02-10 21:45:14 +00:00
return AST_LIST_REMOVE ( & s - > session - > datastores , datastore , entry ) ? 0 : - 1 ;
2008-08-05 16:56:11 +00:00
}
struct ast_datastore * astman_datastore_find ( struct mansession * s , const struct ast_datastore_info * info , const char * uid )
{
struct ast_datastore * datastore = NULL ;
2009-04-23 20:36:35 +00:00
2008-08-05 16:56:11 +00:00
if ( info = = NULL )
return NULL ;
2009-02-10 21:45:14 +00:00
AST_LIST_TRAVERSE_SAFE_BEGIN ( & s - > session - > datastores , datastore , entry ) {
2008-08-05 16:56:11 +00:00
if ( datastore - > info ! = info ) {
continue ;
}
if ( uid = = NULL ) {
/* matched by type only */
break ;
}
if ( ( datastore - > uid ! = NULL ) & & ! strcasecmp ( uid , datastore - > uid ) ) {
/* Matched by type AND uid */
break ;
}
}
AST_LIST_TRAVERSE_SAFE_END ;
return datastore ;
}