2 * Asterisk -- A telephony toolkit for Linux.
4 * Channel Management and more
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
19 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
28 #include <asterisk/channel.h>
29 #include <asterisk/file.h>
30 #include <asterisk/manager.h>
31 #include <asterisk/config.h>
32 #include <asterisk/lock.h>
33 #include <asterisk/logger.h>
34 #include <asterisk/options.h>
35 #include <asterisk/cli.h>
36 #include <asterisk/app.h>
37 #include <asterisk/pbx.h>
38 #include <asterisk/md5.h>
39 #include <asterisk/acl.h>
41 static int enabled = 0;
42 static int portno = DEFAULT_MANAGER_PORT;
43 static int asock = -1;
45 static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
47 static struct permalias {
51 { EVENT_FLAG_SYSTEM, "system" },
52 { EVENT_FLAG_CALL, "call" },
53 { EVENT_FLAG_LOG, "log" },
54 { EVENT_FLAG_VERBOSE, "verbose" },
55 { EVENT_FLAG_COMMAND, "command" },
56 { EVENT_FLAG_AGENT, "agent" },
57 { EVENT_FLAG_USER, "user" },
61 static struct mansession *sessions = NULL;
62 static struct manager_action *first_action = NULL;
63 static ast_mutex_t actionlock = AST_MUTEX_INITIALIZER;
65 static int handle_showmancmds(int fd, int argc, char *argv[])
67 struct manager_action *cur = first_action;
68 char *format = " %-15.15s %-45.45s\n";
70 ast_mutex_lock(&actionlock);
71 ast_cli(fd, format, "Action", "Synopsis");
72 while(cur) { /* Walk the list of actions */
73 ast_cli(fd, format, cur->action, cur->synopsis);
77 ast_mutex_unlock(&actionlock);
78 return RESULT_SUCCESS;
81 static int handle_showmanconn(int fd, int argc, char *argv[])
84 char *format = " %-15.15s %-15.15s\n";
85 ast_mutex_lock(&sessionlock);
87 ast_cli(fd, format, "Username", "IP Address");
89 ast_cli(fd, format,s->username, inet_ntoa(s->sin.sin_addr));
93 ast_mutex_unlock(&sessionlock);
94 return RESULT_SUCCESS;
97 static char showmancmds_help[] =
98 "Usage: show manager commands\n"
99 " Prints a listing of all the available manager commands.\n";
101 static char showmanconn_help[] =
102 "Usage: show manager connected\n"
103 " Prints a listing of the users that are connected to the\n"
104 "manager interface.\n";
106 static struct ast_cli_entry show_mancmds_cli =
107 { { "show", "manager", "commands", NULL },
108 handle_showmancmds, "Show manager commands", showmancmds_help };
110 static struct ast_cli_entry show_manconn_cli =
111 { { "show", "manager", "connected", NULL },
112 handle_showmanconn, "Show connected manager users", showmanconn_help };
114 static void destroy_session(struct mansession *s)
116 struct mansession *cur, *prev = NULL;
117 ast_mutex_lock(&sessionlock);
127 prev->next = cur->next;
129 sessions = cur->next;
134 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
135 ast_mutex_unlock(&sessionlock);
139 char *astman_get_header(struct message *m, char *var)
143 snprintf(cmp, sizeof(cmp), "%s: ", var);
144 for (x=0;x<m->hdrcount;x++)
145 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
146 return m->headers[x] + strlen(cmp);
150 void astman_send_error(struct mansession *s, struct message *m, char *error)
152 char *id = astman_get_header(m,"ActionID");
153 ast_mutex_lock(&s->lock);
154 ast_cli(s->fd, "Response: Error\r\n");
155 if (id && strlen(id))
156 ast_cli(s->fd, "ActionID: %s\r\n",id);
157 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
158 ast_mutex_unlock(&s->lock);
161 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
163 char *id = astman_get_header(m,"ActionID");
164 ast_mutex_lock(&s->lock);
165 ast_cli(s->fd, "Response: %s\r\n", resp);
166 if (id && strlen(id))
167 ast_cli(s->fd, "ActionID: %s\r\n",id);
169 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
171 ast_cli(s->fd, "\r\n");
172 ast_mutex_unlock(&s->lock);
175 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
177 astman_send_response(s, m, "Success", msg);
180 static int get_perm(char *instr)
189 strncpy(tmp, instr, sizeof(tmp) - 1);
191 c = strsep(&stringp, ",");
193 for (x=0;x<sizeof(perms) / sizeof(perms[0]);x++) {
194 if (!strcasecmp(perms[x].label, c))
197 c = strsep(&stringp, ",");
202 static int authenticate(struct mansession *s, struct message *m)
204 struct ast_config *cfg;
206 char *user = astman_get_header(m, "Username");
207 char *pass = astman_get_header(m, "Secret");
208 char *authtype = astman_get_header(m, "AuthType");
209 char *key = astman_get_header(m, "Key");
211 cfg = ast_load("manager.conf");
214 cat = ast_category_browse(cfg, NULL);
216 if (strcasecmp(cat, "general")) {
218 if (!strcasecmp(cat, user)) {
219 struct ast_variable *v;
220 struct ast_ha *ha = NULL;
221 char *password = NULL;
222 v = ast_variable_browse(cfg, cat);
224 if (!strcasecmp(v->name, "secret")) {
226 } else if (!strcasecmp(v->name, "permit") ||
227 !strcasecmp(v->name, "deny")) {
228 ha = ast_append_ha(v->name, v->value, ha);
232 if (ha && !ast_apply_ha(ha, &(s->sin))) {
233 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
239 if (!strcasecmp(authtype, "MD5")) {
240 if (key && strlen(key) && s->challenge) {
243 char md5key[256] = "";
244 struct MD5Context md5;
245 unsigned char digest[16];
247 MD5Update(&md5, s->challenge, strlen(s->challenge));
248 MD5Update(&md5, password, strlen(password));
249 MD5Final(digest, &md5);
251 len += sprintf(md5key + len, "%2.2x", digest[x]);
252 if (!strcmp(md5key, key))
259 } else if (password && !strcasecmp(password, pass)) {
262 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
268 cat = ast_category_browse(cfg, cat);
271 strncpy(s->username, cat, sizeof(s->username) - 1);
272 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
273 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
277 ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
282 static int action_ping(struct mansession *s, struct message *m)
284 astman_send_response(s, m, "Pong", NULL);
288 static int action_logoff(struct mansession *s, struct message *m)
290 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
294 static int action_hangup(struct mansession *s, struct message *m)
296 struct ast_channel *c = NULL;
297 char *name = astman_get_header(m, "Channel");
299 astman_send_error(s, m, "No channel specified");
302 c = ast_channel_walk(NULL);
304 if (!strcasecmp(c->name, name)) {
307 c = ast_channel_walk(c);
310 astman_send_error(s, m, "No such channel");
313 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
314 astman_send_ack(s, m, "Channel Hungup");
318 static int action_status(struct mansession *s, struct message *m)
320 char *id = astman_get_header(m,"ActionID");
321 char idText[256] = "";
322 struct ast_channel *c;
324 astman_send_ack(s, m, "Channel status will follow");
325 c = ast_channel_walk(NULL);
326 if (id && strlen(id))
327 snprintf(idText,256,"ActionID: %s\r\n",id);
330 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
346 c->name, c->callerid ? c->callerid : "<unknown>",
347 ast_state2str(c->_state), c->context,
348 c->exten, c->priority, bridge, c->uniqueid, idText);
359 c->name, c->callerid ? c->callerid : "<unknown>",
360 ast_state2str(c->_state), bridge, c->uniqueid, idText);
362 c = ast_channel_walk(c);
365 "Event: StatusComplete\r\n"
371 static int action_redirect(struct mansession *s, struct message *m)
373 char *name = astman_get_header(m, "Channel");
374 char *name2 = astman_get_header(m, "ExtraChannel");
375 char *exten = astman_get_header(m, "Exten");
376 char *context = astman_get_header(m, "Context");
377 char *priority = astman_get_header(m, "Priority");
380 if (!name || !strlen(name)) {
381 astman_send_error(s, m, "Channel not specified");
384 if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
385 astman_send_error(s, m, "Invalid priority\n");
388 res = ast_async_goto_by_name(name, context, exten, pi);
391 res = ast_async_goto_by_name(name2, context, exten, pi);
393 astman_send_ack(s, m, "Dual Redirect successful");
395 astman_send_error(s, m, "Secondary redirect failed");
397 astman_send_ack(s, m, "Redirect successful");
399 astman_send_error(s, m, "Redirect failed");
403 static int action_command(struct mansession *s, struct message *m)
405 char *cmd = astman_get_header(m, "Command");
406 ast_mutex_lock(&s->lock);
408 ast_mutex_unlock(&s->lock);
409 ast_cli(s->fd, "Response: Follows\r\n");
410 /* FIXME: Wedge a ActionID response in here, waiting for later changes */
411 ast_cli_command(s->fd, cmd);
412 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
413 ast_mutex_lock(&s->lock);
415 ast_mutex_unlock(&s->lock);
419 static int action_originate(struct mansession *s, struct message *m)
421 char *name = astman_get_header(m, "Channel");
422 char *exten = astman_get_header(m, "Exten");
423 char *context = astman_get_header(m, "Context");
424 char *priority = astman_get_header(m, "Priority");
425 char *timeout = astman_get_header(m, "Timeout");
426 char *callerid = astman_get_header(m, "CallerID");
427 char *variable = astman_get_header(m, "Variable");
428 char *account = astman_get_header(m, "Account");
429 char *app = astman_get_header(m, "Application");
430 char *appdata = astman_get_header(m, "Data");
438 astman_send_error(s, m, "Channel not specified");
441 if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
442 astman_send_error(s, m, "Invalid priority\n");
445 if (strlen(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
446 astman_send_error(s, m, "Invalid timeout\n");
449 strncpy(tmp, name, sizeof(tmp) - 1);
451 data = strchr(tmp, '/');
453 astman_send_error(s, m, "Invalid channel\n");
459 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
461 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
464 astman_send_ack(s, m, "Originate successfully queued");
466 astman_send_error(s, m, "Originate failed");
470 static int action_mailboxstatus(struct mansession *s, struct message *m)
472 char *mailbox = astman_get_header(m, "Mailbox");
473 char *id = astman_get_header(m,"ActionID");
474 char idText[256] = "";
475 if (!mailbox || !strlen(mailbox)) {
476 astman_send_error(s, m, "Mailbox not specified");
479 if (id && strlen(id))
480 snprintf(idText,256,"ActionID: %s\r\n",id);
481 ast_cli(s->fd, "Response: Success\r\n"
483 "Message: Mailbox Status\r\n"
485 "Waiting: %d\r\n\r\n", idText, mailbox, ast_app_has_voicemail(mailbox));
489 static int action_mailboxcount(struct mansession *s, struct message *m)
491 char *mailbox = astman_get_header(m, "Mailbox");
492 char *id = astman_get_header(m,"ActionID");
493 char idText[256] = "";
494 int newmsgs = 0, oldmsgs = 0;
495 if (!mailbox || !strlen(mailbox)) {
496 astman_send_error(s, m, "Mailbox not specified");
499 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
500 if (id && strlen(id)) {
501 snprintf(idText,256,"ActionID: %s\r\n",id);
503 ast_cli(s->fd, "Response: Success\r\n"
505 "Message: Mailbox Message Count\r\n"
507 "NewMessages: %d\r\n"
508 "OldMessages: %d\r\n"
510 idText,mailbox, newmsgs, oldmsgs);
514 static int action_extensionstate(struct mansession *s, struct message *m)
516 char *exten = astman_get_header(m, "Exten");
517 char *context = astman_get_header(m, "Context");
518 char *id = astman_get_header(m,"ActionID");
519 char idText[256] = "";
522 if (!exten || !strlen(exten)) {
523 astman_send_error(s, m, "Extension not specified");
526 if (!context || !strlen(context))
528 status = ast_extension_state(NULL, context, exten);
529 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
530 if (id && strlen(id)) {
531 snprintf(idText,256,"ActionID: %s\r\n",id);
533 ast_cli(s->fd, "Response: Success\r\n"
535 "Message: Extension Status\r\n"
539 "Status: %d\r\n\r\n",
540 idText,exten, context, hint, status);
544 static int action_timeout(struct mansession *s, struct message *m)
546 struct ast_channel *c = NULL;
547 char *name = astman_get_header(m, "Channel");
548 int timeout = atoi(astman_get_header(m, "Timeout"));
550 astman_send_error(s, m, "No channel specified");
554 astman_send_error(s, m, "No timeout specified");
557 c = ast_channel_walk(NULL);
559 if (!strcasecmp(c->name, name)) {
562 c = ast_channel_walk(c);
565 astman_send_error(s, m, "No such channel");
568 ast_channel_setwhentohangup(c, timeout);
569 astman_send_ack(s, m, "Timeout Set");
573 static int process_message(struct mansession *s, struct message *m)
576 struct manager_action *tmp = first_action;
577 char *id = astman_get_header(m,"ActionID");
578 char idText[256] = "";
580 strncpy(action, astman_get_header(m, "Action"), sizeof(action));
581 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
583 if (!strlen(action)) {
584 astman_send_error(s, m, "Missing action in request");
587 if (id && strlen(id)) {
588 snprintf(idText,256,"ActionID: %s\r\n",id);
590 if (!s->authenticated) {
591 if (!strcasecmp(action, "Challenge")) {
593 authtype = astman_get_header(m, "AuthType");
594 if (!strcasecmp(authtype, "MD5")) {
595 if (!s->challenge || !strlen(s->challenge)) {
596 ast_mutex_lock(&s->lock);
597 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
598 ast_mutex_unlock(&s->lock);
600 ast_cli(s->fd, "Response: Success\r\n"
602 "Challenge: %s\r\n\r\n",
603 idText,s->challenge);
606 astman_send_error(s, m, "Must specify AuthType");
609 } else if (!strcasecmp(action, "Login")) {
610 if (authenticate(s, m)) {
612 astman_send_error(s, m, "Authentication failed");
615 s->authenticated = 1;
616 if (option_verbose > 1)
617 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
618 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
619 astman_send_ack(s, m, "Authentication accepted");
621 } else if (!strcasecmp(action, "Logoff")) {
622 astman_send_ack(s, m, "See ya");
625 astman_send_error(s, m, "Authentication Required");
628 if (!strcasecmp(action, tmp->action)) {
629 if ((s->writeperm & tmp->authority) == tmp->authority) {
633 astman_send_error(s, m, "Permission denied");
639 astman_send_error(s, m, "Invalid/unknown command");
644 static int get_input(struct mansession *s, char *output)
646 /* output must have at least sizeof(s->inbuf) space */
650 for (x=1;x<s->inlen;x++) {
651 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
652 /* Copy output data up to and including \r\n */
653 memcpy(output, s->inbuf, x + 1);
654 /* Add trailing \0 */
656 /* Move remaining data back to the front */
657 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
662 if (s->inlen >= sizeof(s->inbuf) - 1) {
663 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
668 res = ast_select(s->fd + 1, &fds, NULL, NULL, NULL);
670 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
671 } else if (res > 0) {
672 ast_mutex_lock(&s->lock);
673 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
674 ast_mutex_unlock(&s->lock);
679 s->inbuf[s->inlen] = '\0';
683 static void *session_do(void *data)
685 struct mansession *s = data;
689 ast_mutex_lock(&s->lock);
690 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
691 ast_mutex_unlock(&s->lock);
692 memset(&m, 0, sizeof(&m));
694 res = get_input(s, m.headers[m.hdrcount]);
696 /* Strip trailing \r\n */
697 if (strlen(m.headers[m.hdrcount]) < 2)
699 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
700 if (!strlen(m.headers[m.hdrcount])) {
701 if (process_message(s, &m))
703 memset(&m, 0, sizeof(&m));
704 } else if (m.hdrcount < MAX_HEADERS - 1)
709 if (s->authenticated) {
710 if (option_verbose > 1)
711 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
712 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
714 if (option_verbose > 1)
715 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", inet_ntoa(s->sin.sin_addr));
716 ast_log(LOG_EVENT, "Failed attempt from %s\n", inet_ntoa(s->sin.sin_addr));
722 static void *accept_thread(void *ignore)
725 struct sockaddr_in sin;
727 struct mansession *s;
733 pthread_attr_init(&attr);
734 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
737 sinlen = sizeof(sin);
738 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
740 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
743 p = getprotobyname("tcp");
745 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
746 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
749 s = malloc(sizeof(struct mansession));
751 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
754 memset(s, 0, sizeof(struct mansession));
755 memcpy(&s->sin, &sin, sizeof(sin));
756 /* For safety, make sure socket is non-blocking */
757 flags = fcntl(as, F_GETFL);
758 fcntl(as, F_SETFL, flags | O_NONBLOCK);
759 ast_mutex_init(&s->lock);
761 ast_mutex_lock(&sessionlock);
764 ast_mutex_unlock(&sessionlock);
765 if (pthread_create(&t, &attr, session_do, s))
768 pthread_attr_destroy(&attr);
772 int manager_event(int category, char *event, char *fmt, ...)
774 struct mansession *s;
778 ast_mutex_lock(&sessionlock);
781 if ((s->readperm & category) == category) {
782 ast_mutex_lock(&s->lock);
784 ast_cli(s->fd, "Event: %s\r\n", event);
786 vsnprintf(tmp, sizeof(tmp), fmt, ap);
788 write(s->fd, tmp, strlen(tmp));
789 ast_cli(s->fd, "\r\n");
791 ast_mutex_unlock(&s->lock);
795 ast_mutex_unlock(&sessionlock);
799 int ast_manager_unregister( char *action ) {
800 struct manager_action *cur = first_action, *prev = first_action;
802 ast_mutex_lock(&actionlock);
804 if (!strcasecmp(action, cur->action)) {
805 prev->next = cur->next;
807 if (option_verbose > 1)
808 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
809 ast_mutex_unlock(&actionlock);
815 ast_mutex_unlock(&actionlock);
819 static int manager_state_cb(char *context, char *exten, int state, void *data)
821 /* Notify managers of change */
822 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
826 int ast_manager_register( char *action, int auth,
827 int (*func)(struct mansession *s, struct message *m), char *synopsis)
829 struct manager_action *cur = first_action, *prev = NULL;
831 ast_mutex_lock(&actionlock);
832 while(cur) { /* Walk the list of actions */
833 if (!strcasecmp(cur->action, action)) {
834 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", action);
835 ast_mutex_unlock(&actionlock);
841 cur = malloc( sizeof(struct manager_action) );
843 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
844 ast_mutex_unlock(&actionlock);
847 strncpy( cur->action, action, 255 );
848 cur->authority = auth;
850 cur->synopsis = synopsis;
853 if( prev ) prev->next = cur;
854 else first_action = cur;
856 if (option_verbose > 1)
857 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", action);
858 ast_mutex_unlock(&actionlock);
862 static int registered = 0;
864 int init_manager(void)
866 struct ast_config *cfg;
868 int oldportno = portno;
869 static struct sockaddr_in ba;
872 /* Register default actions */
873 ast_manager_register( "Ping", 0, action_ping, "Ping" );
874 ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
875 ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
876 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
877 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
878 ast_manager_register( "Originate", EVENT_FLAG_CALL, action_originate, "Originate Call" );
879 ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
880 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
881 ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
882 ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
883 ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
885 ast_cli_register(&show_mancmds_cli);
886 ast_cli_register(&show_manconn_cli);
887 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
890 portno = DEFAULT_MANAGER_PORT;
891 cfg = ast_load("manager.conf");
893 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
896 memset(&ba, 0, sizeof(ba));
897 val = ast_variable_retrieve(cfg, "general", "enabled");
899 enabled = ast_true(val);
901 if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
902 if (sscanf(val, "%d", &portno) != 1) {
903 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
904 portno = DEFAULT_MANAGER_PORT;
908 ba.sin_family = AF_INET;
909 ba.sin_port = htons(portno);
910 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
912 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
913 if (!inet_aton(val, &ba.sin_addr)) {
914 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
915 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
919 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
921 /* Can't be done yet */
925 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
930 /* If not enabled, do nothing */
935 asock = socket(AF_INET, SOCK_STREAM, 0);
937 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
940 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
941 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
942 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
947 if (listen(asock, 2)) {
948 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
954 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
955 pthread_create(&t, NULL, accept_thread, NULL);
960 int reload_manager(void)
962 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
963 return init_manager();