Thu Apr 28 2011 16:57:12

Asterisk developer's documentation


manager.c File Reference

The Asterisk Management Interface - AMI. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/mman.h>
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#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"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/ast_version.h"
#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/version.h"
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
Include dependency graph for manager.c:

Go to the source code of this file.

Data Structures

struct  actions
 list of actions registered More...
struct  all_events
struct  ast_manager_user
 user descriptor, as read from the config file. More...
struct  eventqent
struct  fast_originate_helper
 helper function for originate More...
struct  manager_hooks
 list of hooks registered More...
struct  mansession
struct  mansession_session::mansession_datastores
struct  mansession_session
struct  permalias
struct  sessions
struct  users
 list of users found in the config file More...
struct  variable_count

Defines

#define ASTMAN_APPEND_BUF_INITSIZE   256
 initial allocated size for the astman_append_buf
#define GET_HEADER_FIRST_MATCH   0
#define GET_HEADER_LAST_MATCH   1
#define GET_HEADER_SKIP_EMPTY   2
#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"
#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"
#define MANAGER_EVENT_BUF_INITSIZE   256
#define MAX_BLACKLIST_CMD_LEN   2
 Descriptor for a manager session, either on the AMI socket or over HTTP.
#define MSG_MOREDATA   ((char *)astman_send_response)
 send a response with an optional message, and terminate it with an empty line. m is used only to grab the 'ActionID' field.
#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING   "<form action=\"manager\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</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"

Enumerations

enum  error_type {
  UNKNOWN_ACTION = 1, UNKNOWN_CATEGORY, UNSPECIFIED_CATEGORY, UNSPECIFIED_ARGUMENT,
  FAILURE_ALLOCATION, FAILURE_NEWCAT, FAILURE_DELCAT, FAILURE_EMPTYCAT,
  FAILURE_UPDATE, FAILURE_DELETE, FAILURE_APPEND
}
enum  output_format { FORMAT_RAW, FORMAT_HTML, FORMAT_XML }

Functions

static const char * __astman_get_header (const struct message *m, char *var, int mode)
static void __fini_actions (void)
static void __fini_all_events (void)
static void __fini_manager_hooks (void)
static void __fini_users (void)
static void __init_actions (void)
static void __init_all_events (void)
static int __init_manager (int reload)
static void __init_manager_hooks (void)
static void __init_users (void)
int __manager_event (int category, const char *event, const char *file, int line, const char *func, const char *fmt,...)
 manager_event: Send AMI event to client
static int action_atxfer (struct mansession *s, const struct message *m)
static int action_challenge (struct mansession *s, const struct message *m)
static int action_command (struct mansession *s, const struct message *m)
 Manager command "command" - execute CLI command.
static int action_coresettings (struct mansession *s, const struct message *m)
 Show PBX core settings information.
static int action_coreshowchannels (struct mansession *s, const struct message *m)
 Manager command "CoreShowChannels" - List currently defined channels and some information about them.
static int action_corestatus (struct mansession *s, const struct message *m)
 Show PBX core status information.
static int action_createconfig (struct mansession *s, const struct message *m)
static int action_events (struct mansession *s, const struct message *m)
static int action_extensionstate (struct mansession *s, const struct message *m)
static int action_getconfig (struct mansession *s, const struct message *m)
static int action_getconfigjson (struct mansession *s, const struct message *m)
static int action_getvar (struct mansession *s, const struct message *m)
static int action_hangup (struct mansession *s, const struct message *m)
static int action_listcategories (struct mansession *s, const struct message *m)
static int action_listcommands (struct mansession *s, const struct message *m)
static int action_login (struct mansession *s, const struct message *m)
static int action_logoff (struct mansession *s, const struct message *m)
static int action_mailboxcount (struct mansession *s, const struct message *m)
static int action_mailboxstatus (struct mansession *s, const struct message *m)
static int action_originate (struct mansession *s, const struct message *m)
static int action_ping (struct mansession *s, const struct message *m)
static int action_redirect (struct mansession *s, const struct message *m)
 action_redirect: The redirect manager command
static int action_reload (struct mansession *s, const struct message *m)
 Send a reload event.
static int action_sendtext (struct mansession *s, const struct message *m)
static int action_setvar (struct mansession *s, const struct message *m)
static int action_status (struct mansession *s, const struct message *m)
 Manager "status" command to show channels.
static int action_timeout (struct mansession *s, const struct message *m)
static int action_updateconfig (struct mansession *s, const struct message *m)
static int action_userevent (struct mansession *s, const struct message *m)
static int action_waitevent (struct mansession *s, const struct message *m)
static struct eventqentadvance_event (struct eventqent *e)
static int append_event (const char *str, int category)
static int ast_instring (const char *bigstr, const char *smallstr, const char delim)
int ast_manager_register2 (const char *action, int auth, int(*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
 register a new command with manager, including online help. This is the preferred way to register a manager command
void ast_manager_register_hook (struct manager_custom_hook *hook)
 Add a custom hook to be called when an event is fired.
static int ast_manager_register_struct (struct manager_action *act)
int ast_manager_unregister (char *action)
 Unregister a registered manager command.
void ast_manager_unregister_hook (struct manager_custom_hook *hook)
 Delete a custom hook to be called when an event is fired.
 AST_THREADSTORAGE_CUSTOM_SCOPE (astman_append_buf, NULL, ast_free_ptr, static)
 thread local buffer for astman_append
 AST_THREADSTORAGE_CUSTOM_SCOPE (userevent_buf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (manager_event_buf, NULL, ast_free_ptr, static)
void astman_append (struct mansession *s, const char *fmt,...)
int astman_datastore_add (struct mansession *s, struct ast_datastore *datastore)
 Add a datastore to a session.
struct ast_datastoreastman_datastore_find (struct mansession *s, const struct ast_datastore_info *info, const char *uid)
 Find a datastore on a session.
int astman_datastore_remove (struct mansession *s, struct ast_datastore *datastore)
 Remove a datastore from a session.
const char * astman_get_header (const struct message *m, char *var)
 Get header from mananger transaction.
struct ast_variableastman_get_variables (const struct message *m)
 Get a linked list of the Variable: headers.
int astman_is_authed (uint32_t ident)
 Determinie if a manager session ident is authenticated.
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
 Send ack in manager transaction.
void astman_send_error (struct mansession *s, const struct message *m, char *error)
 Send error in manager transaction.
void astman_send_listack (struct mansession *s, const struct message *m, char *msg, char *listflag)
 Send ack in manager list transaction.
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
 Send response in manager transaction.
static void astman_send_response_full (struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
static void astman_start_ack (struct mansession *s, const struct message *m)
int astman_verify_session_readpermissions (uint32_t ident, int perm)
 Verify a session's read permissions against a permission mask.
int astman_verify_session_writepermissions (uint32_t ident, int perm)
 Verify a session's write permissions against a permission mask.
static int authenticate (struct mansession *s, const struct message *m)
static char * authority_to_str (int authority, struct ast_str **res)
 Convert authority code to a list of options.
static int check_blacklist (const char *cmd)
int check_manager_enabled ()
 Event list management functions. We assume that the event list always has at least one element, and the delete code will not remove the last entry even if the.
static int check_manager_session_inuse (const char *name)
int check_webmanager_enabled ()
 Check if AMI/HTTP is enabled.
static int compress_char (char c)
static void destroy_session (struct mansession_session *session)
static int do_message (struct mansession *s)
static void * fast_originate (void *data)
static struct mansession_sessionfind_session (uint32_t ident, int incinuse)
static void free_session (struct mansession_session *session)
static struct ast_strgeneric_http_callback (enum output_format format, struct sockaddr_in *remote_address, const char *uri, enum ast_http_method method, struct ast_variable *params, int *status, char **title, int *contentlength)
static int get_input (struct mansession *s, char *output)
static struct ast_manager_userget_manager_by_name_locked (const char *name)
static int get_perm (const char *instr)
static struct eventqentgrab_last (void)
static char * handle_manager_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager reload.
static char * handle_mandebug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanager (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmanagers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_showmancmds (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list commands.
static char * handle_showmanconn (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list connected.
static char * handle_showmaneventq (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command manager list eventq.
static enum error_type handle_updates (struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
int init_manager (void)
 Called by Asterisk initialization.
static void json_escape (char *out, const char *in)
static int manager_displayconnects (struct mansession_session *session)
 Get displayconnects config option.
static struct ast_strmanager_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 *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
static int manager_modulecheck (struct mansession *s, const struct message *m)
static int manager_moduleload (struct mansession *s, const struct message *m)
static int manager_state_cb (char *context, char *exten, int state, void *data)
static struct ast_strmxml_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 *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
static int process_events (struct mansession *s)
static int process_message (struct mansession *s, const struct message *m)
static void purge_events (void)
static void purge_old_stuff (void *data)
 cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most
static void purge_sessions (int n_max)
 remove at most n_max stale session from the list.
static struct ast_strrawman_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 *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
int reload_manager (void)
 Called by Asterisk module functions and the CLI command.
static int send_string (struct mansession *s, char *string)
static void * session_do (void *data)
 The body of the individual manager session. 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(). )
static int set_eventmask (struct mansession *s, const char *eventmask)
 Rather than braindead on,off this now can also accept a specific int mask value or a ',' delim list of mask strings (the same as manager.conf) -anthm.
static int strings_to_mask (const char *string)
static int variable_count_cmp_fn (void *obj, void *vstr, int flags)
static int variable_count_hash_fn (const void *vvc, const int flags)
static void xml_copy_escape (struct ast_str **out, const char *src, int mode)
static void xml_translate (struct ast_str **out, char *in, struct ast_variable *vars, enum output_format format)
 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'.

Variables

static struct actions actions
static struct all_events all_events
static int allowmultiplelogin = 1
static struct
ast_tcptls_session_args 
ami_desc
struct ast_tls_config ami_tls_cfg
static struct
ast_tcptls_session_args 
amis_desc
static int authlimit
static int authtimeout
static int block_sockets
static int broken_events_action
static struct ast_cli_entry cli_manager []
struct {
   char *   words [AST_MAX_CMD_LEN]
command_blacklist []
static char * contenttype []
static const int DEFAULT_AUTHLIMIT = 50
static const int DEFAULT_AUTHTIMEOUT = 30
static const int DEFAULT_BLOCKSOCKETS = 0
static const int DEFAULT_BROKENEVENTSACTION = 0
static const int DEFAULT_DISPLAYCONNECTS = 1
static const int DEFAULT_ENABLED = 0
static const int DEFAULT_HTTPTIMEOUT = 60
static const int DEFAULT_TIMESTAMPEVENTS = 0
static const int DEFAULT_WEBENABLED = 0
static int displayconnects
static int httptimeout
static int manager_debug
static int manager_enabled = 0
static struct manager_hooks manager_hooks
struct ast_http_uri manageruri
struct ast_http_uri managerxmluri
static char mandescr_atxfer [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_command [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_coresettings [] = " *ActionID: ActionID of this transaction\n"
static char mandescr_coreshowchannels [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_corestatus [] = " *ActionID: ActionID of this transaction\n"
static char mandescr_createconfig [] = " Filename: The configuration filename to create (e.g. foo.conf)\n"
static char mandescr_events [] = " 'system,call,log' to select which flags events should have to be sent.\n"
static char mandescr_extensionstate [] = "The response will include the hint for the extension and the status.\n"
static char mandescr_getconfig [] = " Category: Category in configuration file\n"
static char mandescr_getconfigjson [] = " Filename: Configuration filename (e.g. foo.conf)\n"
static char mandescr_getvar [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_hangup [] = " Channel: The channel name to be hungup\n"
static char mandescr_listcategories [] = " Filename: Configuration filename (e.g. foo.conf)\n"
static char mandescr_listcommands [] = "Variables: NONE\n"
static char mandescr_logoff [] = "Variables: NONE\n"
static char mandescr_mailboxcount [] = "\n"
static char mandescr_mailboxstatus [] = "\n"
 Help text for manager command mailboxstatus.
static char mandescr_modulecheck [] = "For success returns, the module revision number is included.\n"
static char mandescr_moduleload [] = " If no module is specified for a reload loadtype, all modules are reloaded"
static char mandescr_originate [] = " Async: Set to 'true' for fast origination\n"
static char mandescr_ping [] = "Variables: NONE\n"
 Manager PING.
static char mandescr_redirect [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_reload [] = " *Module: Name of the module to reload\n"
static char mandescr_sendtext [] = " ActionID: Optional Action id for message matching.\n"
static char mandescr_setvar [] = " *Value: Value\n"
static char mandescr_status [] = "value for the specified channel variables.\n"
static char mandescr_timeout [] = "Acknowledges set time with 'Timeout Set' message\n"
static char mandescr_updateconfig [] = " Line-XXXXXX: Line in category to operate on (used with delete and insert actions)\n"
static char mandescr_userevent [] = " HeaderN: ContentN\n"
static char mandescr_waitevent [] = " Timeout: Maximum time (in seconds) to wait for events, -1 means forever.\n"
 Manager WAITEVENT.
static int num_sessions
static struct permalias perms []
struct ast_http_uri rawmanuri
static int registered = 0
static struct sessions sessions
static int timestampevents
static int unauth_sessions = 0
static struct users users
static int webmanager_enabled = 0
static int webregged = 0

Detailed Description

The Asterisk Management Interface - AMI.

Author:
Mark Spencer <markster@digium.com>
ExtRef:
OpenSSL http://www.openssl.org - for AMI/SSL

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

manager.conf

Definition in file manager.c.


Define Documentation

#define HSMC_FORMAT   " %-15.15s %-15.15s %-55.55s\n"

Referenced by handle_showmancmds().

#define HSMCONN_FORMAT1   " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"

Referenced by handle_showmanconn().

#define HSMCONN_FORMAT2   " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"

Referenced by handle_showmanconn().

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"

Referenced by generic_http_callback().

#define TEST_STRING   "<form action=\"manager\">\n\ Action: <select name=\"action\">\n\ <option value=\"\">-----&gt;</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"

Referenced by generic_http_callback().


Enumeration Type Documentation

END Doxygen group

Enumerator:
FORMAT_RAW 
FORMAT_HTML 
FORMAT_XML 

Definition at line 3593 of file manager.c.


Function Documentation

static int __init_manager ( int  reload) [static]

Definition at line 4172 of file manager.c.

References action_atxfer(), action_challenge(), action_command(), action_coresettings(), action_coreshowchannels(), action_corestatus(), action_createconfig(), action_events(), action_extensionstate(), action_getconfig(), action_getconfigjson(), action_getvar(), action_hangup(), action_listcategories(), action_listcommands(), action_login(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_reload(), action_sendtext(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), ahp, ami_desc, ami_tls_cfg, amis_desc, append_event(), ARRAY_LEN, ast_append_ha(), ast_calloc, ast_category_browse(), AST_CERTFILE, ast_cli_register_multiple(), ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_debug, ast_extension_state_add(), ast_free, ast_free_ha(), ast_gethostbyname(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, ast_log(), ast_manager_register2(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_tls_config::certfile, ast_tls_config::cipher, cli_manager, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_AUTHLIMIT, DEFAULT_AUTHTIMEOUT, DEFAULT_BLOCKSOCKETS, DEFAULT_BROKENEVENTSACTION, DEFAULT_DISPLAYCONNECTS, DEFAULT_ENABLED, DEFAULT_HTTPTIMEOUT, DEFAULT_MANAGER_PORT, DEFAULT_TIMESTAMPEVENTS, DEFAULT_WEBENABLED, displayconnects, ast_manager_user::displayconnects, ast_tls_config::enabled, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_ORIGINATE, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, EVENT_FLAG_USER, get_manager_by_name_locked(), get_perm(), ast_manager_user::ha, hp, inet_aton(), ast_manager_user::keep, ast_variable::lineno, ast_tcptls_session_args::local_address, LOG_NOTICE, LOG_WARNING, manager_event, manager_modulecheck(), manager_moduleload(), manager_state_cb(), manageruri, managerxmluri, mandescr_atxfer, mandescr_command, mandescr_coresettings, mandescr_coreshowchannels, mandescr_corestatus, mandescr_createconfig, mandescr_events, mandescr_extensionstate, mandescr_getconfig, mandescr_getconfigjson, mandescr_getvar, mandescr_hangup, mandescr_listcategories, mandescr_listcommands, mandescr_logoff, mandescr_mailboxcount, mandescr_mailboxstatus, mandescr_modulecheck, mandescr_moduleload, mandescr_originate, mandescr_ping, mandescr_redirect, mandescr_reload, mandescr_sendtext, mandescr_setvar, mandescr_status, mandescr_timeout, mandescr_updateconfig, mandescr_userevent, mandescr_waitevent, ast_variable::name, ast_variable::next, rawmanuri, ast_manager_user::readperm, registered, ast_manager_user::secret, ast_tcptls_session_args::tls_cfg, ast_manager_user::username, val, ast_variable::value, var, webregged, ast_manager_user::writeperm, and ast_manager_user::writetimeout.

Referenced by init_manager(), and reload_manager().

{
   struct ast_config *ucfg = NULL, *cfg = NULL;
   const char *val;
   char *cat = NULL;
   int newhttptimeout = DEFAULT_HTTPTIMEOUT;
   int have_sslbindaddr = 0;
   struct hostent *hp;
   struct ast_hostent ahp;
   struct ast_manager_user *user = NULL;
   struct ast_variable *var;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
   
   if (!registered) {
      /* Register default actions */
      ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
      ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
      ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
      ast_manager_register2("Login", 0, action_login, "Login Manager", NULL);
      ast_manager_register2("Challenge", 0, action_challenge, "Generate Challenge for MD5 Auth", NULL);
      ast_manager_register2("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
      ast_manager_register2("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status, "Lists channel status", mandescr_status);
      ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar);
      ast_manager_register2("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar, "Gets a Channel Variable", mandescr_getvar);
      ast_manager_register2("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
      ast_manager_register2("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
      ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
      ast_manager_register2("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig, "Creates an empty file in the configuration directory", mandescr_createconfig);
      ast_manager_register2("ListCategories", EVENT_FLAG_CONFIG, action_listcategories, "List categories in configuration file", mandescr_listcategories);
      ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
      ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer);
      ast_manager_register2("Originate", EVENT_FLAG_ORIGINATE, action_originate, "Originate Call", mandescr_originate);
      ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
      ast_manager_register2("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
      ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
      ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
      ast_manager_register2("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
      ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
      ast_manager_register2("SendText", EVENT_FLAG_CALL, action_sendtext, "Send text message to channel", mandescr_sendtext);
      ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
      ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
      ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
      ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
      ast_manager_register2("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload, "Send a reload event", mandescr_reload);
      ast_manager_register2("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels, "List currently active channels", mandescr_coreshowchannels);
      ast_manager_register2("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload, "Module management", mandescr_moduleload);
      ast_manager_register2("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck, "Check if module is loaded", mandescr_modulecheck);

      ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
      ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
      registered = 1;
      /* Append placeholder event so master_eventq never runs dry */
      append_event("Event: Placeholder\r\n\r\n", 0);
   }
   if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
      return 0;

   manager_enabled = DEFAULT_ENABLED;
   webmanager_enabled = DEFAULT_WEBENABLED;
   displayconnects = DEFAULT_DISPLAYCONNECTS;
   broken_events_action = DEFAULT_BROKENEVENTSACTION;
   block_sockets = DEFAULT_BLOCKSOCKETS;
   timestampevents = DEFAULT_TIMESTAMPEVENTS;
   httptimeout = DEFAULT_HTTPTIMEOUT;
   authtimeout = DEFAULT_AUTHTIMEOUT;
   authlimit = DEFAULT_AUTHLIMIT;

   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");
      return 0;
   }

   /* default values */
   memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
   memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
   amis_desc.local_address.sin_port = htons(5039);
   ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT);

   ami_tls_cfg.enabled = 0;
   if (ami_tls_cfg.certfile)
      ast_free(ami_tls_cfg.certfile);
   ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
   if (ami_tls_cfg.cipher)
      ast_free(ami_tls_cfg.cipher);
   ami_tls_cfg.cipher = ast_strdup("");

   for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
      val = var->value;
      if (!strcasecmp(var->name, "sslenable"))
         ami_tls_cfg.enabled = ast_true(val);
      else if (!strcasecmp(var->name, "sslbindport"))
         amis_desc.local_address.sin_port = htons(atoi(val));
      else if (!strcasecmp(var->name, "sslbindaddr")) {
         if ((hp = ast_gethostbyname(val, &ahp))) {
            memcpy(&amis_desc.local_address.sin_addr, hp->h_addr, sizeof(amis_desc.local_address.sin_addr));
            have_sslbindaddr = 1;
         } else {
            ast_log(LOG_WARNING, "Invalid bind address '%s'\n", val);
         }
      } else if (!strcasecmp(var->name, "sslcert")) {
         ast_free(ami_tls_cfg.certfile);
         ami_tls_cfg.certfile = ast_strdup(val);
      } else if (!strcasecmp(var->name, "sslcipher")) {
         ast_free(ami_tls_cfg.cipher);
         ami_tls_cfg.cipher = ast_strdup(val);
      } else if (!strcasecmp(var->name, "enabled")) {
         manager_enabled = ast_true(val);
      } else if (!strcasecmp(var->name, "block-sockets")) {
         block_sockets = ast_true(val);
      } else if (!strcasecmp(var->name, "webenabled")) {
         webmanager_enabled = ast_true(val);
      } else if (!strcasecmp(var->name, "port")) {
         ami_desc.local_address.sin_port = htons(atoi(val));
      } else if (!strcasecmp(var->name, "bindaddr")) {
         if (!inet_aton(val, &ami_desc.local_address.sin_addr)) {
            ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
            memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr));
         }
      } else if (!strcasecmp(var->name, "brokeneventsaction")) {
         broken_events_action = ast_true(val);
      } else if (!strcasecmp(var->name, "allowmultiplelogin")) { 
         allowmultiplelogin = ast_true(val);
      } 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);
      } 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;
         }
      } else {
         ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
            var->name, val);
      }  
   }

   if (manager_enabled)
      ami_desc.local_address.sin_family = AF_INET;
   if (!have_sslbindaddr)
      amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr;
   if (ami_tls_cfg.enabled)
      amis_desc.local_address.sin_family = AF_INET;

   
   AST_RWLIST_WRLOCK(&users);

   /* First, get users from users.conf */
   ucfg = ast_config_load2("users.conf", "manager", config_flags);
   if (ucfg && (ucfg != CONFIG_STATUS_FILEUNCHANGED) && ucfg != CONFIG_STATUS_FILEINVALID) {
      const char *hasmanager;
      int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));

      while ((cat = ast_category_browse(ucfg, cat))) {
         if (!strcasecmp(cat, "general"))
            continue;
         
         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");
            
            /* Look for an existing entry,
             * if none found - create one and add it to the list
             */
            if (!(user = get_manager_by_name_locked(cat))) {
               if (!(user = ast_calloc(1, sizeof(*user))))
                  break;

               /* 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;
               user->keep = 1;
               user->readperm = -1;
               user->writeperm = -1;
               /* Default displayconnect from [general] */
               user->displayconnects = displayconnects;
               user->writetimeout = 100;
            }

            if (!user_secret)
               user_secret = ast_variable_retrieve(ucfg, "general", "secret");
            if (!user_read)
               user_read = ast_variable_retrieve(ucfg, "general", "read");
            if (!user_write)
               user_write = ast_variable_retrieve(ucfg, "general", "write");
            if (!user_displayconnects)
               user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
            if (!user_writetimeout)
               user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");

            if (!ast_strlen_zero(user_secret)) {
               if (user->secret)
                  ast_free(user->secret);
               user->secret = ast_strdup(user_secret);
            }

            if (user_read)
               user->readperm = get_perm(user_read);
            if (user_write)
               user->writeperm = get_perm(user_write);
            if (user_displayconnects)
               user->displayconnects = ast_true(user_displayconnects);

            if (user_writetimeout) {
               int value = atoi(user_writetimeout);
               if (value < 100)
                  ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
               else
                  user->writetimeout = value;
            }
         }
      }
      ast_config_destroy(ucfg);
   }

   /* cat is NULL here in any case */

   while ((cat = ast_category_browse(cfg, cat))) {
      struct ast_ha *oldha;

      if (!strcasecmp(cat, "general"))
         continue;

      /* Look for an existing entry, if none found - create one and add it to the list */
      if (!(user = get_manager_by_name_locked(cat))) {
         if (!(user = ast_calloc(1, sizeof(*user))))
            break;
         /* Copy name over */
         ast_copy_string(user->username, cat, sizeof(user->username));

         user->ha = NULL;
         user->readperm = 0;
         user->writeperm = 0;
         /* Default displayconnect from [general] */
         user->displayconnects = displayconnects;
         user->writetimeout = 100;

         /* Insert into list */
         AST_RWLIST_INSERT_TAIL(&users, user, list);
      }

      /* Make sure we keep this user and don't destroy it during cleanup */
      user->keep = 1;
      oldha = user->ha;
      user->ha = NULL;

      var = ast_variable_browse(cfg, cat);
      for (; var; var = var->next) {
         if (!strcasecmp(var->name, "secret")) {
            if (user->secret)
               ast_free(user->secret);
            user->secret = ast_strdup(var->value);
         } else if (!strcasecmp(var->name, "deny") ||
                   !strcasecmp(var->name, "permit")) {
            user->ha = ast_append_ha(var->name, var->value, user->ha, NULL);
         }  else if (!strcasecmp(var->name, "read") ) {
            user->readperm = get_perm(var->value);
         }  else if (!strcasecmp(var->name, "write") ) {
            user->writeperm = get_perm(var->value);
         }  else if (!strcasecmp(var->name, "displayconnects") ) {
            user->displayconnects = ast_true(var->value);
         } else if (!strcasecmp(var->name, "writetimeout")) {
            int value = atoi(var->value);
            if (value < 100)
               ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
            else
               user->writetimeout = value;
         } else
            ast_debug(1, "%s is an unknown option.\n", var->name);
      }
      ast_free_ha(oldha);
   }
   ast_config_destroy(cfg);

   /* Perform cleanup - essentially prune out old users that no longer exist */
   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
      if (user->keep) { /* valid record. clear flag for the next round */
         user->keep = 0;
         continue;
      }
      /* We do not need to keep this user so take them out of the list */
      AST_RWLIST_REMOVE_CURRENT(list);
      /* Free their memory now */
      if (user->secret)
         ast_free(user->secret);
      ast_free_ha(user->ha);
      ast_free(user);
   }
   AST_RWLIST_TRAVERSE_SAFE_END;

   AST_RWLIST_UNLOCK(&users);

   if (webmanager_enabled && manager_enabled) {
      if (!webregged) {
         ast_http_uri_link(&rawmanuri);
         ast_http_uri_link(&manageruri);
         ast_http_uri_link(&managerxmluri);
         webregged = 1;
      }
   } else {
      if (webregged) {
         ast_http_uri_unlink(&rawmanuri);
         ast_http_uri_unlink(&manageruri);
         ast_http_uri_unlink(&managerxmluri);
         webregged = 0;
      }
   }

   if (newhttptimeout > 0)
      httptimeout = newhttptimeout;

   manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");

   ast_tcptls_server_start(&ami_desc);
   if (ast_ssl_setup(amis_desc.tls_cfg))
      ast_tcptls_server_start(&amis_desc);
   return 0;
}
int astman_datastore_add ( struct mansession s,
struct ast_datastore datastore 
)

Add a datastore to a session.

Return values:
0success
non-zerofailure
Since:
1.6.1

Definition at line 4522 of file manager.c.

References AST_LIST_INSERT_HEAD, mansession_session::datastores, and mansession::session.

{
   AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);

   return 0;
}
struct ast_datastore* astman_datastore_find ( struct mansession s,
const struct ast_datastore_info info,
const char *  uid 
) [read]

Find a datastore on a session.

Return values:
pointerto the datastore if found
NULLif not found
Since:
1.6.1

Definition at line 4534 of file manager.c.

References AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, mansession_session::datastores, ast_datastore::info, mansession::session, and ast_datastore::uid.

{
   struct ast_datastore *datastore = NULL;
   
   if (info == NULL)
      return NULL;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
      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;
}
int astman_datastore_remove ( struct mansession s,
struct ast_datastore datastore 
)

Remove a datastore from a session.

Return values:
0success
non-zerofailure
Since:
1.6.1

Definition at line 4529 of file manager.c.

References AST_LIST_REMOVE, mansession_session::datastores, and mansession::session.

{
   return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
}
int astman_is_authed ( uint32_t  ident)

Determinie if a manager session ident is authenticated.

Definition at line 3631 of file manager.c.

References mansession_session::__lock, ast_mutex_unlock(), mansession_session::authenticated, and find_session().

Referenced by handle_uri(), and static_callback().

{
   int authed;
   struct mansession_session *session;

   if (!(session = find_session(ident, 0)))
      return 0;

   authed = (session->authenticated != 0);

   ast_mutex_unlock(&session->__lock);

   return authed;
}
int astman_verify_session_readpermissions ( uint32_t  ident,
int  perm 
)

Verify a session's read permissions against a permission mask.

Parameters:
identsession identity
permpermission mask to verify
Return values:
1if the session has the permission mask capabilities
0otherwise

Definition at line 3646 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::managerid, and mansession_session::readperm.

{
   int result = 0;
   struct mansession_session *session;

   AST_LIST_LOCK(&sessions);
   AST_LIST_TRAVERSE(&sessions, session, list) {
      ast_mutex_lock(&session->__lock);
      if ((session->managerid == ident) && (session->readperm & perm)) {
         result = 1;
         ast_mutex_unlock(&session->__lock);
         break;
      }
      ast_mutex_unlock(&session->__lock);
   }
   AST_LIST_UNLOCK(&sessions);
   return result;
}
int astman_verify_session_writepermissions ( uint32_t  ident,
int  perm 
)

Verify a session's write permissions against a permission mask.

Parameters:
identsession identity
permpermission mask to verify
Return values:
1if the session has the permission mask capabilities, otherwise 0
0otherwise

Definition at line 3665 of file manager.c.

References mansession_session::__lock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::managerid, and mansession_session::writeperm.

Referenced by http_post_callback().

{
   int result = 0;
   struct mansession_session *session;

   AST_LIST_LOCK(&sessions);
   AST_LIST_TRAVERSE(&sessions, session, list) {
      ast_mutex_lock(&session->__lock);
      if ((session->managerid == ident) && (session->writeperm & perm)) {
         result = 1;
         ast_mutex_unlock(&session->__lock);
         break;
      }
      ast_mutex_unlock(&session->__lock);
   }
   AST_LIST_UNLOCK(&sessions);
   return result;
}
static int compress_char ( char  c) [static]

Definition at line 3750 of file manager.c.

Referenced by variable_count_hash_fn().

{
   c &= 0x7f;
   if (c < 32)
      return 0;
   else if (c >= 'a' && c <= 'z')
      return c - 64;
   else if (c > 'z')
      return '_';
   else
      return c - 32;
}
static struct mansession_session* find_session ( uint32_t  ident,
int  incinuse 
) [static, read]

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).

Definition at line 3610 of file manager.c.

References mansession_session::__lock, ast_atomic_fetchadd_int(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), mansession_session::inuse, mansession_session::managerid, and mansession_session::needdestroy.

Referenced by astman_is_authed(), and generic_http_callback().

{
   struct mansession_session *session;

   if (ident == 0)
      return NULL;

   AST_LIST_LOCK(&sessions);
   AST_LIST_TRAVERSE(&sessions, session, list) {
      ast_mutex_lock(&session->__lock);
      if (session->managerid == ident && !session->needdestroy) {
         ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
         break;
      }
      ast_mutex_unlock(&session->__lock);
   }
   AST_LIST_UNLOCK(&sessions);

   return session;
}
static struct ast_str* generic_http_callback ( enum output_format  format,
struct sockaddr_in *  remote_address,
const char *  uri,
enum ast_http_method  method,
struct ast_variable params,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

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.

Definition at line 3914 of file manager.c.

References mansession_session::__lock, ast_atomic_fetchadd_int(), ast_calloc, ast_debug, ast_http_error(), ast_inet_ntoa(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_MANHEADERS, ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_random(), ast_str_append(), ast_str_create(), ast_verb, mansession_session::authenticated, buf, contenttype, destroy_session(), mansession::f, mansession::fd, mansession_session::fd, find_session(), FORMAT_HTML, FORMAT_XML, grab_last(), message::hdrcount, message::headers, mansession_session::inuse, LOG_EVENT, LOG_WARNING, manager_displayconnects(), mansession_session::managerid, ast_variable::name, mansession_session::needdestroy, ast_variable::next, process_message(), ROW_FMT, s, mansession_session::send_events, mansession::session, mansession_session::sessiontimeout, mansession_session::sin, TEST_STRING, mansession_session::username, ast_variable::value, mansession_session::waiting_thread, and xml_translate().

Referenced by manager_http_callback(), mxml_http_callback(), and rawman_http_callback().

{
   struct mansession s = {.session = NULL, };
   struct mansession_session *session = NULL;
   uint32_t ident = 0;
   int blastaway = 0;
   struct ast_variable *v;
   char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
   struct ast_str *out = NULL;
   struct message m = { 0 };
   unsigned int x;
   size_t hdrlen;

   for (v = params; v; v = v->next) {
      if (!strcasecmp(v->name, "mansession_id")) {
         sscanf(v->value, "%30x", &ident);
         break;
      }
   }

   if (!(session = find_session(ident, 1))) {
      /* Create new session.
       * While it is not in the list we don't need any locking
       */
      if (!(session = ast_calloc(1, sizeof(*session)))) {
         *status = 500;
         goto generic_callback_out;
      }
      session->sin = *remote_address;
      session->fd = -1;
      session->waiting_thread = AST_PTHREADT_NULL;
      session->send_events = 0;
      ast_mutex_init(&session->__lock);
      ast_mutex_lock(&session->__lock);
      session->inuse = 1;
      /*!\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.
       */
      while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
      session->last_ev = grab_last();
      AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
      AST_LIST_LOCK(&sessions);
      AST_LIST_INSERT_HEAD(&sessions, session, list);
      ast_atomic_fetchadd_int(&num_sessions, 1);
      AST_LIST_UNLOCK(&sessions);
   }

   s.session = session;

   ast_mutex_unlock(&session->__lock);

   if (!(out = ast_str_create(1024))) {
      *status = 500;
      goto generic_callback_out;
   }

   s.fd = mkstemp(template);  /* create a temporary file for command output */
   unlink(template);
   s.f = fdopen(s.fd, "w+");

   for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
      hdrlen = strlen(v->name) + strlen(v->value) + 3;
      m.headers[m.hdrcount] = alloca(hdrlen);
      snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
      ast_debug(1, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
      m.hdrcount = x + 1;
   }

   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));
         }
         ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
      } else {
         if (displayconnects) {
            ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
         }
         ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
      }
      session->needdestroy = 1;
   }

   ast_str_append(&out, 0,
             "Content-type: text/%s\r\n"
             "Cache-Control: no-cache;\r\n"
             "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
             "Pragma: SuppressEvents\r\n"
             "\r\n",
         contenttype[format],
         session->managerid, httptimeout);

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "<ajax-response>\n");
   } else if (format == FORMAT_HTML) {
      /*
       * 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...
       */

#define ROW_FMT   "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
#define TEST_STRING \
   "<form action=\"manager\">\n\
   Action: <select name=\"action\">\n\
      <option value=\"\">-----&gt;</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"

      ast_str_append(&out, 0, "<title>Asterisk&trade; Manager Interface</title>");
      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);
   }

   if (s.f != NULL) {   /* have temporary output */
      char *buf;
      size_t l;

      if ((l = ftell(s.f))) {
         if (MAP_FAILED == (buf = mmap(NULL, l + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) {
            ast_log(LOG_WARNING, "mmap failed.  Manager output was not processed\n");
         } else {
            buf[l] = '\0';
            if (format == FORMAT_XML || format == FORMAT_HTML) {
               xml_translate(&out, buf, params, format);
            } else {
               ast_str_append(&out, 0, "%s", buf);
            }
            munmap(buf, l + 1);
         }
      } else if (format == FORMAT_XML || format == FORMAT_HTML) {
         xml_translate(&out, "", params, format);
      }
      fclose(s.f);
      s.f = NULL;
      s.fd = -1;
   }

   if (format == FORMAT_XML) {
      ast_str_append(&out, 0, "</ajax-response>\n");
   } else if (format == FORMAT_HTML)
      ast_str_append(&out, 0, "</table></body>\r\n");

   ast_mutex_lock(&session->__lock);
   /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
   session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);

   if (session->needdestroy) {
      if (session->inuse == 1) {
         ast_debug(1, "Need destroy, doing it now!\n");
         blastaway = 1;
      } else {
         ast_debug(1, "Need destroy, but can't do it yet!\n");
         if (session->waiting_thread != AST_PTHREADT_NULL)
            pthread_kill(session->waiting_thread, SIGURG);
         session->inuse--;
      }
   } else
      session->inuse--;
   ast_mutex_unlock(&session->__lock);

   if (blastaway)
      destroy_session(session);
generic_callback_out:
   if (*status != 200)
      return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
   return out;
}
int init_manager ( void  )

Called by Asterisk initialization.

Definition at line 4512 of file manager.c.

References __init_manager().

Referenced by main().

{
   return __init_manager(0);
}
static struct ast_str* 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 params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 4096 of file manager.c.

References FORMAT_HTML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   return generic_http_callback(FORMAT_HTML, &ser->remote_address, uri, method, params, status, title, contentlength);
}
static struct ast_str* 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 params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 4101 of file manager.c.

References FORMAT_XML, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   return generic_http_callback(FORMAT_XML, &ser->remote_address, uri, method, params, status, title, contentlength);
}
static void purge_old_stuff ( void *  data) [static]

cleanup code called at each iteration of server_root, guaranteed to happen every 5 seconds at most

Definition at line 4144 of file manager.c.

References purge_events(), and purge_sessions().

static struct ast_str* 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 params,
struct ast_variable headers,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 4106 of file manager.c.

References FORMAT_RAW, generic_http_callback(), and ast_tcptls_session_instance::remote_address.

{
   return generic_http_callback(FORMAT_RAW, &ser->remote_address, uri, method, params, status, title, contentlength);
}
int reload_manager ( void  )

Called by Asterisk module functions and the CLI command.

Definition at line 4517 of file manager.c.

References __init_manager().

Referenced by handle_manager_reload().

{
   return __init_manager(1);
}
static int variable_count_cmp_fn ( void *  obj,
void *  vstr,
int  flags 
) [static]

Definition at line 3775 of file manager.c.

References CMP_MATCH, CMP_STOP, str, and variable_count::varname.

Referenced by xml_translate().

{
   /* 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;
   return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
}
static int variable_count_hash_fn ( const void *  vvc,
const int  flags 
) [static]

Definition at line 3763 of file manager.c.

References compress_char(), and variable_count::varname.

Referenced by xml_translate().

{
   const struct variable_count *vc = vvc;
   int res = 0, i;
   for (i = 0; i < 5; i++) {
      if (vc->varname[i] == '\0')
         break;
      res += compress_char(vc->varname[i]) << (i * 6);
   }
   return res;
}
static void xml_copy_escape ( struct ast_str **  out,
const char *  src,
int  mode 
) [static]

Definition at line 3689 of file manager.c.

References ast_str_append(), buf, and ast_frame::src.

Referenced by xml_translate().

{
   /* 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);
         if (*src == '\0')
            break;
      }
         
      if ( (mode & 2) && !isalnum(*src)) {
         *dst++ = '_';
         space--;
         continue;
      }
      switch (*src) {
      case '<':
         strcpy(dst, "&lt;");
         dst += 4;
         space -= 4;
         break;
      case '>':
         strcpy(dst, "&gt;");
         dst += 4;
         space -= 4;
         break;
      case '\"':
         strcpy(dst, "&quot;");
         dst += 6;
         space -= 6;
         break;
      case '\'':
         strcpy(dst, "&apos;");
         dst += 6;
         space -= 6;
         break;
      case '&':
         strcpy(dst, "&amp;");
         dst += 5;
         space -= 5;
         break;

      default:
         *dst++ = mode ? tolower(*src) : *src;
         space--;
      }
   }
}
static void xml_translate ( struct ast_str **  out,
char *  in,
struct ast_variable vars,
enum output_format  format 
) [static]

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):

General: the unformatted text is used as a value of XML output: to be completed

 *   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"
 * 

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


Definition at line 3814 of file manager.c.

References ao2_alloc, ao2_container_alloc, ao2_find, ao2_link, ao2_ref, ast_debug, ast_skip_blanks(), ast_str_append(), ast_strlen_zero(), ast_trim_blanks(), variable_count::count, FORMAT_XML, ast_variable::name, ast_variable::next, strsep(), val, ast_variable::value, var, variable_count_cmp_fn(), variable_count_hash_fn(), variable_count::varname, and xml_copy_escape().

Referenced by generic_http_callback().

{
   struct ast_variable *v;
   const char *dest = NULL;
   char *var, *val;
   const char *objtype = NULL;
   int in_data = 0;  /* parsing data */
   int inobj = 0;
   int xml = (format == FORMAT_XML);
   struct variable_count *vc = NULL;
   struct ao2_container *vco = NULL;

   for (v = vars; v; v = v->next) {
      if (!dest && !strcasecmp(v->name, "ajaxdest"))
         dest = v->value;
      else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
         objtype = v->value;
   }
   if (!dest)
      dest = "unknown";
   if (!objtype)
      objtype = "generic";

   /* we want to stop when we find an empty line */
   while (in && *in) {
      val = strsep(&in, "\r\n"); /* mark start and end of line */
      if (in && *in == '\n')     /* remove trailing \n if any */
         in++;
      ast_trim_blanks(val);
      ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
      if (ast_strlen_zero(val)) {
         if (in_data) { /* close data */
            ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
            in_data = 0;
         }
         if (inobj) {
            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;
         }
         continue;
      }

      /* we expect Name: value lines */
      if (in_data) {
         var = NULL;
      } else {
         var = strsep(&val, ":");
         if (val) {  /* found the field name */
            val = ast_skip_blanks(val);
            ast_trim_blanks(var);
         } else {    /* field name not found, move to opaque mode */
            val = var;
            var = "Opaque-data";
         }
      }

      if (!inobj) {
         if (xml)
            ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
         else
            ast_str_append(out, 0, "<body>\n");
         vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
         inobj = 1;
      }

      if (!in_data) {   /* build appropriate line start */
         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);
         if (vc->count > 1)
            ast_str_append(out, 0, "-%d", vc->count);
         ao2_ref(vc, -1);
         ast_str_append(out, 0, xml ? "='" : "</td><td>");
         if (!strcmp(var, "Opaque-data"))
            in_data = 1;
      }
      xml_copy_escape(out, val, 0); /* data field */
      if (!in_data)
         ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
      else
         ast_str_append(out, 0, xml ? "\n" : "<br>\n");
   }
   if (inobj) {
      ast_str_append(out, 0, xml ? " /></response>\n" :
         "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
      ao2_ref(vco, -1);
   }
}

Variable Documentation

Definition at line 4151 of file manager.c.

Referenced by __init_manager().

Definition at line 4150 of file manager.c.

Referenced by __init_manager().

Definition at line 4162 of file manager.c.

Referenced by __init_manager().

char* contenttype[] [static]
Initial value:
 {
   [FORMAT_RAW] = "plain",
   [FORMAT_HTML] = "html",
   [FORMAT_XML] =  "xml",
}

Definition at line 3599 of file manager.c.

Referenced by generic_http_callback().

Definition at line 4120 of file manager.c.

Referenced by __init_manager().

Definition at line 4129 of file manager.c.

Referenced by __init_manager().

Definition at line 4111 of file manager.c.

Referenced by __init_manager().

int registered = 0 [static]

Definition at line 4138 of file manager.c.

Referenced by __init_manager().

int webregged = 0 [static]

Definition at line 4139 of file manager.c.

Referenced by __init_manager().

char* words[AST_MAX_CMD_LEN]

Definition at line 160 of file manager.c.

Referenced by check_blacklist().