Newer
Older
/* Add trailing \0 */
output[x+1] = '\0';
/* Move remaining data back to the front */
memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
s->inlen -= (x + 1);
return 1;
}
}
if (s->inlen >= sizeof(s->inbuf) - 1) {
ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
s->inlen = 0;
}
fds[0].fd = s->fd;
fds[0].events = POLLIN;
res = poll(fds, 1, -1);
if (res < 0) {
ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
} else if (res > 0) {
ast_mutex_lock(&s->lock);
res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
ast_mutex_unlock(&s->lock);
if (res < 1)
return -1;
}
s->inlen += res;
s->inbuf[s->inlen] = '\0';
return 0;
}
static void *session_do(void *data)
{
struct mansession *s = data;
struct message m;
int res;
ast_mutex_lock(&s->lock);
ast_mutex_unlock(&s->lock);
memset(&m, 0, sizeof(&m));
for (;;) {
res = get_input(s, m.headers[m.hdrcount]);
if (res > 0) {
/* Strip trailing \r\n */
if (strlen(m.headers[m.hdrcount]) < 2)
continue;
m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
if (ast_strlen_zero(m.headers[m.hdrcount])) {
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
if (process_message(s, &m))
break;
memset(&m, 0, sizeof(&m));
} else if (m.hdrcount < MAX_HEADERS - 1)
m.hdrcount++;
} else if (res < 0)
break;
}
if (s->authenticated) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
} else {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", inet_ntoa(s->sin.sin_addr));
ast_log(LOG_EVENT, "Failed attempt from %s\n", inet_ntoa(s->sin.sin_addr));
}
destroy_session(s);
return NULL;
}
static void *accept_thread(void *ignore)
{
int as;
struct sockaddr_in sin;
int sinlen;
struct mansession *s;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
as = accept(asock, (struct sockaddr *)&sin, &sinlen);
if (as < 0) {
ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
continue;
}
p = getprotobyname("tcp");
if( p ) {
if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
}
}
s = malloc(sizeof(struct mansession));
if (!s) {
ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
continue;
}
memset(s, 0, sizeof(struct mansession));
memcpy(&s->sin, &sin, sizeof(sin));
if(! block_sockets) {
/* For safety, make sure socket is non-blocking */
flags = fcntl(as, F_GETFL);
fcntl(as, F_SETFL, flags | O_NONBLOCK);
}
ast_mutex_init(&s->lock);
ast_mutex_lock(&sessionlock);
ast_mutex_unlock(&sessionlock);
if (pthread_create(&t, &attr, session_do, s))
}
int manager_event(int category, char *event, char *fmt, ...)
{
struct mansession *s;
char tmp[4096];
va_list ap;
ast_mutex_lock(&sessionlock);
if (((s->readperm & category) == category) && s->send_events) {
ast_mutex_lock(&s->lock);
if (!s->blocking) {
ast_cli(s->fd, "Event: %s\r\n", event);
va_start(ap, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
ast_mutex_unlock(&s->lock);
ast_mutex_unlock(&sessionlock);
int ast_manager_unregister( char *action ) {
struct manager_action *cur = first_action, *prev = first_action;
ast_mutex_lock(&actionlock);
while( cur ) {
if (!strcasecmp(action, cur->action)) {
prev->next = cur->next;
free(cur);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
ast_mutex_unlock(&actionlock);
return 0;
}
prev = cur;
cur = cur->next;
}
ast_mutex_unlock(&actionlock);
static int manager_state_cb(char *context, char *exten, int state, void *data)
{
/* Notify managers of change */
manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
return 0;
}
static int ast_manager_register_struct(struct manager_action *act)
{
struct manager_action *cur = first_action, *prev = NULL;
int ret;
ast_mutex_lock(&actionlock);
ret = strcasecmp(cur->action, act->action);
if (ret == 0) {
ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
ast_mutex_unlock(&actionlock);
return -1;
} else if (ret > 0) {
/* Insert these alphabetically */
if (prev) {
act->next = prev->next;
prev->next = act;
} else {
act->next = first_action;
first_action = act;
}
break;
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
if (!cur) {
if (prev)
prev->next = act;
else
first_action = act;
act->next = NULL;
}
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
ast_mutex_unlock(&actionlock);
return 0;
}
int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description)
{
struct manager_action *cur;
cur = malloc(sizeof(struct manager_action));
if (!cur) {
ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
ast_mutex_unlock(&actionlock);
cur->action = action;
cur->authority = auth;
cur->func = func;
cur->synopsis = synopsis;
cur->description = description;
ast_manager_register_struct(cur);
return 0;
}
static int registered = 0;
int init_manager(void)
{
struct ast_config *cfg;
char *val;
int oldportno = portno;
static struct sockaddr_in ba;
int x = 1;
if (!registered) {
/* Register default actions */
ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping);
ast_manager_register( "Events", 0, action_events, "Contol Event Flow" );
ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
ast_manager_register( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable" );
ast_manager_register( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable" );
ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
ast_cli_register(&show_mancmd_cli);
ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
portno = DEFAULT_MANAGER_PORT;
cfg = ast_load("manager.conf");
if (!cfg) {
ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
return 0;
}
memset(&ba, 0, sizeof(ba));
val = ast_variable_retrieve(cfg, "general", "enabled");
if (val)
enabled = ast_true(val);
val = ast_variable_retrieve(cfg, "general", "block-sockets");
if(val)
block_sockets = ast_true(val);
James Golovich
committed
if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
if (sscanf(val, "%d", &portno) != 1) {
ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
portno = DEFAULT_MANAGER_PORT;
}
James Golovich
committed
} else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
if (sscanf(val, "%d", &portno) != 1) {
ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
portno = DEFAULT_MANAGER_PORT;
}
ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
}
ba.sin_family = AF_INET;
ba.sin_port = htons(portno);
memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
if (!inet_aton(val, &ba.sin_addr)) {
ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
}
}
if ((asock > -1) && ((portno != oldportno) || !enabled)) {
#if 0
/* Can't be done yet */
close(asock);
asock = -1;
#else
ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
#endif
}
if (asock < 0) {
asock = socket(AF_INET, SOCK_STREAM, 0);
if (asock < 0) {
ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
return -1;
}
setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
close(asock);
asock = -1;
return -1;
}
if (listen(asock, 2)) {
ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
close(asock);
asock = -1;
return -1;
}
if (option_verbose)
ast_verbose("Asterisk Management interface listening on port %d\n", portno);
pthread_create(&t, NULL, accept_thread, NULL);
}
return 0;
}
int reload_manager(void)
{
manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");