2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief The Asterisk Management Interface - AMI
23 * \author Mark Spencer <markster@digium.com>
25 * Channel Management and more
30 /*! \addtogroup Group_AMI AMI functions
39 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
51 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53 #include "asterisk/channel.h"
54 #include "asterisk/file.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/config.h"
57 #include "asterisk/callerid.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/logger.h"
60 #include "asterisk/options.h"
61 #include "asterisk/cli.h"
62 #include "asterisk/app.h"
63 #include "asterisk/pbx.h"
64 #include "asterisk/md5.h"
65 #include "asterisk/acl.h"
66 #include "asterisk/utils.h"
68 struct fast_originate_helper {
80 struct ast_variable *vars;
83 static int enabled = 0;
84 static int portno = DEFAULT_MANAGER_PORT;
85 static int asock = -1;
86 static int displayconnects = 1;
87 static int timestampevents = 0;
90 AST_MUTEX_DEFINE_STATIC(sessionlock);
91 static int block_sockets = 0;
93 static struct permalias {
97 { EVENT_FLAG_SYSTEM, "system" },
98 { EVENT_FLAG_CALL, "call" },
99 { EVENT_FLAG_LOG, "log" },
100 { EVENT_FLAG_VERBOSE, "verbose" },
101 { EVENT_FLAG_COMMAND, "command" },
102 { EVENT_FLAG_AGENT, "agent" },
103 { EVENT_FLAG_USER, "user" },
108 static struct mansession *sessions = NULL;
109 static struct manager_action *first_action = NULL;
110 AST_MUTEX_DEFINE_STATIC(actionlock);
112 /*! If you are calling ast_carefulwrite, it is assumed that you are calling
113 it on a file descriptor that _DOES_ have NONBLOCK set. This way,
114 there is only one system call made to do a write, unless we actually
115 have a need to wait. This way, we get better performance. */
116 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
118 /* Try to write string, but wait no more than ms milliseconds
121 struct pollfd fds[1];
123 res = write(fd, s, len);
124 if ((res < 0) && (errno != EAGAIN)) {
127 if (res < 0) res = 0;
133 fds[0].events = POLLOUT;
134 /* Wait until writable again */
135 res = poll(fds, 1, timeoutms);
143 /*! authority_to_str: Convert authority code to string with serveral options */
144 static char *authority_to_str(int authority, char *res, int reslen)
146 int running_total = 0, i;
147 memset(res, 0, reslen);
148 for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
149 if (authority & perms[i].num) {
151 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
154 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
155 running_total += strlen(perms[i].label);
158 if (ast_strlen_zero(res)) {
159 ast_copy_string(res, "<none>", reslen);
164 static char *complete_show_mancmd(char *line, char *word, int pos, int state)
166 struct manager_action *cur = first_action;
169 ast_mutex_lock(&actionlock);
170 while (cur) { /* Walk the list of actions */
171 if (!strncasecmp(word, cur->action, strlen(word))) {
172 if (++which > state) {
173 char *ret = strdup(cur->action);
174 ast_mutex_unlock(&actionlock);
180 ast_mutex_unlock(&actionlock);
184 static int handle_showmancmd(int fd, int argc, char *argv[])
186 struct manager_action *cur = first_action;
191 return RESULT_SHOWUSAGE;
192 ast_mutex_lock(&actionlock);
193 while (cur) { /* Walk the list of actions */
194 for (num = 3; num < argc; num++) {
195 if (!strcasecmp(cur->action, argv[num])) {
196 ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
202 ast_mutex_unlock(&actionlock);
203 return RESULT_SUCCESS;
206 /*! \brief handle_showmancmds: CLI command */
207 /* Should change to "manager show commands" */
208 static int handle_showmancmds(int fd, int argc, char *argv[])
210 struct manager_action *cur = first_action;
212 char *format = " %-15.15s %-15.15s %-55.55s\n";
214 ast_mutex_lock(&actionlock);
215 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
216 ast_cli(fd, format, "------", "---------", "--------");
217 while (cur) { /* Walk the list of actions */
218 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
222 ast_mutex_unlock(&actionlock);
223 return RESULT_SUCCESS;
226 /*! \brief handle_showmanconn: CLI command show manager connected */
227 /* Should change to "manager show connected" */
228 static int handle_showmanconn(int fd, int argc, char *argv[])
230 struct mansession *s;
231 char iabuf[INET_ADDRSTRLEN];
232 char *format = " %-15.15s %-15.15s\n";
233 ast_mutex_lock(&sessionlock);
235 ast_cli(fd, format, "Username", "IP Address");
237 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
241 ast_mutex_unlock(&sessionlock);
242 return RESULT_SUCCESS;
245 static char showmancmd_help[] =
246 "Usage: show manager command <actionname>\n"
247 " Shows the detailed description for a specific Asterisk manager interface command.\n";
249 static char showmancmds_help[] =
250 "Usage: show manager commands\n"
251 " Prints a listing of all the available Asterisk manager interface commands.\n";
253 static char showmanconn_help[] =
254 "Usage: show manager connected\n"
255 " Prints a listing of the users that are currently connected to the\n"
256 "Asterisk manager interface.\n";
258 static struct ast_cli_entry show_mancmd_cli =
259 { { "show", "manager", "command", NULL },
260 handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
262 static struct ast_cli_entry show_mancmds_cli =
263 { { "show", "manager", "commands", NULL },
264 handle_showmancmds, "List manager interface commands", showmancmds_help };
266 static struct ast_cli_entry show_manconn_cli =
267 { { "show", "manager", "connected", NULL },
268 handle_showmanconn, "Show connected manager interface users", showmanconn_help };
270 static void free_session(struct mansession *s)
272 struct eventqent *eqe;
275 ast_mutex_destroy(&s->__lock);
278 s->eventq = s->eventq->next;
284 static void destroy_session(struct mansession *s)
286 struct mansession *cur, *prev = NULL;
287 ast_mutex_lock(&sessionlock);
297 prev->next = cur->next;
299 sessions = cur->next;
302 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
303 ast_mutex_unlock(&sessionlock);
307 char *astman_get_header(struct message *m, char *var)
311 snprintf(cmp, sizeof(cmp), "%s: ", var);
312 for (x=0;x<m->hdrcount;x++)
313 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
314 return m->headers[x] + strlen(cmp);
318 struct ast_variable *astman_get_variables(struct message *m)
321 struct ast_variable *head = NULL, *cur;
323 unsigned int var_count;
326 varlen = strlen("Variable: ");
328 for (x = 0; x < m->hdrcount; x++) {
329 if (strncasecmp("Variable: ", m->headers[x], varlen))
332 if (!(var = ast_strdupa(m->headers[x] + varlen)))
335 if ((var_count = ast_app_separate_args(var, '|', vars, sizeof(vars) / sizeof(vars[0])))) {
336 for (y = 0; y < var_count; y++) {
339 var = val = ast_strdupa(vars[y]);
341 if (!val || ast_strlen_zero(var))
343 cur = ast_variable_new(var, val);
357 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
358 hold the session lock _or_ be running in an action callback (in which case s->busy will
359 be non-zero). In either of these cases, there is no need to lock-protect the session's
360 fd, since no other output will be sent (events will be queued), and no input will
361 be read until either the current action finishes or get_input() obtains the session
364 void astman_send_error(struct mansession *s, struct message *m, char *error)
366 char *id = astman_get_header(m,"ActionID");
368 ast_cli(s->fd, "Response: Error\r\n");
369 if (!ast_strlen_zero(id))
370 ast_cli(s->fd, "ActionID: %s\r\n",id);
371 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
374 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
376 char *id = astman_get_header(m,"ActionID");
378 ast_cli(s->fd, "Response: %s\r\n", resp);
379 if (!ast_strlen_zero(id))
380 ast_cli(s->fd, "ActionID: %s\r\n",id);
382 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
384 ast_cli(s->fd, "\r\n");
387 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
389 astman_send_response(s, m, "Success", msg);
392 /*! Tells you if smallstr exists inside bigstr
393 which is delim by delim and uses no buf or stringsep
394 ast_instring("this|that|more","this",',') == 1;
396 feel free to move this to app.c -anthm */
397 static int ast_instring(char *bigstr, char *smallstr, char delim)
399 char *val = bigstr, *next;
402 if ((next = strchr(val, delim))) {
403 if (!strncmp(val, smallstr, (next - val)))
408 return !strcmp(smallstr, val);
410 } while (*(val = (next + 1)));
415 static int get_perm(char *instr)
422 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
423 if (ast_instring(instr, perms[x].label, ','))
429 static int ast_is_number(char *string)
436 for (x=0; x < strlen(string); x++) {
437 if (!(string[x] >= 48 && string[x] <= 57)) {
443 return ret ? atoi(string) : 0;
446 static int ast_strings_to_mask(char *string)
450 x = ast_is_number(string);
454 } else if (ast_strlen_zero(string)) {
456 } else if (ast_false(string)) {
458 } else if (ast_true(string)) {
460 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
464 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
465 if (ast_instring(string, perms[x].label, ','))
474 Rather than braindead on,off this now can also accept a specific int mask value
475 or a ',' delim list of mask strings (the same as manager.conf) -anthm
478 static int set_eventmask(struct mansession *s, char *eventmask)
480 int maskint = ast_strings_to_mask(eventmask);
482 ast_mutex_lock(&s->__lock);
484 s->send_events = maskint;
485 ast_mutex_unlock(&s->__lock);
490 static int authenticate(struct mansession *s, struct message *m)
492 struct ast_config *cfg;
493 char iabuf[INET_ADDRSTRLEN];
495 char *user = astman_get_header(m, "Username");
496 char *pass = astman_get_header(m, "Secret");
497 char *authtype = astman_get_header(m, "AuthType");
498 char *key = astman_get_header(m, "Key");
499 char *events = astman_get_header(m, "Events");
501 cfg = ast_config_load("manager.conf");
504 cat = ast_category_browse(cfg, NULL);
506 if (strcasecmp(cat, "general")) {
508 if (!strcasecmp(cat, user)) {
509 struct ast_variable *v;
510 struct ast_ha *ha = NULL;
511 char *password = NULL;
512 v = ast_variable_browse(cfg, cat);
514 if (!strcasecmp(v->name, "secret")) {
516 } else if (!strcasecmp(v->name, "permit") ||
517 !strcasecmp(v->name, "deny")) {
518 ha = ast_append_ha(v->name, v->value, ha);
519 } else if (!strcasecmp(v->name, "writetimeout")) {
520 int val = atoi(v->value);
523 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
525 s->writetimeout = val;
530 if (ha && !ast_apply_ha(ha, &(s->sin))) {
531 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
533 ast_config_destroy(cfg);
537 if (!strcasecmp(authtype, "MD5")) {
538 if (!ast_strlen_zero(key) && s->challenge) {
541 char md5key[256] = "";
542 struct MD5Context md5;
543 unsigned char digest[16];
545 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
546 MD5Update(&md5, (unsigned char *) password, strlen(password));
547 MD5Final(digest, &md5);
549 len += sprintf(md5key + len, "%2.2x", digest[x]);
550 if (!strcmp(md5key, key))
553 ast_config_destroy(cfg);
557 } else if (password && !strcasecmp(password, pass)) {
560 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
561 ast_config_destroy(cfg);
566 cat = ast_category_browse(cfg, cat);
569 ast_copy_string(s->username, cat, sizeof(s->username));
570 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
571 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
572 ast_config_destroy(cfg);
574 set_eventmask(s, events);
577 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
578 ast_config_destroy(cfg);
582 /*! \brief PING: Manager PING */
583 static char mandescr_ping[] =
584 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
585 " manager connection open.\n"
588 static int action_ping(struct mansession *s, struct message *m)
590 astman_send_response(s, m, "Pong", NULL);
594 static char mandescr_listcommands[] =
595 "Description: Returns the action name and synopsis for every\n"
596 " action that is available to the user\n"
599 static int action_listcommands(struct mansession *s, struct message *m)
601 struct manager_action *cur = first_action;
602 char idText[256] = "";
604 char *id = astman_get_header(m,"ActionID");
606 if (!ast_strlen_zero(id))
607 snprintf(idText,256,"ActionID: %s\r\n",id);
608 ast_cli(s->fd, "Response: Success\r\n%s", idText);
609 ast_mutex_lock(&actionlock);
610 while (cur) { /* Walk the list of actions */
611 if ((s->writeperm & cur->authority) == cur->authority)
612 ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
615 ast_mutex_unlock(&actionlock);
616 ast_cli(s->fd, "\r\n");
621 static char mandescr_events[] =
622 "Description: Enable/Disable sending of events to this manager\n"
625 " EventMask: 'on' if all events should be sent,\n"
626 " 'off' if no events should be sent,\n"
627 " 'system,call,log' to select which flags events should have to be sent.\n";
629 static int action_events(struct mansession *s, struct message *m)
631 char *mask = astman_get_header(m, "EventMask");
634 res = set_eventmask(s, mask);
636 astman_send_response(s, m, "Events On", NULL);
638 astman_send_response(s, m, "Events Off", NULL);
643 static char mandescr_logoff[] =
644 "Description: Logoff this manager session\n"
647 static int action_logoff(struct mansession *s, struct message *m)
649 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
653 static char mandescr_hangup[] =
654 "Description: Hangup a channel\n"
656 " Channel: The channel name to be hungup\n";
658 static int action_hangup(struct mansession *s, struct message *m)
660 struct ast_channel *c = NULL;
661 char *name = astman_get_header(m, "Channel");
662 if (ast_strlen_zero(name)) {
663 astman_send_error(s, m, "No channel specified");
666 c = ast_get_channel_by_name_locked(name);
668 astman_send_error(s, m, "No such channel");
671 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
672 ast_mutex_unlock(&c->lock);
673 astman_send_ack(s, m, "Channel Hungup");
677 static char mandescr_setvar[] =
678 "Description: Set a global or local channel variable.\n"
679 "Variables: (Names marked with * are required)\n"
680 " Channel: Channel to set variable for\n"
681 " *Variable: Variable name\n"
684 static int action_setvar(struct mansession *s, struct message *m)
686 struct ast_channel *c = NULL;
687 char *name = astman_get_header(m, "Channel");
688 char *varname = astman_get_header(m, "Variable");
689 char *varval = astman_get_header(m, "Value");
691 if (ast_strlen_zero(varname)) {
692 astman_send_error(s, m, "No variable specified");
696 if (ast_strlen_zero(varval)) {
697 astman_send_error(s, m, "No value specified");
701 if (!ast_strlen_zero(name)) {
702 c = ast_get_channel_by_name_locked(name);
704 astman_send_error(s, m, "No such channel");
709 pbx_builtin_setvar_helper(c, varname, varval);
712 ast_mutex_unlock(&c->lock);
714 astman_send_ack(s, m, "Variable Set");
719 static char mandescr_getvar[] =
720 "Description: Get the value of a global or local channel variable.\n"
721 "Variables: (Names marked with * are required)\n"
722 " Channel: Channel to read variable from\n"
723 " *Variable: Variable name\n"
724 " ActionID: Optional Action id for message matching.\n";
726 static int action_getvar(struct mansession *s, struct message *m)
728 struct ast_channel *c = NULL;
729 char *name = astman_get_header(m, "Channel");
730 char *varname = astman_get_header(m, "Variable");
731 char *id = astman_get_header(m,"ActionID");
733 char workspace[1024];
735 if (ast_strlen_zero(varname)) {
736 astman_send_error(s, m, "No variable specified");
740 if (!ast_strlen_zero(name)) {
741 c = ast_get_channel_by_name_locked(name);
743 astman_send_error(s, m, "No such channel");
748 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
751 ast_mutex_unlock(&c->lock);
752 ast_cli(s->fd, "Response: Success\r\n"
753 "Variable: %s\r\nValue: %s\r\n", varname, varval);
754 if (!ast_strlen_zero(id))
755 ast_cli(s->fd, "ActionID: %s\r\n",id);
756 ast_cli(s->fd, "\r\n");
762 /*! \brief action_status: Manager "status" command to show channels */
763 /* Needs documentation... */
764 static int action_status(struct mansession *s, struct message *m)
766 char *id = astman_get_header(m,"ActionID");
767 char *name = astman_get_header(m,"Channel");
768 char idText[256] = "";
769 struct ast_channel *c;
771 struct timeval now = ast_tvnow();
772 long elapsed_seconds=0;
773 int all = ast_strlen_zero(name); /* set if we want all channels */
775 astman_send_ack(s, m, "Channel status will follow");
776 if (!ast_strlen_zero(id))
777 snprintf(idText,256,"ActionID: %s\r\n",id);
779 c = ast_channel_walk_locked(NULL);
781 c = ast_get_channel_by_name_locked(name);
783 astman_send_error(s, m, "No such channel");
787 /* if we look by name, we break after the first iteration */
790 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
795 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
799 "Privilege: Call\r\n"
802 "CallerIDName: %s\r\n"
814 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
815 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
817 ast_state2str(c->_state), c->context,
818 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
822 "Privilege: Call\r\n"
825 "CallerIDName: %s\r\n"
833 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
834 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
836 ast_state2str(c->_state), bridge, c->uniqueid, idText);
838 ast_mutex_unlock(&c->lock);
841 c = ast_channel_walk_locked(c);
844 "Event: StatusComplete\r\n"
850 static char mandescr_redirect[] =
851 "Description: Redirect (transfer) a call.\n"
852 "Variables: (Names marked with * are required)\n"
853 " *Channel: Channel to redirect\n"
854 " ExtraChannel: Second call leg to transfer (optional)\n"
855 " *Exten: Extension to transfer to\n"
856 " *Context: Context to transfer to\n"
857 " *Priority: Priority to transfer to\n"
858 " ActionID: Optional Action id for message matching.\n";
860 /*! \brief action_redirect: The redirect manager command */
861 static int action_redirect(struct mansession *s, struct message *m)
863 char *name = astman_get_header(m, "Channel");
864 char *name2 = astman_get_header(m, "ExtraChannel");
865 char *exten = astman_get_header(m, "Exten");
866 char *context = astman_get_header(m, "Context");
867 char *priority = astman_get_header(m, "Priority");
868 struct ast_channel *chan, *chan2 = NULL;
872 if (ast_strlen_zero(name)) {
873 astman_send_error(s, m, "Channel not specified");
876 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
877 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
878 astman_send_error(s, m, "Invalid priority\n");
882 chan = ast_get_channel_by_name_locked(name);
885 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
886 astman_send_error(s, m, buf);
889 if (!ast_strlen_zero(name2))
890 chan2 = ast_get_channel_by_name_locked(name2);
891 res = ast_async_goto(chan, context, exten, pi);
893 if (!ast_strlen_zero(name2)) {
895 res = ast_async_goto(chan2, context, exten, pi);
899 astman_send_ack(s, m, "Dual Redirect successful");
901 astman_send_error(s, m, "Secondary redirect failed");
903 astman_send_ack(s, m, "Redirect successful");
905 astman_send_error(s, m, "Redirect failed");
907 ast_mutex_unlock(&chan->lock);
909 ast_mutex_unlock(&chan2->lock);
913 static char mandescr_command[] =
914 "Description: Run a CLI command.\n"
915 "Variables: (Names marked with * are required)\n"
916 " *Command: Asterisk CLI command to run\n"
917 " ActionID: Optional Action id for message matching.\n";
919 /*! \brief action_command: Manager command "command" - execute CLI command */
920 static int action_command(struct mansession *s, struct message *m)
922 char *cmd = astman_get_header(m, "Command");
923 char *id = astman_get_header(m, "ActionID");
924 ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
925 if (!ast_strlen_zero(id))
926 ast_cli(s->fd, "ActionID: %s\r\n", id);
927 /* FIXME: Wedge a ActionID response in here, waiting for later changes */
928 ast_cli_command(s->fd, cmd);
929 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
933 static void *fast_originate(void *data)
935 struct fast_originate_helper *in = data;
938 struct ast_channel *chan = NULL;
940 if (!ast_strlen_zero(in->app)) {
941 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
942 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
943 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
946 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
947 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
948 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
952 /* Tell the manager what happened with the channel */
953 manager_event(EVENT_FLAG_CALL,
954 res ? "OriginateSuccess" : "OriginateFailure",
962 "CallerIDName: %s\r\n",
963 in->idtext, in->tech, in->data, in->context, in->exten, reason,
964 chan ? chan->uniqueid : "<null>",
965 in->cid_num ? in->cid_num : "<unknown>",
966 in->cid_name ? in->cid_name : "<unknown>"
969 /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
971 ast_mutex_unlock(&chan->lock);
976 static char mandescr_originate[] =
977 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
978 " Application/Data\n"
979 "Variables: (Names marked with * are required)\n"
980 " *Channel: Channel name to call\n"
981 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
982 " Context: Context to use (requires 'Exten' and 'Priority')\n"
983 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
984 " Application: Application to use\n"
985 " Data: Data to use (requires 'Application')\n"
986 " Timeout: How long to wait for call to be answered (in ms)\n"
987 " CallerID: Caller ID to be set on the outgoing channel\n"
988 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
989 " Account: Account code\n"
990 " Async: Set to 'true' for fast origination\n";
992 static int action_originate(struct mansession *s, struct message *m)
994 char *name = astman_get_header(m, "Channel");
995 char *exten = astman_get_header(m, "Exten");
996 char *context = astman_get_header(m, "Context");
997 char *priority = astman_get_header(m, "Priority");
998 char *timeout = astman_get_header(m, "Timeout");
999 char *callerid = astman_get_header(m, "CallerID");
1000 char *account = astman_get_header(m, "Account");
1001 char *app = astman_get_header(m, "Application");
1002 char *appdata = astman_get_header(m, "Data");
1003 char *async = astman_get_header(m, "Async");
1004 char *id = astman_get_header(m, "ActionID");
1005 struct ast_variable *vars = astman_get_variables(m);
1007 char *l=NULL, *n=NULL;
1016 pthread_attr_t attr;
1018 astman_send_error(s, m, "Channel not specified");
1021 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1022 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1023 astman_send_error(s, m, "Invalid priority\n");
1027 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1028 astman_send_error(s, m, "Invalid timeout\n");
1031 ast_copy_string(tmp, name, sizeof(tmp));
1033 data = strchr(tmp, '/');
1035 astman_send_error(s, m, "Invalid channel\n");
1040 ast_copy_string(tmp2, callerid, sizeof(tmp2));
1041 ast_callerid_parse(tmp2, &n, &l);
1043 if (ast_strlen_zero(n))
1047 ast_shrink_phone_number(l);
1048 if (ast_strlen_zero(l))
1052 struct ast_variable *newvar;
1053 newvar = ast_variable_new("CDR(accountcode|r)", account);
1054 newvar->next = vars;
1057 if (ast_true(async)) {
1058 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1062 memset(fast, 0, sizeof(struct fast_originate_helper));
1063 if (!ast_strlen_zero(id))
1064 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1065 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1066 ast_copy_string(fast->data, data, sizeof(fast->data));
1067 ast_copy_string(fast->app, app, sizeof(fast->app));
1068 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1070 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1072 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1074 ast_copy_string(fast->context, context, sizeof(fast->context));
1075 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1077 fast->priority = pi;
1078 pthread_attr_init(&attr);
1079 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1080 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1086 } else if (!ast_strlen_zero(app)) {
1087 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
1089 if (exten && context && pi)
1090 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
1092 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1097 astman_send_ack(s, m, "Originate successfully queued");
1099 astman_send_error(s, m, "Originate failed");
1103 /*! \brief Help text for manager command mailboxstatus
1105 static char mandescr_mailboxstatus[] =
1106 "Description: Checks a voicemail account for status.\n"
1107 "Variables: (Names marked with * are required)\n"
1108 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1109 " ActionID: Optional ActionID for message matching.\n"
1110 "Returns number of messages.\n"
1111 " Message: Mailbox Status\n"
1112 " Mailbox: <mailboxid>\n"
1113 " Waiting: <count>\n"
1116 static int action_mailboxstatus(struct mansession *s, struct message *m)
1118 char *mailbox = astman_get_header(m, "Mailbox");
1119 char *id = astman_get_header(m,"ActionID");
1120 char idText[256] = "";
1122 if (ast_strlen_zero(mailbox)) {
1123 astman_send_error(s, m, "Mailbox not specified");
1126 if (!ast_strlen_zero(id))
1127 snprintf(idText,256,"ActionID: %s\r\n",id);
1128 ret = ast_app_has_voicemail(mailbox, NULL);
1129 ast_cli(s->fd, "Response: Success\r\n"
1131 "Message: Mailbox Status\r\n"
1133 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1137 static char mandescr_mailboxcount[] =
1138 "Description: Checks a voicemail account for new messages.\n"
1139 "Variables: (Names marked with * are required)\n"
1140 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1141 " ActionID: Optional ActionID for message matching.\n"
1142 "Returns number of new and old messages.\n"
1143 " Message: Mailbox Message Count\n"
1144 " Mailbox: <mailboxid>\n"
1145 " NewMessages: <count>\n"
1146 " OldMessages: <count>\n"
1148 static int action_mailboxcount(struct mansession *s, struct message *m)
1150 char *mailbox = astman_get_header(m, "Mailbox");
1151 char *id = astman_get_header(m,"ActionID");
1152 char idText[256] = "";
1153 int newmsgs = 0, oldmsgs = 0;
1154 if (ast_strlen_zero(mailbox)) {
1155 astman_send_error(s, m, "Mailbox not specified");
1158 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1159 if (!ast_strlen_zero(id)) {
1160 snprintf(idText,256,"ActionID: %s\r\n",id);
1162 ast_cli(s->fd, "Response: Success\r\n"
1164 "Message: Mailbox Message Count\r\n"
1166 "NewMessages: %d\r\n"
1167 "OldMessages: %d\r\n"
1169 idText,mailbox, newmsgs, oldmsgs);
1173 static char mandescr_extensionstate[] =
1174 "Description: Report the extension state for given extension.\n"
1175 " If the extension has a hint, will use devicestate to check\n"
1176 " the status of the device connected to the extension.\n"
1177 "Variables: (Names marked with * are required)\n"
1178 " *Exten: Extension to check state on\n"
1179 " *Context: Context for extension\n"
1180 " ActionId: Optional ID for this transaction\n"
1181 "Will return an \"Extension Status\" message.\n"
1182 "The response will include the hint for the extension and the status.\n";
1184 static int action_extensionstate(struct mansession *s, struct message *m)
1186 char *exten = astman_get_header(m, "Exten");
1187 char *context = astman_get_header(m, "Context");
1188 char *id = astman_get_header(m,"ActionID");
1189 char idText[256] = "";
1190 char hint[256] = "";
1192 if (ast_strlen_zero(exten)) {
1193 astman_send_error(s, m, "Extension not specified");
1196 if (ast_strlen_zero(context))
1197 context = "default";
1198 status = ast_extension_state(NULL, context, exten);
1199 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1200 if (!ast_strlen_zero(id)) {
1201 snprintf(idText,256,"ActionID: %s\r\n",id);
1203 ast_cli(s->fd, "Response: Success\r\n"
1205 "Message: Extension Status\r\n"
1209 "Status: %d\r\n\r\n",
1210 idText,exten, context, hint, status);
1214 static char mandescr_timeout[] =
1215 "Description: Hangup a channel after a certain time.\n"
1216 "Variables: (Names marked with * are required)\n"
1217 " *Channel: Channel name to hangup\n"
1218 " *Timeout: Maximum duration of the call (sec)\n"
1219 "Acknowledges set time with 'Timeout Set' message\n";
1221 static int action_timeout(struct mansession *s, struct message *m)
1223 struct ast_channel *c = NULL;
1224 char *name = astman_get_header(m, "Channel");
1225 int timeout = atoi(astman_get_header(m, "Timeout"));
1226 if (ast_strlen_zero(name)) {
1227 astman_send_error(s, m, "No channel specified");
1231 astman_send_error(s, m, "No timeout specified");
1234 c = ast_get_channel_by_name_locked(name);
1236 astman_send_error(s, m, "No such channel");
1239 ast_channel_setwhentohangup(c, timeout);
1240 ast_mutex_unlock(&c->lock);
1241 astman_send_ack(s, m, "Timeout Set");
1245 static int process_message(struct mansession *s, struct message *m)
1247 char action[80] = "";
1248 struct manager_action *tmp = first_action;
1249 char *id = astman_get_header(m,"ActionID");
1250 char idText[256] = "";
1251 char iabuf[INET_ADDRSTRLEN];
1253 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1254 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1256 if (ast_strlen_zero(action)) {
1257 astman_send_error(s, m, "Missing action in request");
1260 if (!ast_strlen_zero(id)) {
1261 snprintf(idText,256,"ActionID: %s\r\n",id);
1263 if (!s->authenticated) {
1264 if (!strcasecmp(action, "Challenge")) {
1266 authtype = astman_get_header(m, "AuthType");
1267 if (!strcasecmp(authtype, "MD5")) {
1268 if (ast_strlen_zero(s->challenge))
1269 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
1270 ast_mutex_lock(&s->__lock);
1271 ast_cli(s->fd, "Response: Success\r\n"
1273 "Challenge: %s\r\n\r\n",
1274 idText,s->challenge);
1275 ast_mutex_unlock(&s->__lock);
1278 astman_send_error(s, m, "Must specify AuthType");
1281 } else if (!strcasecmp(action, "Login")) {
1282 if (authenticate(s, m)) {
1284 astman_send_error(s, m, "Authentication failed");
1287 s->authenticated = 1;
1288 if (option_verbose > 1) {
1289 if ( displayconnects ) {
1290 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1293 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1294 astman_send_ack(s, m, "Authentication accepted");
1296 } else if (!strcasecmp(action, "Logoff")) {
1297 astman_send_ack(s, m, "See ya");
1300 astman_send_error(s, m, "Authentication Required");
1303 struct eventqent *eqe;
1304 ast_mutex_lock(&s->__lock);
1306 ast_mutex_unlock(&s->__lock);
1308 if (!strcasecmp(action, tmp->action)) {
1309 if ((s->writeperm & tmp->authority) == tmp->authority) {
1310 if (tmp->func(s, m))
1313 astman_send_error(s, m, "Permission denied");
1320 astman_send_error(s, m, "Invalid/unknown command");
1321 ast_mutex_lock(&s->__lock);
1324 if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
1329 s->eventq = s->eventq->next;
1332 ast_mutex_unlock(&s->__lock);
1338 static int get_input(struct mansession *s, char *output)
1340 /* output must have at least sizeof(s->inbuf) space */
1343 struct pollfd fds[1];
1344 char iabuf[INET_ADDRSTRLEN];
1345 for (x=1;x<s->inlen;x++) {
1346 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1347 /* Copy output data up to and including \r\n */
1348 memcpy(output, s->inbuf, x + 1);
1349 /* Add trailing \0 */
1351 /* Move remaining data back to the front */
1352 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1353 s->inlen -= (x + 1);
1357 if (s->inlen >= sizeof(s->inbuf) - 1) {
1358 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
1362 fds[0].events = POLLIN;
1364 res = poll(fds, 1, -1);
1366 if (errno == EINTR) {
1371 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1373 } else if (res > 0) {
1374 ast_mutex_lock(&s->__lock);
1375 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1376 ast_mutex_unlock(&s->__lock);
1383 s->inbuf[s->inlen] = '\0';
1387 static void *session_do(void *data)
1389 struct mansession *s = data;
1391 char iabuf[INET_ADDRSTRLEN];
1394 ast_mutex_lock(&s->__lock);
1395 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
1396 ast_mutex_unlock(&s->__lock);
1397 memset(&m, 0, sizeof(m));
1399 res = get_input(s, m.headers[m.hdrcount]);
1401 /* Strip trailing \r\n */
1402 if (strlen(m.headers[m.hdrcount]) < 2)
1404 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1405 if (ast_strlen_zero(m.headers[m.hdrcount])) {
1406 if (process_message(s, &m))
1408 memset(&m, 0, sizeof(m));
1409 } else if (m.hdrcount < MAX_HEADERS - 1)
1414 if (s->authenticated) {
1415 if (option_verbose > 1) {
1416 if (displayconnects)
1417 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1419 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1421 if (option_verbose > 1) {
1422 if ( displayconnects )
1423 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1425 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1431 static void *accept_thread(void *ignore)
1434 struct sockaddr_in sin;
1436 struct mansession *s;
1440 pthread_attr_t attr;
1442 pthread_attr_init(&attr);
1443 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1446 sinlen = sizeof(sin);
1447 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1449 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1452 p = getprotobyname("tcp");
1454 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1455 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1458 s = malloc(sizeof(struct mansession));
1460 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1463 memset(s, 0, sizeof(struct mansession));
1464 memcpy(&s->sin, &sin, sizeof(sin));
1465 s->writetimeout = 100;
1467 if(! block_sockets) {
1468 /* For safety, make sure socket is non-blocking */
1469 flags = fcntl(as, F_GETFL);
1470 fcntl(as, F_SETFL, flags | O_NONBLOCK);
1472 ast_mutex_init(&s->__lock);
1474 s->send_events = -1;
1475 ast_mutex_lock(&sessionlock);
1478 ast_mutex_unlock(&sessionlock);
1479 if (ast_pthread_create(&s->t, &attr, session_do, s))
1482 pthread_attr_destroy(&attr);
1486 static int append_event(struct mansession *s, const char *str)
1488 struct eventqent *tmp, *prev=NULL;
1489 tmp = malloc(sizeof(struct eventqent) + strlen(str));
1492 strcpy(tmp->eventdata, str);
1506 /*! \brief manager_event: Send AMI event to client */
1507 int manager_event(int category, char *event, char *fmt, ...)
1509 struct mansession *s;
1511 char tmp[4096] = "";
1512 char *tmp_next = tmp;
1513 size_t tmp_left = sizeof(tmp) - 2;
1516 ast_mutex_lock(&sessionlock);
1517 for (s = sessions; s; s = s->next) {
1518 if ((s->readperm & category) != category)
1521 if ((s->send_events & category) != category)
1524 if (ast_strlen_zero(tmp)) {
1527 ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1528 event, authority_to_str(category, auth, sizeof(auth)));
1529 if (timestampevents) {
1531 ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n",
1532 now.tv_sec, now.tv_usec);
1535 ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1542 ast_mutex_lock(&s->__lock);
1544 append_event(s, tmp);
1545 } else if (!s->dead) {
1546 if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
1547 ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
1549 pthread_kill(s->t, SIGURG);
1552 ast_mutex_unlock(&s->__lock);
1554 ast_mutex_unlock(&sessionlock);
1559 int ast_manager_unregister( char *action )
1561 struct manager_action *cur = first_action, *prev = first_action;
1563 ast_mutex_lock(&actionlock);
1565 if (!strcasecmp(action, cur->action)) {
1566 prev->next = cur->next;
1568 if (option_verbose > 1)
1569 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1570 ast_mutex_unlock(&actionlock);
1576 ast_mutex_unlock(&actionlock);
1580 static int manager_state_cb(char *context, char *exten, int state, void *data)
1582 /* Notify managers of change */
1583 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1587 static int ast_manager_register_struct(struct manager_action *act)
1589 struct manager_action *cur = first_action, *prev = NULL;
1592 ast_mutex_lock(&actionlock);
1593 while(cur) { /* Walk the list of actions */
1594 ret = strcasecmp(cur->action, act->action);
1596 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1597 ast_mutex_unlock(&actionlock);
1599 } else if (ret > 0) {
1600 /* Insert these alphabetically */
1602 act->next = prev->next;
1605 act->next = first_action;
1622 if (option_verbose > 1)
1623 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1624 ast_mutex_unlock(&actionlock);
1628 /*! \brief register a new command with manager, including online help. This is
1629 the preferred way to register a manager command */
1630 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
1632 struct manager_action *cur;
1634 cur = malloc(sizeof(struct manager_action));
1636 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1637 ast_mutex_unlock(&actionlock);
1640 cur->action = action;
1641 cur->authority = auth;
1643 cur->synopsis = synopsis;
1644 cur->description = description;
1647 ast_manager_register_struct(cur);
1652 END Doxygen group */
1654 static int registered = 0;
1656 int init_manager(void)
1658 struct ast_config *cfg;
1660 int oldportno = portno;
1661 static struct sockaddr_in ba;
1664 /* Register default actions */
1665 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
1666 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
1667 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
1668 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
1669 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
1670 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
1671 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
1672 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
1673 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1674 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
1675 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
1676 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
1677 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
1678 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
1679 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
1681 ast_cli_register(&show_mancmd_cli);
1682 ast_cli_register(&show_mancmds_cli);
1683 ast_cli_register(&show_manconn_cli);
1684 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1687 portno = DEFAULT_MANAGER_PORT;
1688 displayconnects = 1;
1689 cfg = ast_config_load("manager.conf");
1691 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
1694 memset(&ba, 0, sizeof(ba));
1695 val = ast_variable_retrieve(cfg, "general", "enabled");
1697 enabled = ast_true(val);
1699 val = ast_variable_retrieve(cfg, "general", "block-sockets");
1701 block_sockets = ast_true(val);
1703 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1704 if (sscanf(val, "%d", &portno) != 1) {
1705 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1706 portno = DEFAULT_MANAGER_PORT;
1708 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
1709 if (sscanf(val, "%d", &portno) != 1) {
1710 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1711 portno = DEFAULT_MANAGER_PORT;
1713 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
1716 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
1717 displayconnects = ast_true(val);
1719 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
1720 timestampevents = ast_true(val);
1722 ba.sin_family = AF_INET;
1723 ba.sin_port = htons(portno);
1724 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1726 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1727 if (!inet_aton(val, &ba.sin_addr)) {
1728 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1729 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1733 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1735 /* Can't be done yet */
1739 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1742 ast_config_destroy(cfg);
1744 /* If not enabled, do nothing */
1749 asock = socket(AF_INET, SOCK_STREAM, 0);
1751 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1754 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1755 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1756 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1761 if (listen(asock, 2)) {
1762 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1768 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1769 ast_pthread_create(&t, NULL, accept_thread, NULL);
1774 int reload_manager(void)
1776 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1777 return init_manager();