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>
29 #include <asterisk/channel.h>
30 #include <asterisk/file.h>
31 #include <asterisk/manager.h>
32 #include <asterisk/config.h>
33 #include <asterisk/lock.h>
34 #include <asterisk/logger.h>
35 #include <asterisk/options.h>
36 #include <asterisk/cli.h>
37 #include <asterisk/app.h>
38 #include <asterisk/pbx.h>
39 #include <asterisk/md5.h>
40 #include <asterisk/acl.h>
41 #include <asterisk/utils.h>
43 struct fast_originate_helper
58 static int enabled = 0;
59 static int portno = DEFAULT_MANAGER_PORT;
60 static int asock = -1;
62 static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
63 static int block_sockets = 0;
65 static struct permalias {
69 { EVENT_FLAG_SYSTEM, "system" },
70 { EVENT_FLAG_CALL, "call" },
71 { EVENT_FLAG_LOG, "log" },
72 { EVENT_FLAG_VERBOSE, "verbose" },
73 { EVENT_FLAG_COMMAND, "command" },
74 { EVENT_FLAG_AGENT, "agent" },
75 { EVENT_FLAG_USER, "user" },
79 static struct mansession *sessions = NULL;
80 static struct manager_action *first_action = NULL;
81 static ast_mutex_t actionlock = AST_MUTEX_INITIALIZER;
83 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
85 /* Try to write string, but wait no more than ms milliseconds
90 res = write(fd, s, len);
91 if ((res < 0) && (errno != EAGAIN)) {
98 fds[0].events = POLLOUT;
99 /* Wait until writable again */
100 res = poll(fds, 1, timeoutms);
107 static char *complete_show_mancmd(char *line, char *word, int pos, int state)
109 struct manager_action *cur = first_action;
112 ast_mutex_lock(&actionlock);
113 while (cur) { /* Walk the list of actions */
114 if (!strncasecmp(word, cur->action, strlen(word))) {
115 if (++which > state) {
116 char *ret = strdup(cur->action);
117 ast_mutex_unlock(&actionlock);
123 ast_mutex_unlock(&actionlock);
127 static int handle_showmancmd(int fd, int argc, char *argv[])
129 struct manager_action *cur = first_action;
133 return RESULT_SHOWUSAGE;
134 ast_mutex_lock(&actionlock);
135 while (cur) { /* Walk the list of actions */
136 for (num = 3; num < argc; num++) {
137 if (!strcasecmp(cur->action, argv[num])) {
138 ast_cli(fd, "Action: %s\nSynopsis: %s\n%s\n", cur->action, cur->synopsis, cur->description ? cur->description : "");
144 ast_mutex_unlock(&actionlock);
145 return RESULT_SUCCESS;
148 static int handle_showmancmds(int fd, int argc, char *argv[])
150 struct manager_action *cur = first_action;
151 char *format = " %-15.15s %-45.45s\n";
153 ast_mutex_lock(&actionlock);
154 ast_cli(fd, format, "Action", "Synopsis");
155 while (cur) { /* Walk the list of actions */
156 ast_cli(fd, format, cur->action, cur->synopsis);
160 ast_mutex_unlock(&actionlock);
161 return RESULT_SUCCESS;
164 static int handle_showmanconn(int fd, int argc, char *argv[])
166 struct mansession *s;
167 char *format = " %-15.15s %-15.15s\n";
168 ast_mutex_lock(&sessionlock);
170 ast_cli(fd, format, "Username", "IP Address");
172 ast_cli(fd, format,s->username, inet_ntoa(s->sin.sin_addr));
176 ast_mutex_unlock(&sessionlock);
177 return RESULT_SUCCESS;
180 static char showmancmd_help[] =
181 "Usage: show manager command <actionname>\n"
182 " Shows the detailed description for a specific manager command.\n";
184 static char showmancmds_help[] =
185 "Usage: show manager commands\n"
186 " Prints a listing of all the available manager commands.\n";
188 static char showmanconn_help[] =
189 "Usage: show manager connected\n"
190 " Prints a listing of the users that are connected to the\n"
191 "manager interface.\n";
193 static struct ast_cli_entry show_mancmd_cli =
194 { { "show", "manager", "command", NULL },
195 handle_showmancmd, "Show manager command", showmancmd_help, complete_show_mancmd };
197 static struct ast_cli_entry show_mancmds_cli =
198 { { "show", "manager", "commands", NULL },
199 handle_showmancmds, "Show manager commands", showmancmds_help };
201 static struct ast_cli_entry show_manconn_cli =
202 { { "show", "manager", "connected", NULL },
203 handle_showmanconn, "Show connected manager users", showmanconn_help };
205 static void destroy_session(struct mansession *s)
207 struct mansession *cur, *prev = NULL;
208 ast_mutex_lock(&sessionlock);
218 prev->next = cur->next;
220 sessions = cur->next;
225 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
226 ast_mutex_unlock(&sessionlock);
230 char *astman_get_header(struct message *m, char *var)
234 snprintf(cmp, sizeof(cmp), "%s: ", var);
235 for (x=0;x<m->hdrcount;x++)
236 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
237 return m->headers[x] + strlen(cmp);
241 void astman_send_error(struct mansession *s, struct message *m, char *error)
243 char *id = astman_get_header(m,"ActionID");
244 ast_mutex_lock(&s->lock);
245 ast_cli(s->fd, "Response: Error\r\n");
246 if (id && !ast_strlen_zero(id))
247 ast_cli(s->fd, "ActionID: %s\r\n",id);
248 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
249 ast_mutex_unlock(&s->lock);
252 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
254 char *id = astman_get_header(m,"ActionID");
255 ast_mutex_lock(&s->lock);
256 ast_cli(s->fd, "Response: %s\r\n", resp);
257 if (id && !ast_strlen_zero(id))
258 ast_cli(s->fd, "ActionID: %s\r\n",id);
260 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
262 ast_cli(s->fd, "\r\n");
263 ast_mutex_unlock(&s->lock);
266 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
268 astman_send_response(s, m, "Success", msg);
271 static int get_perm(char *instr)
280 strncpy(tmp, instr, sizeof(tmp) - 1);
282 c = strsep(&stringp, ",");
284 for (x=0;x<sizeof(perms) / sizeof(perms[0]);x++) {
285 if (!strcasecmp(perms[x].label, c))
288 c = strsep(&stringp, ",");
293 static int set_eventmask(struct mansession *s, char *eventmask)
297 if (!strcasecmp(eventmask, "on") || ast_true(eventmask)) {
298 ast_mutex_lock(&s->lock);
300 ast_mutex_unlock(&s->lock);
302 } else if (!strcasecmp(eventmask, "off") || ast_false(eventmask)) {
303 ast_mutex_lock(&s->lock);
305 ast_mutex_unlock(&s->lock);
311 static int authenticate(struct mansession *s, struct message *m)
313 struct ast_config *cfg;
315 char *user = astman_get_header(m, "Username");
316 char *pass = astman_get_header(m, "Secret");
317 char *authtype = astman_get_header(m, "AuthType");
318 char *key = astman_get_header(m, "Key");
319 char *events = astman_get_header(m, "Events");
321 cfg = ast_load("manager.conf");
324 cat = ast_category_browse(cfg, NULL);
326 if (strcasecmp(cat, "general")) {
328 if (!strcasecmp(cat, user)) {
329 struct ast_variable *v;
330 struct ast_ha *ha = NULL;
331 char *password = NULL;
332 v = ast_variable_browse(cfg, cat);
334 if (!strcasecmp(v->name, "secret")) {
336 } else if (!strcasecmp(v->name, "permit") ||
337 !strcasecmp(v->name, "deny")) {
338 ha = ast_append_ha(v->name, v->value, ha);
342 if (ha && !ast_apply_ha(ha, &(s->sin))) {
343 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
349 if (!strcasecmp(authtype, "MD5")) {
350 if (key && !ast_strlen_zero(key) && s->challenge) {
353 char md5key[256] = "";
354 struct MD5Context md5;
355 unsigned char digest[16];
357 MD5Update(&md5, s->challenge, strlen(s->challenge));
358 MD5Update(&md5, password, strlen(password));
359 MD5Final(digest, &md5);
361 len += sprintf(md5key + len, "%2.2x", digest[x]);
362 if (!strcmp(md5key, key))
369 } else if (password && !strcasecmp(password, pass)) {
372 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
378 cat = ast_category_browse(cfg, cat);
381 strncpy(s->username, cat, sizeof(s->username) - 1);
382 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
383 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
386 set_eventmask(s, events);
389 ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
394 static char mandescr_ping[] =
395 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
396 " manager connection open.\n"
399 static int action_ping(struct mansession *s, struct message *m)
401 astman_send_response(s, m, "Pong", NULL);
405 static int action_events(struct mansession *s, struct message *m)
407 char *mask = astman_get_header(m, "EventMask");
410 res = set_eventmask(s, mask);
412 astman_send_response(s, m, "Events On", NULL);
414 astman_send_response(s, m, "Events Off", NULL);
416 astman_send_response(s, m, "EventMask parse error", NULL);
420 static int action_logoff(struct mansession *s, struct message *m)
422 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
426 static int action_hangup(struct mansession *s, struct message *m)
428 struct ast_channel *c = NULL;
429 char *name = astman_get_header(m, "Channel");
430 if (ast_strlen_zero(name)) {
431 astman_send_error(s, m, "No channel specified");
434 c = ast_channel_walk_locked(NULL);
436 if (!strcasecmp(c->name, name)) {
439 ast_mutex_unlock(&c->lock);
440 c = ast_channel_walk_locked(c);
443 astman_send_error(s, m, "No such channel");
446 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
447 ast_mutex_unlock(&c->lock);
448 astman_send_ack(s, m, "Channel Hungup");
452 static int action_status(struct mansession *s, struct message *m)
454 char *id = astman_get_header(m,"ActionID");
455 char idText[256] = "";
456 struct ast_channel *c;
458 astman_send_ack(s, m, "Channel status will follow");
459 c = ast_channel_walk_locked(NULL);
460 if (id && !ast_strlen_zero(id))
461 snprintf(idText,256,"ActionID: %s\r\n",id);
464 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
480 c->name, c->callerid ? c->callerid : "<unknown>",
481 ast_state2str(c->_state), c->context,
482 c->exten, c->priority, bridge, c->uniqueid, idText);
493 c->name, c->callerid ? c->callerid : "<unknown>",
494 ast_state2str(c->_state), bridge, c->uniqueid, idText);
496 ast_mutex_unlock(&c->lock);
497 c = ast_channel_walk_locked(c);
500 "Event: StatusComplete\r\n"
506 static int action_redirect(struct mansession *s, struct message *m)
508 char *name = astman_get_header(m, "Channel");
509 char *name2 = astman_get_header(m, "ExtraChannel");
510 char *exten = astman_get_header(m, "Exten");
511 char *context = astman_get_header(m, "Context");
512 char *priority = astman_get_header(m, "Priority");
513 struct ast_channel *chan, *chan2 = NULL;
516 if (!name || ast_strlen_zero(name)) {
517 astman_send_error(s, m, "Channel not specified");
520 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
521 astman_send_error(s, m, "Invalid priority\n");
524 chan = ast_get_channel_by_name_locked(name);
526 astman_send_error(s, m, "Channel not existant");
529 if (!ast_strlen_zero(name2))
530 chan2 = ast_get_channel_by_name_locked(name2);
531 res = ast_async_goto(chan, context, exten, pi);
533 if (!ast_strlen_zero(name2)) {
535 res = ast_async_goto(chan2, context, exten, pi);
539 astman_send_ack(s, m, "Dual Redirect successful");
541 astman_send_error(s, m, "Secondary redirect failed");
543 astman_send_ack(s, m, "Redirect successful");
545 astman_send_error(s, m, "Redirect failed");
547 ast_mutex_unlock(&chan->lock);
549 ast_mutex_unlock(&chan2->lock);
553 static int action_command(struct mansession *s, struct message *m)
555 char *cmd = astman_get_header(m, "Command");
556 char *id = astman_get_header(m, "ActionID");
557 ast_mutex_lock(&s->lock);
559 ast_mutex_unlock(&s->lock);
560 ast_cli(s->fd, "Response: Follows\r\n");
561 if (id && !ast_strlen_zero(id))
562 ast_cli(s->fd, "ActionID: %s\r\n", id);
563 /* FIXME: Wedge a ActionID response in here, waiting for later changes */
564 ast_cli_command(s->fd, cmd);
565 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
566 ast_mutex_lock(&s->lock);
568 ast_mutex_unlock(&s->lock);
572 static void *fast_originate(void *data)
574 struct fast_originate_helper *in = data;
577 if (!ast_strlen_zero(in->app)) {
578 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
580 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
586 static char mandescr_originate[] =
587 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
588 " Application/Data\n"
589 "Variables: (Names marked with * are required)\n"
590 " *Channel: Channel name to call\n"
591 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
592 " Context: Context to use (requires 'Exten' and 'Priority')\n"
593 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
594 " Application: Application to use\n"
595 " Data: Data to use (requires 'Application')\n"
596 " Timeout: How long to wait for call to be answered (in ms)\n"
597 " CallerID: Caller ID to be set on the outgoing channel\n"
598 " Variable: Channel variable to set (VAR1=value1|VAR2=value2)\n"
599 " Account: Account code\n"
600 " Async: Set to 'true' for fast origination\n";
602 static int action_originate(struct mansession *s, struct message *m)
604 char *name = astman_get_header(m, "Channel");
605 char *exten = astman_get_header(m, "Exten");
606 char *context = astman_get_header(m, "Context");
607 char *priority = astman_get_header(m, "Priority");
608 char *timeout = astman_get_header(m, "Timeout");
609 char *callerid = astman_get_header(m, "CallerID");
610 char *variable = astman_get_header(m, "Variable");
611 char *account = astman_get_header(m, "Account");
612 char *app = astman_get_header(m, "Application");
613 char *appdata = astman_get_header(m, "Data");
614 char *async = astman_get_header(m, "Async");
624 astman_send_error(s, m, "Channel not specified");
627 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
628 astman_send_error(s, m, "Invalid priority\n");
631 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
632 astman_send_error(s, m, "Invalid timeout\n");
635 strncpy(tmp, name, sizeof(tmp) - 1);
637 data = strchr(tmp, '/');
639 astman_send_error(s, m, "Invalid channel\n");
646 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
653 memset(fast, 0, sizeof(struct fast_originate_helper));
654 strncpy(fast->tech, tech, sizeof(fast->tech) - 1);
655 strncpy(fast->data, data, sizeof(fast->data) - 1);
656 strncpy(fast->app, app, sizeof(fast->app) - 1);
657 strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1);
658 strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1);
659 strncpy(fast->variable, variable, sizeof(fast->variable) - 1);
660 strncpy(fast->account, account, sizeof(fast->account) - 1);
661 strncpy(fast->context, context, sizeof(fast->context) - 1);
662 strncpy(fast->exten, exten, sizeof(fast->exten) - 1);
665 pthread_attr_init(&attr);
666 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
667 if (pthread_create(&th, &attr, fast_originate, fast))
676 } else if (!ast_strlen_zero(app)) {
677 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
679 if (exten && context && pi)
680 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
682 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
687 astman_send_ack(s, m, "Originate successfully queued");
689 astman_send_error(s, m, "Originate failed");
693 static int action_mailboxstatus(struct mansession *s, struct message *m)
695 char *mailbox = astman_get_header(m, "Mailbox");
696 char *id = astman_get_header(m,"ActionID");
697 char idText[256] = "";
698 if (!mailbox || ast_strlen_zero(mailbox)) {
699 astman_send_error(s, m, "Mailbox not specified");
702 if (id && !ast_strlen_zero(id))
703 snprintf(idText,256,"ActionID: %s\r\n",id);
704 ast_cli(s->fd, "Response: Success\r\n"
706 "Message: Mailbox Status\r\n"
708 "Waiting: %d\r\n\r\n", idText, mailbox, ast_app_has_voicemail(mailbox));
712 static int action_mailboxcount(struct mansession *s, struct message *m)
714 char *mailbox = astman_get_header(m, "Mailbox");
715 char *id = astman_get_header(m,"ActionID");
716 char idText[256] = "";
717 int newmsgs = 0, oldmsgs = 0;
718 if (!mailbox || ast_strlen_zero(mailbox)) {
719 astman_send_error(s, m, "Mailbox not specified");
722 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
723 if (id && !ast_strlen_zero(id)) {
724 snprintf(idText,256,"ActionID: %s\r\n",id);
726 ast_cli(s->fd, "Response: Success\r\n"
728 "Message: Mailbox Message Count\r\n"
730 "NewMessages: %d\r\n"
731 "OldMessages: %d\r\n"
733 idText,mailbox, newmsgs, oldmsgs);
737 static int action_extensionstate(struct mansession *s, struct message *m)
739 char *exten = astman_get_header(m, "Exten");
740 char *context = astman_get_header(m, "Context");
741 char *id = astman_get_header(m,"ActionID");
742 char idText[256] = "";
745 if (!exten || ast_strlen_zero(exten)) {
746 astman_send_error(s, m, "Extension not specified");
749 if (!context || ast_strlen_zero(context))
751 status = ast_extension_state(NULL, context, exten);
752 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
753 if (id && !ast_strlen_zero(id)) {
754 snprintf(idText,256,"ActionID: %s\r\n",id);
756 ast_cli(s->fd, "Response: Success\r\n"
758 "Message: Extension Status\r\n"
762 "Status: %d\r\n\r\n",
763 idText,exten, context, hint, status);
767 static int action_timeout(struct mansession *s, struct message *m)
769 struct ast_channel *c = NULL;
770 char *name = astman_get_header(m, "Channel");
771 int timeout = atoi(astman_get_header(m, "Timeout"));
772 if (ast_strlen_zero(name)) {
773 astman_send_error(s, m, "No channel specified");
777 astman_send_error(s, m, "No timeout specified");
780 c = ast_channel_walk_locked(NULL);
782 if (!strcasecmp(c->name, name)) {
785 ast_mutex_unlock(&c->lock);
786 c = ast_channel_walk_locked(c);
789 astman_send_error(s, m, "No such channel");
792 ast_channel_setwhentohangup(c, timeout);
793 ast_mutex_unlock(&c->lock);
794 astman_send_ack(s, m, "Timeout Set");
798 static int process_message(struct mansession *s, struct message *m)
801 struct manager_action *tmp = first_action;
802 char *id = astman_get_header(m,"ActionID");
803 char idText[256] = "";
805 strncpy(action, astman_get_header(m, "Action"), sizeof(action));
806 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
808 if (ast_strlen_zero(action)) {
809 astman_send_error(s, m, "Missing action in request");
812 if (id && !ast_strlen_zero(id)) {
813 snprintf(idText,256,"ActionID: %s\r\n",id);
815 if (!s->authenticated) {
816 if (!strcasecmp(action, "Challenge")) {
818 authtype = astman_get_header(m, "AuthType");
819 if (!strcasecmp(authtype, "MD5")) {
820 if (!s->challenge || ast_strlen_zero(s->challenge)) {
821 ast_mutex_lock(&s->lock);
822 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
823 ast_mutex_unlock(&s->lock);
825 ast_cli(s->fd, "Response: Success\r\n"
827 "Challenge: %s\r\n\r\n",
828 idText,s->challenge);
831 astman_send_error(s, m, "Must specify AuthType");
834 } else if (!strcasecmp(action, "Login")) {
835 if (authenticate(s, m)) {
837 astman_send_error(s, m, "Authentication failed");
840 s->authenticated = 1;
841 if (option_verbose > 1)
842 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
843 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
844 astman_send_ack(s, m, "Authentication accepted");
846 } else if (!strcasecmp(action, "Logoff")) {
847 astman_send_ack(s, m, "See ya");
850 astman_send_error(s, m, "Authentication Required");
853 if (!strcasecmp(action, tmp->action)) {
854 if ((s->writeperm & tmp->authority) == tmp->authority) {
858 astman_send_error(s, m, "Permission denied");
864 astman_send_error(s, m, "Invalid/unknown command");
869 static int get_input(struct mansession *s, char *output)
871 /* output must have at least sizeof(s->inbuf) space */
874 struct pollfd fds[1];
875 for (x=1;x<s->inlen;x++) {
876 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
877 /* Copy output data up to and including \r\n */
878 memcpy(output, s->inbuf, x + 1);
879 /* Add trailing \0 */
881 /* Move remaining data back to the front */
882 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
887 if (s->inlen >= sizeof(s->inbuf) - 1) {
888 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
892 fds[0].events = POLLIN;
893 res = poll(fds, 1, -1);
895 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
896 } else if (res > 0) {
897 ast_mutex_lock(&s->lock);
898 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
899 ast_mutex_unlock(&s->lock);
904 s->inbuf[s->inlen] = '\0';
908 static void *session_do(void *data)
910 struct mansession *s = data;
914 ast_mutex_lock(&s->lock);
915 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
916 ast_mutex_unlock(&s->lock);
917 memset(&m, 0, sizeof(&m));
919 res = get_input(s, m.headers[m.hdrcount]);
921 /* Strip trailing \r\n */
922 if (strlen(m.headers[m.hdrcount]) < 2)
924 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
925 if (ast_strlen_zero(m.headers[m.hdrcount])) {
926 if (process_message(s, &m))
928 memset(&m, 0, sizeof(&m));
929 } else if (m.hdrcount < MAX_HEADERS - 1)
934 if (s->authenticated) {
935 if (option_verbose > 1)
936 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
937 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
939 if (option_verbose > 1)
940 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", inet_ntoa(s->sin.sin_addr));
941 ast_log(LOG_EVENT, "Failed attempt from %s\n", inet_ntoa(s->sin.sin_addr));
947 static void *accept_thread(void *ignore)
950 struct sockaddr_in sin;
952 struct mansession *s;
958 pthread_attr_init(&attr);
959 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
962 sinlen = sizeof(sin);
963 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
965 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
968 p = getprotobyname("tcp");
970 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
971 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
974 s = malloc(sizeof(struct mansession));
976 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
979 memset(s, 0, sizeof(struct mansession));
980 memcpy(&s->sin, &sin, sizeof(sin));
982 if(! block_sockets) {
983 /* For safety, make sure socket is non-blocking */
984 flags = fcntl(as, F_GETFL);
985 fcntl(as, F_SETFL, flags | O_NONBLOCK);
987 ast_mutex_init(&s->lock);
990 ast_mutex_lock(&sessionlock);
993 ast_mutex_unlock(&sessionlock);
994 if (pthread_create(&t, &attr, session_do, s))
997 pthread_attr_destroy(&attr);
1001 int manager_event(int category, char *event, char *fmt, ...)
1003 struct mansession *s;
1007 ast_mutex_lock(&sessionlock);
1010 if (((s->readperm & category) == category) && s->send_events) {
1011 ast_mutex_lock(&s->lock);
1013 ast_cli(s->fd, "Event: %s\r\n", event);
1015 vsnprintf(tmp, sizeof(tmp), fmt, ap);
1017 ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
1018 ast_cli(s->fd, "\r\n");
1020 ast_mutex_unlock(&s->lock);
1024 ast_mutex_unlock(&sessionlock);
1028 int ast_manager_unregister( char *action ) {
1029 struct manager_action *cur = first_action, *prev = first_action;
1031 ast_mutex_lock(&actionlock);
1033 if (!strcasecmp(action, cur->action)) {
1034 prev->next = cur->next;
1036 if (option_verbose > 1)
1037 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1038 ast_mutex_unlock(&actionlock);
1044 ast_mutex_unlock(&actionlock);
1048 static int manager_state_cb(char *context, char *exten, int state, void *data)
1050 /* Notify managers of change */
1051 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1055 static int ast_manager_register_struct(struct manager_action *act)
1057 struct manager_action *cur = first_action, *prev = NULL;
1060 ast_mutex_lock(&actionlock);
1061 while(cur) { /* Walk the list of actions */
1062 ret = strcasecmp(cur->action, act->action);
1064 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1065 ast_mutex_unlock(&actionlock);
1067 } else if (ret > 0) {
1068 /* Insert these alphabetically */
1070 act->next = prev->next;
1073 act->next = first_action;
1090 if (option_verbose > 1)
1091 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1092 ast_mutex_unlock(&actionlock);
1096 int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description)
1098 struct manager_action *cur;
1100 cur = malloc(sizeof(struct manager_action));
1102 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1103 ast_mutex_unlock(&actionlock);
1106 cur->action = action;
1107 cur->authority = auth;
1109 cur->synopsis = synopsis;
1110 cur->description = description;
1113 ast_manager_register_struct(cur);
1118 static int registered = 0;
1120 int init_manager(void)
1122 struct ast_config *cfg;
1124 int oldportno = portno;
1125 static struct sockaddr_in ba;
1128 /* Register default actions */
1129 ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping);
1130 ast_manager_register( "Events", 0, action_events, "Contol Event Flow" );
1131 ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
1132 ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
1133 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
1134 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
1135 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1136 ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
1137 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
1138 ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
1139 ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
1140 ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
1142 ast_cli_register(&show_mancmd_cli);
1143 ast_cli_register(&show_mancmds_cli);
1144 ast_cli_register(&show_manconn_cli);
1145 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1148 portno = DEFAULT_MANAGER_PORT;
1149 cfg = ast_load("manager.conf");
1151 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
1154 memset(&ba, 0, sizeof(ba));
1155 val = ast_variable_retrieve(cfg, "general", "enabled");
1157 enabled = ast_true(val);
1159 val = ast_variable_retrieve(cfg, "general", "block-sockets");
1161 block_sockets = ast_true(val);
1163 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1164 if (sscanf(val, "%d", &portno) != 1) {
1165 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1166 portno = DEFAULT_MANAGER_PORT;
1168 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
1169 if (sscanf(val, "%d", &portno) != 1) {
1170 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1171 portno = DEFAULT_MANAGER_PORT;
1173 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
1176 ba.sin_family = AF_INET;
1177 ba.sin_port = htons(portno);
1178 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1180 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1181 if (!inet_aton(val, &ba.sin_addr)) {
1182 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1183 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1187 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1189 /* Can't be done yet */
1193 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1198 /* If not enabled, do nothing */
1203 asock = socket(AF_INET, SOCK_STREAM, 0);
1205 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1208 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1209 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1210 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1215 if (listen(asock, 2)) {
1216 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1222 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1223 pthread_create(&t, NULL, accept_thread, NULL);
1228 int reload_manager(void)
1230 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1231 return init_manager();