Thu Oct 11 06:43:58 2012

Asterisk developer's documentation


manager.h File Reference

The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party software. More...

#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "asterisk/lock.h"

Include dependency graph for manager.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  manager_action
struct  message

Defines

#define ast_manager_register(a, b, c, d)   ast_manager_register2(a, b, c, d, NULL)
#define AST_MAX_MANHEADERS   128
#define DEFAULT_MANAGER_PORT   5038
#define EVENT_FLAG_AGENT   (1 << 5)
#define EVENT_FLAG_CALL   (1 << 1)
#define EVENT_FLAG_COMMAND   (1 << 4)
#define EVENT_FLAG_CONFIG   (1 << 7)
#define EVENT_FLAG_LOG   (1 << 2)
#define EVENT_FLAG_SYSTEM   (1 << 0)
#define EVENT_FLAG_USER   (1 << 6)
#define EVENT_FLAG_VERBOSE   (1 << 3)

Functions

int ast_manager_register2 (const char *action, int authority, 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
int ast_manager_unregister (char *action)
void astman_append (struct mansession *s, const char *fmt,...)
const char * astman_get_header (const struct message *m, char *var)
struct ast_variableastman_get_variables (const struct message *m)
void astman_send_ack (struct mansession *s, const struct message *m, char *msg)
void astman_send_error (struct mansession *s, const struct message *m, char *error)
void astman_send_response (struct mansession *s, const struct message *m, char *resp, char *msg)
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.
int init_manager (void)
int manager_event (int category, const char *event, const char *contents,...)
 manager_event: Send AMI event to client
int reload_manager (void)


Detailed Description

The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party software.

Manager protocol packages are text fields of the form a: b. There is always exactly one space after the colon.

The first header type is the "Event" header. Other headers vary from event to event. Headers end with standard
termination. The last line of the manager response or event is an empty line. (
)

Please try to re-use existing headers to simplify manager message parsing in clients. Don't re-use an existing header with a new meaning, please. You can find a reference of standard headers in doc/manager.txt

Definition in file manager.h.


Define Documentation

#define ast_manager_register ( a,
b,
c,
 )     ast_manager_register2(a, b, c, d, NULL)

Definition at line 85 of file manager.h.

Referenced by astdb_init(), init_manager(), and load_module().

#define AST_MAX_MANHEADERS   128

Definition at line 60 of file manager.h.

Referenced by do_message(), and generic_http_callback().

#define DEFAULT_MANAGER_PORT   5038

Definition at line 48 of file manager.h.

Referenced by init_manager().

#define EVENT_FLAG_AGENT   (1 << 5)

#define EVENT_FLAG_CALL   (1 << 1)

#define EVENT_FLAG_COMMAND   (1 << 4)

Definition at line 54 of file manager.h.

Referenced by init_manager().

#define EVENT_FLAG_CONFIG   (1 << 7)

Definition at line 57 of file manager.h.

Referenced by init_manager().

#define EVENT_FLAG_LOG   (1 << 2)

Definition at line 52 of file manager.h.

#define EVENT_FLAG_SYSTEM   (1 << 0)

#define EVENT_FLAG_USER   (1 << 6)

Definition at line 56 of file manager.h.

Referenced by action_userevent(), aji_log_hook(), init_manager(), and userevent_exec().

#define EVENT_FLAG_VERBOSE   (1 << 3)

Definition at line 53 of file manager.h.


Function Documentation

int astman_verify_session_readpermissions ( uint32_t  ident,
int  perm 
)

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

Parameters:
ident session identity
perm permission mask to verify
Returns:
1 if the session has the permission mask capabilities, otherwise 0

Definition at line 2841 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::list, mansession_session::managerid, mansession_session::readperm, and s.

02842 {
02843    int result = 0;
02844    struct mansession_session *s;
02845 
02846    AST_LIST_LOCK(&sessions);
02847    AST_LIST_TRAVERSE(&sessions, s, list) {
02848       ast_mutex_lock(&s->__lock);
02849       if ((s->managerid == ident) && (s->readperm & perm)) {
02850          result = 1;
02851          ast_mutex_unlock(&s->__lock);
02852          break;
02853       }
02854       ast_mutex_unlock(&s->__lock);
02855    }
02856    AST_LIST_UNLOCK(&sessions);
02857    return result;
02858 }

int astman_verify_session_writepermissions ( uint32_t  ident,
int  perm 
)

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

Parameters:
ident session identity
perm permission mask to verify
Returns:
1 if the session has the permission mask capabilities, otherwise 0

Definition at line 2860 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::list, mansession_session::managerid, s, and mansession_session::writeperm.

02861 {
02862    int result = 0;
02863    struct mansession_session *s;
02864 
02865    AST_LIST_LOCK(&sessions);
02866    AST_LIST_TRAVERSE(&sessions, s, list) {
02867       ast_mutex_lock(&s->__lock);
02868       if ((s->managerid == ident) && (s->writeperm & perm)) {
02869          result = 1;
02870          ast_mutex_unlock(&s->__lock);
02871          break;
02872       }
02873       ast_mutex_unlock(&s->__lock);
02874    }
02875    AST_LIST_UNLOCK(&sessions);
02876    return result;
02877 }

int init_manager ( void   ) 

Called by Asterisk initialization

Definition at line 3129 of file manager.c.

References accept_thread(), action_command(), action_events(), action_extensionstate(), action_getconfig(), action_getvar(), action_hangup(), action_listcommands(), action_logoff(), action_mailboxcount(), action_mailboxstatus(), action_originate(), action_ping(), action_redirect(), action_setvar(), action_status(), action_timeout(), action_updateconfig(), action_userevent(), action_waitevent(), append_event(), ast_calloc, ast_category_browse(), ast_cli_register_multiple(), ast_config_destroy(), ast_config_load(), ast_copy_string(), ast_extension_state_add(), ast_get_manager_by_name_locked(), ast_http_uri_link(), ast_http_uri_unlink(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_manager_register, ast_manager_register2(), ast_pthread_create_background, ast_strdup, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verbose(), cli_manager, DEFAULT_MANAGER_PORT, ast_manager_user::deny, ast_manager_user::displayconnects, errno, EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, EVENT_FLAG_CONFIG, EVENT_FLAG_USER, ast_channel::flags, free, ast_manager_user::keep, mansession_session::list, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_state_cb(), manageruri, managerxmluri, mandescr_command, mandescr_events, mandescr_extensionstate, mandescr_getconfig, mandescr_getvar, mandescr_hangup, mandescr_listcommands, mandescr_logoff, mandescr_mailboxcount, mandescr_mailboxstatus, mandescr_originate, mandescr_ping, mandescr_redirect, mandescr_setvar, mandescr_timeout, mandescr_updateconfig, mandescr_userevent, mandescr_waitevent, ast_variable::name, ast_variable::next, option_verbose, ast_manager_user::permit, rawmanuri, ast_manager_user::read, registered, ast_manager_user::secret, ast_manager_user::username, ast_variable::value, var, webregged, and ast_manager_user::write.

Referenced by main(), and reload_manager().

03130 {
03131    struct ast_config *cfg = NULL, *ucfg = NULL;
03132    const char *val;
03133    char *cat = NULL;
03134    int oldportno = portno;
03135    static struct sockaddr_in ba;
03136    int x = 1;
03137    int flags;
03138    int webenabled = DEFAULT_WEBENABLED;
03139    int newhttptimeout = DEFAULT_HTTPTIMEOUT;
03140    struct ast_manager_user *user = NULL;
03141 
03142    if (!registered) {
03143       /* Register default actions */
03144       ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
03145       ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
03146       ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
03147       ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
03148       ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
03149       ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
03150       ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
03151       ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
03152       ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
03153       ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
03154       ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
03155       ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
03156       ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
03157       ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
03158       ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
03159       ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
03160       ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
03161       ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
03162       ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
03163 
03164       ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
03165       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
03166       registered = 1;
03167       /* Append placeholder event so master_eventq never runs dry */
03168       append_event("Event: Placeholder\r\n\r\n", 0);
03169    }
03170 
03171    portno = DEFAULT_MANAGER_PORT;
03172    displayconnects = DEFAULT_DISPLAYCONNECTS;
03173    broken_events_action = DEFAULT_BROKENEVENTSACTION;
03174    block_sockets = DEFAULT_BLOCKSOCKETS;
03175    timestampevents = DEFAULT_TIMESTAMPEVENTS;
03176    httptimeout = DEFAULT_HTTPTIMEOUT;
03177    authtimeout = DEFAULT_AUTHTIMEOUT;
03178    authlimit = DEFAULT_AUTHLIMIT;
03179 
03180    cfg = ast_config_load("manager.conf");
03181    if (!cfg) {
03182       ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
03183       return 0;
03184    }
03185    val = ast_variable_retrieve(cfg, "general", "enabled");
03186    if (val)
03187       enabled = ast_true(val);
03188 
03189    val = ast_variable_retrieve(cfg, "general", "block-sockets");
03190    if (val)
03191       block_sockets = ast_true(val);
03192 
03193    val = ast_variable_retrieve(cfg, "general", "webenabled");
03194    if (val)
03195       webenabled = ast_true(val);
03196 
03197    if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
03198       if (sscanf(val, "%5d", &portno) != 1) {
03199          ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
03200          portno = DEFAULT_MANAGER_PORT;
03201       }
03202    }
03203 
03204    if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
03205       displayconnects = ast_true(val);
03206 
03207    if ((val = ast_variable_retrieve(cfg, "general", "brokeneventsaction")))
03208       broken_events_action = ast_true(val);
03209 
03210    if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
03211       timestampevents = ast_true(val);
03212 
03213    if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
03214       newhttptimeout = atoi(val);
03215 
03216    if ((val = ast_variable_retrieve(cfg, "general", "authtimeout"))) {
03217       int timeout = atoi(val);
03218 
03219       if (timeout < 1) {
03220          ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", val);
03221       } else {
03222          authtimeout = timeout;
03223       }
03224    }
03225 
03226    if ((val = ast_variable_retrieve(cfg, "general", "authlimit"))) {
03227       int limit = atoi(val);
03228 
03229       if (limit < 1) {
03230          ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", val);
03231       } else {
03232          authlimit = limit;
03233       }
03234    }
03235 
03236    memset(&ba, 0, sizeof(ba));
03237    ba.sin_family = AF_INET;
03238    ba.sin_port = htons(portno);
03239 
03240    if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
03241       if (!inet_aton(val, &ba.sin_addr)) { 
03242          ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
03243          memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
03244       }
03245    }
03246    
03247 
03248    if ((asock > -1) && ((portno != oldportno) || !enabled)) {
03249 #if 0
03250       /* Can't be done yet */
03251       close(asock);
03252       asock = -1;
03253 #else
03254       ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
03255 #endif
03256    }
03257 
03258    AST_LIST_LOCK(&users);
03259 
03260    if ((ucfg = ast_config_load("users.conf"))) {
03261       while ((cat = ast_category_browse(ucfg, cat))) {
03262          int hasmanager = 0;
03263          struct ast_variable *var = NULL;
03264 
03265          if (!strcasecmp(cat, "general")) {
03266             continue;
03267          }
03268 
03269          if (!(hasmanager = ast_true(ast_variable_retrieve(ucfg, cat, "hasmanager")))) {
03270             continue;
03271          }
03272 
03273          /* Look for an existing entry, if none found - create one and add it to the list */
03274          if (!(user = ast_get_manager_by_name_locked(cat))) {
03275             if (!(user = ast_calloc(1, sizeof(*user)))) {
03276                break;
03277             }
03278             /* Copy name over */
03279             ast_copy_string(user->username, cat, sizeof(user->username));
03280             /* Insert into list */
03281             AST_LIST_INSERT_TAIL(&users, user, list);
03282          }
03283 
03284          /* Make sure we keep this user and don't destroy it during cleanup */
03285          user->keep = 1;
03286 
03287          for (var = ast_variable_browse(ucfg, cat); var; var = var->next) {
03288             if (!strcasecmp(var->name, "secret")) {
03289                if (user->secret) {
03290                   free(user->secret);
03291                }
03292                user->secret = ast_strdup(var->value);
03293             } else if (!strcasecmp(var->name, "deny") ) {
03294                if (user->deny) {
03295                   free(user->deny);
03296                }
03297                user->deny = ast_strdup(var->value);
03298             } else if (!strcasecmp(var->name, "permit") ) {
03299                if (user->permit) {
03300                   free(user->permit);
03301                }
03302                user->permit = ast_strdup(var->value);
03303             } else if (!strcasecmp(var->name, "read") ) {
03304                if (user->read) {
03305                   free(user->read);
03306                }
03307                user->read = ast_strdup(var->value);
03308             } else if (!strcasecmp(var->name, "write") ) {
03309                if (user->write) {
03310                   free(user->write);
03311                }
03312                user->write = ast_strdup(var->value);
03313             } else if (!strcasecmp(var->name, "displayconnects") ) {
03314                user->displayconnects = ast_true(var->value);
03315             } else if (!strcasecmp(var->name, "hasmanager")) {
03316                /* already handled */
03317             } else {
03318                ast_log(LOG_DEBUG, "%s is an unknown option (to the manager module).\n", var->name);
03319             }
03320          }
03321       }
03322       ast_config_destroy(ucfg);
03323    }
03324 
03325    while ((cat = ast_category_browse(cfg, cat))) {
03326       struct ast_variable *var = NULL;
03327 
03328       if (!strcasecmp(cat, "general"))
03329          continue;
03330 
03331       /* Look for an existing entry, if none found - create one and add it to the list */
03332       if (!(user = ast_get_manager_by_name_locked(cat))) {
03333          if (!(user = ast_calloc(1, sizeof(*user))))
03334             break;
03335          /* Copy name over */
03336          ast_copy_string(user->username, cat, sizeof(user->username));
03337          /* Insert into list */
03338          AST_LIST_INSERT_TAIL(&users, user, list);
03339       }
03340 
03341       /* Make sure we keep this user and don't destroy it during cleanup */
03342       user->keep = 1;
03343 
03344       var = ast_variable_browse(cfg, cat);
03345       while (var) {
03346          if (!strcasecmp(var->name, "secret")) {
03347             if (user->secret)
03348                free(user->secret);
03349             user->secret = ast_strdup(var->value);
03350          } else if (!strcasecmp(var->name, "deny") ) {
03351             if (user->deny)
03352                free(user->deny);
03353             user->deny = ast_strdup(var->value);
03354          } else if (!strcasecmp(var->name, "permit") ) {
03355             if (user->permit)
03356                free(user->permit);
03357             user->permit = ast_strdup(var->value);
03358          }  else if (!strcasecmp(var->name, "read") ) {
03359             if (user->read)
03360                free(user->read);
03361             user->read = ast_strdup(var->value);
03362          }  else if (!strcasecmp(var->name, "write") ) {
03363             if (user->write)
03364                free(user->write);
03365             user->write = ast_strdup(var->value);
03366          }  else if (!strcasecmp(var->name, "displayconnects") )
03367             user->displayconnects = ast_true(var->value);
03368          else
03369             ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
03370          var = var->next;
03371       }
03372    }
03373 
03374    /* Perform cleanup - essentially prune out old users that no longer exist */
03375    AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
03376       if (user->keep) {
03377          user->keep = 0;
03378          continue;
03379       }
03380       /* We do not need to keep this user so take them out of the list */
03381       AST_LIST_REMOVE_CURRENT(&users, list);
03382       /* Free their memory now */
03383       if (user->secret)
03384          free(user->secret);
03385       if (user->deny)
03386          free(user->deny);
03387       if (user->permit)
03388          free(user->permit);
03389       if (user->read)
03390          free(user->read);
03391       if (user->write)
03392          free(user->write);
03393       free(user);
03394    }
03395    AST_LIST_TRAVERSE_SAFE_END
03396 
03397    AST_LIST_UNLOCK(&users);
03398 
03399    ast_config_destroy(cfg);
03400    
03401    if (webenabled && enabled) {
03402       if (!webregged) {
03403          ast_http_uri_link(&rawmanuri);
03404          ast_http_uri_link(&manageruri);
03405          ast_http_uri_link(&managerxmluri);
03406          webregged = 1;
03407       }
03408    } else {
03409       if (webregged) {
03410          ast_http_uri_unlink(&rawmanuri);
03411          ast_http_uri_unlink(&manageruri);
03412          ast_http_uri_unlink(&managerxmluri);
03413          webregged = 0;
03414       }
03415    }
03416 
03417    if (newhttptimeout > 0)
03418       httptimeout = newhttptimeout;
03419 
03420    /* If not enabled, do nothing */
03421    if (!enabled)
03422       return 0;
03423 
03424    if (asock < 0) {
03425       asock = socket(AF_INET, SOCK_STREAM, 0);
03426       if (asock < 0) {
03427          ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
03428          return -1;
03429       }
03430       setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
03431       if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
03432          ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
03433          close(asock);
03434          asock = -1;
03435          return -1;
03436       }
03437       if (listen(asock, 2)) {
03438          ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
03439          close(asock);
03440          asock = -1;
03441          return -1;
03442       }
03443       flags = fcntl(asock, F_GETFL);
03444       fcntl(asock, F_SETFL, flags | O_NONBLOCK);
03445       if (option_verbose)
03446          ast_verbose("Asterisk Management interface listening on port %d\n", portno);
03447       ast_pthread_create_background(&t, NULL, accept_thread, NULL);
03448    }
03449    return 0;
03450 }

int reload_manager ( void   ) 

Definition at line 3452 of file manager.c.

References EVENT_FLAG_SYSTEM, init_manager(), and manager_event().

03453 {
03454    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
03455    return init_manager();
03456 }


Generated on Thu Oct 11 06:43:59 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6