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 * Channel Management and more
28 /*! \addtogroup Group_AMI AMI functions
37 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <arpa/inet.h>
49 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
51 #include "asterisk/channel.h"
52 #include "asterisk/file.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/config.h"
55 #include "asterisk/callerid.h"
56 #include "asterisk/lock.h"
57 #include "asterisk/logger.h"
58 #include "asterisk/options.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/app.h"
61 #include "asterisk/pbx.h"
62 #include "asterisk/md5.h"
63 #include "asterisk/acl.h"
64 #include "asterisk/utils.h"
66 struct fast_originate_helper {
78 struct ast_variable *vars;
81 static int enabled = 0;
82 static int portno = DEFAULT_MANAGER_PORT;
83 static int asock = -1;
84 static int displayconnects = 1;
87 AST_MUTEX_DEFINE_STATIC(sessionlock);
88 static int block_sockets = 0;
90 static struct permalias {
94 { EVENT_FLAG_SYSTEM, "system" },
95 { EVENT_FLAG_CALL, "call" },
96 { EVENT_FLAG_LOG, "log" },
97 { EVENT_FLAG_VERBOSE, "verbose" },
98 { EVENT_FLAG_COMMAND, "command" },
99 { EVENT_FLAG_AGENT, "agent" },
100 { EVENT_FLAG_USER, "user" },
105 static struct mansession *sessions = NULL;
106 static struct manager_action *first_action = NULL;
107 AST_MUTEX_DEFINE_STATIC(actionlock);
109 /*! If you are calling ast_carefulwrite, it is assumed that you are calling
110 it on a file descriptor that _DOES_ have NONBLOCK set. This way,
111 there is only one system call made to do a write, unless we actually
112 have a need to wait. This way, we get better performance. */
113 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
115 /* Try to write string, but wait no more than ms milliseconds
118 struct pollfd fds[1];
120 res = write(fd, s, len);
121 if ((res < 0) && (errno != EAGAIN)) {
124 if (res < 0) res = 0;
130 fds[0].events = POLLOUT;
131 /* Wait until writable again */
132 res = poll(fds, 1, timeoutms);
140 /*! authority_to_str: Convert authority code to string with serveral options */
141 static char *authority_to_str(int authority, char *res, int reslen)
143 int running_total = 0, i;
144 memset(res, 0, reslen);
145 for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
146 if (authority & perms[i].num) {
148 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
151 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
152 running_total += strlen(perms[i].label);
155 if (ast_strlen_zero(res)) {
156 ast_copy_string(res, "<none>", reslen);
161 static char *complete_show_mancmd(char *line, char *word, int pos, int state)
163 struct manager_action *cur = first_action;
166 ast_mutex_lock(&actionlock);
167 while (cur) { /* Walk the list of actions */
168 if (!strncasecmp(word, cur->action, strlen(word))) {
169 if (++which > state) {
170 char *ret = strdup(cur->action);
171 ast_mutex_unlock(&actionlock);
177 ast_mutex_unlock(&actionlock);
181 static int handle_showmancmd(int fd, int argc, char *argv[])
183 struct manager_action *cur = first_action;
188 return RESULT_SHOWUSAGE;
189 ast_mutex_lock(&actionlock);
190 while (cur) { /* Walk the list of actions */
191 for (num = 3; num < argc; num++) {
192 if (!strcasecmp(cur->action, argv[num])) {
193 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 : "");
199 ast_mutex_unlock(&actionlock);
200 return RESULT_SUCCESS;
203 /*! \brief handle_showmancmds: CLI command */
204 /* Should change to "manager show commands" */
205 static int handle_showmancmds(int fd, int argc, char *argv[])
207 struct manager_action *cur = first_action;
209 char *format = " %-15.15s %-15.15s %-55.55s\n";
211 ast_mutex_lock(&actionlock);
212 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
213 ast_cli(fd, format, "------", "---------", "--------");
214 while (cur) { /* Walk the list of actions */
215 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
219 ast_mutex_unlock(&actionlock);
220 return RESULT_SUCCESS;
223 /*! \brief handle_showmanconn: CLI command show manager connected */
224 /* Should change to "manager show connected" */
225 static int handle_showmanconn(int fd, int argc, char *argv[])
227 struct mansession *s;
228 char iabuf[INET_ADDRSTRLEN];
229 char *format = " %-15.15s %-15.15s\n";
230 ast_mutex_lock(&sessionlock);
232 ast_cli(fd, format, "Username", "IP Address");
234 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
238 ast_mutex_unlock(&sessionlock);
239 return RESULT_SUCCESS;
242 static char showmancmd_help[] =
243 "Usage: show manager command <actionname>\n"
244 " Shows the detailed description for a specific Asterisk manager interface command.\n";
246 static char showmancmds_help[] =
247 "Usage: show manager commands\n"
248 " Prints a listing of all the available Asterisk manager interface commands.\n";
250 static char showmanconn_help[] =
251 "Usage: show manager connected\n"
252 " Prints a listing of the users that are currently connected to the\n"
253 "Asterisk manager interface.\n";
255 static struct ast_cli_entry show_mancmd_cli =
256 { { "show", "manager", "command", NULL },
257 handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
259 static struct ast_cli_entry show_mancmds_cli =
260 { { "show", "manager", "commands", NULL },
261 handle_showmancmds, "List manager interface commands", showmancmds_help };
263 static struct ast_cli_entry show_manconn_cli =
264 { { "show", "manager", "connected", NULL },
265 handle_showmanconn, "Show connected manager interface users", showmanconn_help };
267 static void free_session(struct mansession *s)
269 struct eventqent *eqe;
272 ast_mutex_destroy(&s->__lock);
275 s->eventq = s->eventq->next;
281 static void destroy_session(struct mansession *s)
283 struct mansession *cur, *prev = NULL;
284 ast_mutex_lock(&sessionlock);
294 prev->next = cur->next;
296 sessions = cur->next;
299 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
300 ast_mutex_unlock(&sessionlock);
304 char *astman_get_header(struct message *m, char *var)
308 snprintf(cmp, sizeof(cmp), "%s: ", var);
309 for (x=0;x<m->hdrcount;x++)
310 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
311 return m->headers[x] + strlen(cmp);
315 struct ast_variable *astman_get_variables(struct message *m)
318 struct ast_variable *head = NULL, *cur;
320 unsigned int var_count;
323 varlen = strlen("Variable: ");
325 for (x = 0; x < m->hdrcount; x++) {
326 if (strncasecmp("Variable: ", m->headers[x], varlen))
329 if (!(var = ast_strdupa(m->headers[x] + varlen)))
332 if ((var_count = ast_app_separate_args(var, '|', vars, sizeof(vars) / sizeof(vars[0])))) {
333 for (y = 0; y < var_count; y++) {
336 var = val = ast_strdupa(vars[y]);
338 if (!val || ast_strlen_zero(var))
340 cur = ast_variable_new(var, val);
354 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
355 hold the session lock _or_ be running in an action callback (in which case s->busy will
356 be non-zero). In either of these cases, there is no need to lock-protect the session's
357 fd, since no other output will be sent (events will be queued), and no input will
358 be read until either the current action finishes or get_input() obtains the session
361 void astman_send_error(struct mansession *s, struct message *m, char *error)
363 char *id = astman_get_header(m,"ActionID");
365 ast_cli(s->fd, "Response: Error\r\n");
366 if (!ast_strlen_zero(id))
367 ast_cli(s->fd, "ActionID: %s\r\n",id);
368 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
371 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
373 char *id = astman_get_header(m,"ActionID");
375 ast_cli(s->fd, "Response: %s\r\n", resp);
376 if (!ast_strlen_zero(id))
377 ast_cli(s->fd, "ActionID: %s\r\n",id);
379 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
381 ast_cli(s->fd, "\r\n");
384 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
386 astman_send_response(s, m, "Success", msg);
389 /*! Tells you if smallstr exists inside bigstr
390 which is delim by delim and uses no buf or stringsep
391 ast_instring("this|that|more","this",',') == 1;
393 feel free to move this to app.c -anthm */
394 static int ast_instring(char *bigstr, char *smallstr, char delim)
396 char *val = bigstr, *next;
399 if ((next = strchr(val, delim))) {
400 if (!strncmp(val, smallstr, (next - val)))
405 return !strcmp(smallstr, val);
407 } while (*(val = (next + 1)));
412 static int get_perm(char *instr)
419 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
420 if (ast_instring(instr, perms[x].label, ','))
426 static int ast_is_number(char *string)
433 for (x=0; x < strlen(string); x++) {
434 if (!(string[x] >= 48 && string[x] <= 57)) {
440 return ret ? atoi(string) : 0;
443 static int ast_strings_to_mask(char *string)
447 x = ast_is_number(string);
451 } else if (ast_strlen_zero(string)) {
453 } else if (ast_false(string)) {
455 } else if (ast_true(string)) {
457 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
461 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
462 if (ast_instring(string, perms[x].label, ','))
471 Rather than braindead on,off this now can also accept a specific int mask value
472 or a ',' delim list of mask strings (the same as manager.conf) -anthm
475 static int set_eventmask(struct mansession *s, char *eventmask)
477 int maskint = ast_strings_to_mask(eventmask);
479 ast_mutex_lock(&s->__lock);
481 s->send_events = maskint;
482 ast_mutex_unlock(&s->__lock);
487 static int authenticate(struct mansession *s, struct message *m)
489 struct ast_config *cfg;
490 char iabuf[INET_ADDRSTRLEN];
492 char *user = astman_get_header(m, "Username");
493 char *pass = astman_get_header(m, "Secret");
494 char *authtype = astman_get_header(m, "AuthType");
495 char *key = astman_get_header(m, "Key");
496 char *events = astman_get_header(m, "Events");
498 cfg = ast_config_load("manager.conf");
501 cat = ast_category_browse(cfg, NULL);
503 if (strcasecmp(cat, "general")) {
505 if (!strcasecmp(cat, user)) {
506 struct ast_variable *v;
507 struct ast_ha *ha = NULL;
508 char *password = NULL;
509 v = ast_variable_browse(cfg, cat);
511 if (!strcasecmp(v->name, "secret")) {
513 } else if (!strcasecmp(v->name, "permit") ||
514 !strcasecmp(v->name, "deny")) {
515 ha = ast_append_ha(v->name, v->value, ha);
516 } else if (!strcasecmp(v->name, "writetimeout")) {
517 int val = atoi(v->value);
520 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
522 s->writetimeout = val;
527 if (ha && !ast_apply_ha(ha, &(s->sin))) {
528 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
530 ast_config_destroy(cfg);
534 if (!strcasecmp(authtype, "MD5")) {
535 if (!ast_strlen_zero(key) && s->challenge) {
538 char md5key[256] = "";
539 struct MD5Context md5;
540 unsigned char digest[16];
542 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
543 MD5Update(&md5, (unsigned char *) password, strlen(password));
544 MD5Final(digest, &md5);
546 len += sprintf(md5key + len, "%2.2x", digest[x]);
547 if (!strcmp(md5key, key))
550 ast_config_destroy(cfg);
554 } else if (password && !strcasecmp(password, pass)) {
557 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
558 ast_config_destroy(cfg);
563 cat = ast_category_browse(cfg, cat);
566 ast_copy_string(s->username, cat, sizeof(s->username));
567 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
568 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
569 ast_config_destroy(cfg);
571 set_eventmask(s, events);
574 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
575 ast_config_destroy(cfg);
579 /*! \brief PING: Manager PING */
580 static char mandescr_ping[] =
581 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
582 " manager connection open.\n"
585 static int action_ping(struct mansession *s, struct message *m)
587 astman_send_response(s, m, "Pong", NULL);
591 static char mandescr_listcommands[] =
592 "Description: Returns the action name and synopsis for every\n"
593 " action that is available to the user\n"
596 static int action_listcommands(struct mansession *s, struct message *m)
598 struct manager_action *cur = first_action;
599 char idText[256] = "";
601 char *id = astman_get_header(m,"ActionID");
603 if (!ast_strlen_zero(id))
604 snprintf(idText,256,"ActionID: %s\r\n",id);
605 ast_cli(s->fd, "Response: Success\r\n%s", idText);
606 ast_mutex_lock(&actionlock);
607 while (cur) { /* Walk the list of actions */
608 if ((s->writeperm & cur->authority) == cur->authority)
609 ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
612 ast_mutex_unlock(&actionlock);
613 ast_cli(s->fd, "\r\n");
618 static char mandescr_events[] =
619 "Description: Enable/Disable sending of events to this manager\n"
622 " EventMask: 'on' if all events should be sent,\n"
623 " 'off' if no events should be sent,\n"
624 " 'system,call,log' to select which flags events should have to be sent.\n";
626 static int action_events(struct mansession *s, struct message *m)
628 char *mask = astman_get_header(m, "EventMask");
631 res = set_eventmask(s, mask);
633 astman_send_response(s, m, "Events On", NULL);
635 astman_send_response(s, m, "Events Off", NULL);
640 static char mandescr_logoff[] =
641 "Description: Logoff this manager session\n"
644 static int action_logoff(struct mansession *s, struct message *m)
646 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
650 static char mandescr_hangup[] =
651 "Description: Hangup a channel\n"
653 " Channel: The channel name to be hungup\n";
655 static int action_hangup(struct mansession *s, struct message *m)
657 struct ast_channel *c = NULL;
658 char *name = astman_get_header(m, "Channel");
659 if (ast_strlen_zero(name)) {
660 astman_send_error(s, m, "No channel specified");
663 c = ast_get_channel_by_name_locked(name);
665 astman_send_error(s, m, "No such channel");
668 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
669 ast_mutex_unlock(&c->lock);
670 astman_send_ack(s, m, "Channel Hungup");
674 static char mandescr_setvar[] =
675 "Description: Set a global or local channel variable.\n"
676 "Variables: (Names marked with * are required)\n"
677 " Channel: Channel to set variable for\n"
678 " *Variable: Variable name\n"
681 static int action_setvar(struct mansession *s, struct message *m)
683 struct ast_channel *c = NULL;
684 char *name = astman_get_header(m, "Channel");
685 char *varname = astman_get_header(m, "Variable");
686 char *varval = astman_get_header(m, "Value");
688 if (ast_strlen_zero(varname)) {
689 astman_send_error(s, m, "No variable specified");
693 if (!ast_strlen_zero(name)) {
694 c = ast_get_channel_by_name_locked(name);
696 astman_send_error(s, m, "No such channel");
701 pbx_builtin_setvar_helper(c,varname,varval);
703 ast_mutex_unlock(&c->lock);
704 astman_send_ack(s, m, "Variable Set");
709 static char mandescr_getvar[] =
710 "Description: Get the value of a global or local channel variable.\n"
711 "Variables: (Names marked with * are required)\n"
712 " Channel: Channel to read variable from\n"
713 " *Variable: Variable name\n"
714 " ActionID: Optional Action id for message matching.\n";
716 static int action_getvar(struct mansession *s, struct message *m)
718 struct ast_channel *c = NULL;
719 char *name = astman_get_header(m, "Channel");
720 char *varname = astman_get_header(m, "Variable");
721 char *id = astman_get_header(m,"ActionID");
725 if (!strlen(varname)) {
726 astman_send_error(s, m, "No variable specified");
731 c = ast_get_channel_by_name_locked(name);
733 astman_send_error(s, m, "No such channel");
738 varval=pbx_builtin_getvar_helper(c,varname);
740 varval2 = ast_strdupa(varval);
744 ast_mutex_unlock(&c->lock);
745 ast_cli(s->fd, "Response: Success\r\n"
746 "Variable: %s\r\nValue: %s\r\n" ,varname,varval2);
747 if (!ast_strlen_zero(id))
748 ast_cli(s->fd, "ActionID: %s\r\n",id);
749 ast_cli(s->fd, "\r\n");
755 /*! \brief action_status: Manager "status" command to show channels */
756 /* Needs documentation... */
757 static int action_status(struct mansession *s, struct message *m)
759 char *id = astman_get_header(m,"ActionID");
760 char *name = astman_get_header(m,"Channel");
761 char idText[256] = "";
762 struct ast_channel *c;
764 struct timeval now = ast_tvnow();
765 long elapsed_seconds=0;
766 int all = ast_strlen_zero(name); /* set if we want all channels */
768 astman_send_ack(s, m, "Channel status will follow");
769 if (!ast_strlen_zero(id))
770 snprintf(idText,256,"ActionID: %s\r\n",id);
772 c = ast_channel_walk_locked(NULL);
774 c = ast_get_channel_by_name_locked(name);
776 astman_send_error(s, m, "No such channel");
780 /* if we look by name, we break after the first iteration */
783 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
788 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
792 "Privilege: Call\r\n"
795 "CallerIDName: %s\r\n"
807 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
808 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
810 ast_state2str(c->_state), c->context,
811 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
815 "Privilege: Call\r\n"
818 "CallerIDName: %s\r\n"
826 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
827 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
829 ast_state2str(c->_state), bridge, c->uniqueid, idText);
831 ast_mutex_unlock(&c->lock);
834 c = ast_channel_walk_locked(c);
837 "Event: StatusComplete\r\n"
843 static char mandescr_redirect[] =
844 "Description: Redirect (transfer) a call.\n"
845 "Variables: (Names marked with * are required)\n"
846 " *Channel: Channel to redirect\n"
847 " ExtraChannel: Second call leg to transfer (optional)\n"
848 " *Exten: Extension to transfer to\n"
849 " *Context: Context to transfer to\n"
850 " *Priority: Priority to transfer to\n"
851 " ActionID: Optional Action id for message matching.\n";
853 /*! \brief action_redirect: The redirect manager command */
854 static int action_redirect(struct mansession *s, struct message *m)
856 char *name = astman_get_header(m, "Channel");
857 char *name2 = astman_get_header(m, "ExtraChannel");
858 char *exten = astman_get_header(m, "Exten");
859 char *context = astman_get_header(m, "Context");
860 char *priority = astman_get_header(m, "Priority");
861 struct ast_channel *chan, *chan2 = NULL;
865 if (ast_strlen_zero(name)) {
866 astman_send_error(s, m, "Channel not specified");
869 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
870 astman_send_error(s, m, "Invalid priority\n");
873 chan = ast_get_channel_by_name_locked(name);
876 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
877 astman_send_error(s, m, buf);
880 if (!ast_strlen_zero(name2))
881 chan2 = ast_get_channel_by_name_locked(name2);
882 res = ast_async_goto(chan, context, exten, pi);
884 if (!ast_strlen_zero(name2)) {
886 res = ast_async_goto(chan2, context, exten, pi);
890 astman_send_ack(s, m, "Dual Redirect successful");
892 astman_send_error(s, m, "Secondary redirect failed");
894 astman_send_ack(s, m, "Redirect successful");
896 astman_send_error(s, m, "Redirect failed");
898 ast_mutex_unlock(&chan->lock);
900 ast_mutex_unlock(&chan2->lock);
904 static char mandescr_command[] =
905 "Description: Run a CLI command.\n"
906 "Variables: (Names marked with * are required)\n"
907 " *Command: Asterisk CLI command to run\n"
908 " ActionID: Optional Action id for message matching.\n";
910 /*! \brief action_command: Manager command "command" - execute CLI command */
911 static int action_command(struct mansession *s, struct message *m)
913 char *cmd = astman_get_header(m, "Command");
914 char *id = astman_get_header(m, "ActionID");
915 ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
916 if (!ast_strlen_zero(id))
917 ast_cli(s->fd, "ActionID: %s\r\n", id);
918 /* FIXME: Wedge a ActionID response in here, waiting for later changes */
919 ast_cli_command(s->fd, cmd);
920 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
924 static void *fast_originate(void *data)
926 struct fast_originate_helper *in = data;
929 struct ast_channel *chan = NULL;
931 if (!ast_strlen_zero(in->app)) {
932 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
933 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
934 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
937 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
938 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
939 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
943 manager_event(EVENT_FLAG_CALL,
951 in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
953 manager_event(EVENT_FLAG_CALL,
961 in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
963 /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
965 ast_mutex_unlock(&chan->lock);
970 static char mandescr_originate[] =
971 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
972 " Application/Data\n"
973 "Variables: (Names marked with * are required)\n"
974 " *Channel: Channel name to call\n"
975 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
976 " Context: Context to use (requires 'Exten' and 'Priority')\n"
977 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
978 " Application: Application to use\n"
979 " Data: Data to use (requires 'Application')\n"
980 " Timeout: How long to wait for call to be answered (in ms)\n"
981 " CallerID: Caller ID to be set on the outgoing channel\n"
982 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
983 " Account: Account code\n"
984 " Async: Set to 'true' for fast origination\n";
986 static int action_originate(struct mansession *s, struct message *m)
988 char *name = astman_get_header(m, "Channel");
989 char *exten = astman_get_header(m, "Exten");
990 char *context = astman_get_header(m, "Context");
991 char *priority = astman_get_header(m, "Priority");
992 char *timeout = astman_get_header(m, "Timeout");
993 char *callerid = astman_get_header(m, "CallerID");
994 char *account = astman_get_header(m, "Account");
995 char *app = astman_get_header(m, "Application");
996 char *appdata = astman_get_header(m, "Data");
997 char *async = astman_get_header(m, "Async");
998 char *id = astman_get_header(m, "ActionID");
999 struct ast_variable *vars = astman_get_variables(m);
1001 char *l=NULL, *n=NULL;
1010 pthread_attr_t attr;
1012 astman_send_error(s, m, "Channel not specified");
1015 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1016 astman_send_error(s, m, "Invalid priority\n");
1019 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1020 astman_send_error(s, m, "Invalid timeout\n");
1023 ast_copy_string(tmp, name, sizeof(tmp));
1025 data = strchr(tmp, '/');
1027 astman_send_error(s, m, "Invalid channel\n");
1032 ast_copy_string(tmp2, callerid, sizeof(tmp2));
1033 ast_callerid_parse(tmp2, &n, &l);
1035 if (ast_strlen_zero(n))
1039 ast_shrink_phone_number(l);
1040 if (ast_strlen_zero(l))
1044 struct ast_variable *newvar;
1045 newvar = ast_variable_new("CDR(accountcode|r)", account);
1046 newvar->next = vars;
1049 if (ast_true(async)) {
1050 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1054 memset(fast, 0, sizeof(struct fast_originate_helper));
1055 if (!ast_strlen_zero(id))
1056 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1057 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1058 ast_copy_string(fast->data, data, sizeof(fast->data));
1059 ast_copy_string(fast->app, app, sizeof(fast->app));
1060 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1062 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1064 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1066 ast_copy_string(fast->context, context, sizeof(fast->context));
1067 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1069 fast->priority = pi;
1070 pthread_attr_init(&attr);
1071 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1072 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1078 } else if (!ast_strlen_zero(app)) {
1079 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
1081 if (exten && context && pi)
1082 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
1084 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1089 astman_send_ack(s, m, "Originate successfully queued");
1091 astman_send_error(s, m, "Originate failed");
1095 /*! \brief Help text for manager command mailboxstatus
1097 static char mandescr_mailboxstatus[] =
1098 "Description: Checks a voicemail account for status.\n"
1099 "Variables: (Names marked with * are required)\n"
1100 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1101 " ActionID: Optional ActionID for message matching.\n"
1102 "Returns number of messages.\n"
1103 " Message: Mailbox Status\n"
1104 " Mailbox: <mailboxid>\n"
1105 " Waiting: <count>\n"
1108 static int action_mailboxstatus(struct mansession *s, struct message *m)
1110 char *mailbox = astman_get_header(m, "Mailbox");
1111 char *id = astman_get_header(m,"ActionID");
1112 char idText[256] = "";
1114 if (ast_strlen_zero(mailbox)) {
1115 astman_send_error(s, m, "Mailbox not specified");
1118 if (!ast_strlen_zero(id))
1119 snprintf(idText,256,"ActionID: %s\r\n",id);
1120 ret = ast_app_has_voicemail(mailbox, NULL);
1121 ast_cli(s->fd, "Response: Success\r\n"
1123 "Message: Mailbox Status\r\n"
1125 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1129 static char mandescr_mailboxcount[] =
1130 "Description: Checks a voicemail account for new messages.\n"
1131 "Variables: (Names marked with * are required)\n"
1132 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1133 " ActionID: Optional ActionID for message matching.\n"
1134 "Returns number of new and old messages.\n"
1135 " Message: Mailbox Message Count\n"
1136 " Mailbox: <mailboxid>\n"
1137 " NewMessages: <count>\n"
1138 " OldMessages: <count>\n"
1140 static int action_mailboxcount(struct mansession *s, struct message *m)
1142 char *mailbox = astman_get_header(m, "Mailbox");
1143 char *id = astman_get_header(m,"ActionID");
1144 char idText[256] = "";
1145 int newmsgs = 0, oldmsgs = 0;
1146 if (ast_strlen_zero(mailbox)) {
1147 astman_send_error(s, m, "Mailbox not specified");
1150 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1151 if (!ast_strlen_zero(id)) {
1152 snprintf(idText,256,"ActionID: %s\r\n",id);
1154 ast_cli(s->fd, "Response: Success\r\n"
1156 "Message: Mailbox Message Count\r\n"
1158 "NewMessages: %d\r\n"
1159 "OldMessages: %d\r\n"
1161 idText,mailbox, newmsgs, oldmsgs);
1165 static char mandescr_extensionstate[] =
1166 "Description: Report the extension state for given extension.\n"
1167 " If the extension has a hint, will use devicestate to check\n"
1168 " the status of the device connected to the extension.\n"
1169 "Variables: (Names marked with * are required)\n"
1170 " *Exten: Extension to check state on\n"
1171 " *Context: Context for extension\n"
1172 " ActionId: Optional ID for this transaction\n"
1173 "Will return an \"Extension Status\" message.\n"
1174 "The response will include the hint for the extension and the status.\n";
1176 static int action_extensionstate(struct mansession *s, struct message *m)
1178 char *exten = astman_get_header(m, "Exten");
1179 char *context = astman_get_header(m, "Context");
1180 char *id = astman_get_header(m,"ActionID");
1181 char idText[256] = "";
1182 char hint[256] = "";
1184 if (ast_strlen_zero(exten)) {
1185 astman_send_error(s, m, "Extension not specified");
1188 if (ast_strlen_zero(context))
1189 context = "default";
1190 status = ast_extension_state(NULL, context, exten);
1191 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1192 if (!ast_strlen_zero(id)) {
1193 snprintf(idText,256,"ActionID: %s\r\n",id);
1195 ast_cli(s->fd, "Response: Success\r\n"
1197 "Message: Extension Status\r\n"
1201 "Status: %d\r\n\r\n",
1202 idText,exten, context, hint, status);
1206 static char mandescr_timeout[] =
1207 "Description: Hangup a channel after a certain time.\n"
1208 "Variables: (Names marked with * are required)\n"
1209 " *Channel: Channel name to hangup\n"
1210 " *Timeout: Maximum duration of the call (sec)\n"
1211 "Acknowledges set time with 'Timeout Set' message\n";
1213 static int action_timeout(struct mansession *s, struct message *m)
1215 struct ast_channel *c = NULL;
1216 char *name = astman_get_header(m, "Channel");
1217 int timeout = atoi(astman_get_header(m, "Timeout"));
1218 if (ast_strlen_zero(name)) {
1219 astman_send_error(s, m, "No channel specified");
1223 astman_send_error(s, m, "No timeout specified");
1226 c = ast_get_channel_by_name_locked(name);
1228 astman_send_error(s, m, "No such channel");
1231 ast_channel_setwhentohangup(c, timeout);
1232 ast_mutex_unlock(&c->lock);
1233 astman_send_ack(s, m, "Timeout Set");
1237 static int process_message(struct mansession *s, struct message *m)
1239 char action[80] = "";
1240 struct manager_action *tmp = first_action;
1241 char *id = astman_get_header(m,"ActionID");
1242 char idText[256] = "";
1243 char iabuf[INET_ADDRSTRLEN];
1245 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1246 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1248 if (ast_strlen_zero(action)) {
1249 astman_send_error(s, m, "Missing action in request");
1252 if (!ast_strlen_zero(id)) {
1253 snprintf(idText,256,"ActionID: %s\r\n",id);
1255 if (!s->authenticated) {
1256 if (!strcasecmp(action, "Challenge")) {
1258 authtype = astman_get_header(m, "AuthType");
1259 if (!strcasecmp(authtype, "MD5")) {
1260 if (ast_strlen_zero(s->challenge))
1261 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
1262 ast_mutex_lock(&s->__lock);
1263 ast_cli(s->fd, "Response: Success\r\n"
1265 "Challenge: %s\r\n\r\n",
1266 idText,s->challenge);
1267 ast_mutex_unlock(&s->__lock);
1270 astman_send_error(s, m, "Must specify AuthType");
1273 } else if (!strcasecmp(action, "Login")) {
1274 if (authenticate(s, m)) {
1276 astman_send_error(s, m, "Authentication failed");
1279 s->authenticated = 1;
1280 if (option_verbose > 1) {
1281 if ( displayconnects ) {
1282 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1285 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1286 astman_send_ack(s, m, "Authentication accepted");
1288 } else if (!strcasecmp(action, "Logoff")) {
1289 astman_send_ack(s, m, "See ya");
1292 astman_send_error(s, m, "Authentication Required");
1295 struct eventqent *eqe;
1296 ast_mutex_lock(&s->__lock);
1298 ast_mutex_unlock(&s->__lock);
1300 if (!strcasecmp(action, tmp->action)) {
1301 if ((s->writeperm & tmp->authority) == tmp->authority) {
1302 if (tmp->func(s, m))
1305 astman_send_error(s, m, "Permission denied");
1312 astman_send_error(s, m, "Invalid/unknown command");
1313 ast_mutex_lock(&s->__lock);
1316 if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
1321 s->eventq = s->eventq->next;
1324 ast_mutex_unlock(&s->__lock);
1330 static int get_input(struct mansession *s, char *output)
1332 /* output must have at least sizeof(s->inbuf) space */
1335 struct pollfd fds[1];
1336 char iabuf[INET_ADDRSTRLEN];
1337 for (x=1;x<s->inlen;x++) {
1338 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1339 /* Copy output data up to and including \r\n */
1340 memcpy(output, s->inbuf, x + 1);
1341 /* Add trailing \0 */
1343 /* Move remaining data back to the front */
1344 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1345 s->inlen -= (x + 1);
1349 if (s->inlen >= sizeof(s->inbuf) - 1) {
1350 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);
1354 fds[0].events = POLLIN;
1356 res = poll(fds, 1, -1);
1358 if (errno == EINTR) {
1363 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1365 } else if (res > 0) {
1366 ast_mutex_lock(&s->__lock);
1367 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1368 ast_mutex_unlock(&s->__lock);
1375 s->inbuf[s->inlen] = '\0';
1379 static void *session_do(void *data)
1381 struct mansession *s = data;
1383 char iabuf[INET_ADDRSTRLEN];
1386 ast_mutex_lock(&s->__lock);
1387 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
1388 ast_mutex_unlock(&s->__lock);
1389 memset(&m, 0, sizeof(m));
1391 res = get_input(s, m.headers[m.hdrcount]);
1393 /* Strip trailing \r\n */
1394 if (strlen(m.headers[m.hdrcount]) < 2)
1396 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1397 if (ast_strlen_zero(m.headers[m.hdrcount])) {
1398 if (process_message(s, &m))
1400 memset(&m, 0, sizeof(m));
1401 } else if (m.hdrcount < MAX_HEADERS - 1)
1406 if (s->authenticated) {
1407 if (option_verbose > 1) {
1408 if (displayconnects)
1409 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1411 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1413 if (option_verbose > 1) {
1414 if ( displayconnects )
1415 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1417 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1423 static void *accept_thread(void *ignore)
1426 struct sockaddr_in sin;
1428 struct mansession *s;
1432 pthread_attr_t attr;
1434 pthread_attr_init(&attr);
1435 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1438 sinlen = sizeof(sin);
1439 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1441 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1444 p = getprotobyname("tcp");
1446 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1447 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1450 s = malloc(sizeof(struct mansession));
1452 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1455 memset(s, 0, sizeof(struct mansession));
1456 memcpy(&s->sin, &sin, sizeof(sin));
1457 s->writetimeout = 100;
1459 if(! block_sockets) {
1460 /* For safety, make sure socket is non-blocking */
1461 flags = fcntl(as, F_GETFL);
1462 fcntl(as, F_SETFL, flags | O_NONBLOCK);
1464 ast_mutex_init(&s->__lock);
1466 s->send_events = -1;
1467 ast_mutex_lock(&sessionlock);
1470 ast_mutex_unlock(&sessionlock);
1471 if (ast_pthread_create(&s->t, &attr, session_do, s))
1474 pthread_attr_destroy(&attr);
1478 static int append_event(struct mansession *s, const char *str)
1480 struct eventqent *tmp, *prev=NULL;
1481 tmp = malloc(sizeof(struct eventqent) + strlen(str));
1484 strcpy(tmp->eventdata, str);
1498 /*! \brief manager_event: Send AMI event to client */
1499 int manager_event(int category, char *event, char *fmt, ...)
1501 struct mansession *s;
1503 char tmp[4096] = "";
1504 char *tmp_next = tmp;
1505 size_t tmp_left = sizeof(tmp) - 2;
1508 ast_mutex_lock(&sessionlock);
1509 for (s = sessions; s; s = s->next) {
1510 if ((s->readperm & category) != category)
1513 if ((s->send_events & category) != category)
1516 if (ast_strlen_zero(tmp)) {
1517 ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1518 event, authority_to_str(category, auth, sizeof(auth)));
1520 ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1527 ast_mutex_lock(&s->__lock);
1529 append_event(s, tmp);
1530 } else if (!s->dead) {
1531 if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
1532 ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
1534 pthread_kill(s->t, SIGURG);
1537 ast_mutex_unlock(&s->__lock);
1539 ast_mutex_unlock(&sessionlock);
1544 int ast_manager_unregister( char *action )
1546 struct manager_action *cur = first_action, *prev = first_action;
1548 ast_mutex_lock(&actionlock);
1550 if (!strcasecmp(action, cur->action)) {
1551 prev->next = cur->next;
1553 if (option_verbose > 1)
1554 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1555 ast_mutex_unlock(&actionlock);
1561 ast_mutex_unlock(&actionlock);
1565 static int manager_state_cb(char *context, char *exten, int state, void *data)
1567 /* Notify managers of change */
1568 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1572 static int ast_manager_register_struct(struct manager_action *act)
1574 struct manager_action *cur = first_action, *prev = NULL;
1577 ast_mutex_lock(&actionlock);
1578 while(cur) { /* Walk the list of actions */
1579 ret = strcasecmp(cur->action, act->action);
1581 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1582 ast_mutex_unlock(&actionlock);
1584 } else if (ret > 0) {
1585 /* Insert these alphabetically */
1587 act->next = prev->next;
1590 act->next = first_action;
1607 if (option_verbose > 1)
1608 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1609 ast_mutex_unlock(&actionlock);
1613 /*! \brief register a new command with manager, including online help. This is
1614 the preferred way to register a manager command */
1615 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
1617 struct manager_action *cur;
1619 cur = malloc(sizeof(struct manager_action));
1621 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1622 ast_mutex_unlock(&actionlock);
1625 cur->action = action;
1626 cur->authority = auth;
1628 cur->synopsis = synopsis;
1629 cur->description = description;
1632 ast_manager_register_struct(cur);
1637 END Doxygen group */
1639 static int registered = 0;
1641 int init_manager(void)
1643 struct ast_config *cfg;
1645 int oldportno = portno;
1646 static struct sockaddr_in ba;
1649 /* Register default actions */
1650 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
1651 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
1652 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
1653 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
1654 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
1655 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
1656 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
1657 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
1658 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1659 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
1660 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
1661 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
1662 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
1663 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
1664 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
1666 ast_cli_register(&show_mancmd_cli);
1667 ast_cli_register(&show_mancmds_cli);
1668 ast_cli_register(&show_manconn_cli);
1669 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1672 portno = DEFAULT_MANAGER_PORT;
1673 displayconnects = 1;
1674 cfg = ast_config_load("manager.conf");
1676 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
1679 memset(&ba, 0, sizeof(ba));
1680 val = ast_variable_retrieve(cfg, "general", "enabled");
1682 enabled = ast_true(val);
1684 val = ast_variable_retrieve(cfg, "general", "block-sockets");
1686 block_sockets = ast_true(val);
1688 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1689 if (sscanf(val, "%d", &portno) != 1) {
1690 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1691 portno = DEFAULT_MANAGER_PORT;
1693 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
1694 if (sscanf(val, "%d", &portno) != 1) {
1695 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1696 portno = DEFAULT_MANAGER_PORT;
1698 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
1700 /* Parsing the displayconnects */
1701 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
1702 displayconnects = ast_true(val);;
1706 ba.sin_family = AF_INET;
1707 ba.sin_port = htons(portno);
1708 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1710 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1711 if (!inet_aton(val, &ba.sin_addr)) {
1712 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1713 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1717 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1719 /* Can't be done yet */
1723 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1726 ast_config_destroy(cfg);
1728 /* If not enabled, do nothing */
1733 asock = socket(AF_INET, SOCK_STREAM, 0);
1735 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1738 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1739 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1740 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1745 if (listen(asock, 2)) {
1746 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1752 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1753 ast_pthread_create(&t, NULL, accept_thread, NULL);
1758 int reload_manager(void)
1760 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1761 return init_manager();