diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index ac3a2b2dca2f8d35bcbb472fc1a8284c343a6d30..26abd9d224c5f30b846718a61d6c1a919e47ca7c 100755 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -66,7 +66,7 @@ struct mansession { int writeperm; char inbuf[MAX_LEN]; int inlen; - + int send_events; struct mansession *next; }; @@ -84,6 +84,8 @@ struct manager_action { struct manager_action *next; }; +int ast_carefulwrite(int fd, char *s, int len, int timeoutms); + /* External routines may register/unregister manager callbacks this way */ int ast_manager_register( char *action, int authority, int (*func)(struct mansession *s, struct message *m), char *synopsis); diff --git a/manager.c b/manager.c index ed285ec6986307c8c6620c03ee5f6f3fedcdb44f..ea738589efc76a704b2fefe45a16507fbf1ebbdb 100755 --- a/manager.c +++ b/manager.c @@ -43,6 +43,7 @@ static int portno = DEFAULT_MANAGER_PORT; static int asock = -1; static pthread_t t; static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER; +static int block_sockets = 0; static struct permalias { int num; @@ -62,6 +63,37 @@ static struct mansession *sessions = NULL; static struct manager_action *first_action = NULL; static ast_mutex_t actionlock = AST_MUTEX_INITIALIZER; + + + +int ast_carefulwrite(int fd, char *s, int len, int timeoutms) +{ + /* Try to write string, but wait no more than ms milliseconds + before timing out */ + int res=0; + struct timeval tv; + fd_set fds; + while(len) { + res = write(fd, s, len); + if ((res < 0) && (errno != EAGAIN)) { + return -1; + } + if (res < 0) res = 0; + len -= res; + s += res; + tv.tv_sec = timeoutms / 1000; + tv.tv_usec = timeoutms % 1000; + FD_ZERO(&fds); + FD_SET(fd, &fds); + /* Wait until writable again */ + res = select(fd + 1, NULL, &fds, NULL, &tv); + if (res < 1) + return -1; + } + return res; +} + + static int handle_showmancmds(int fd, int argc, char *argv[]) { struct manager_action *cur = first_action; @@ -207,7 +239,9 @@ static int authenticate(struct mansession *s, struct message *m) char *pass = astman_get_header(m, "Secret"); char *authtype = astman_get_header(m, "AuthType"); char *key = astman_get_header(m, "Key"); - + char *events = astman_get_header(m, "Events"); + int send_events = events ? ast_true(events) : 1; + cfg = ast_load("manager.conf"); if (!cfg) return -1; @@ -272,6 +306,7 @@ static int authenticate(struct mansession *s, struct message *m) s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read")); s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write")); ast_destroy(cfg); + s->send_events=send_events; return 0; } ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user); @@ -285,6 +320,35 @@ static int action_ping(struct mansession *s, struct message *m) return 0; } + +static int events_on_off(struct mansession *s,int onoff) { + ast_mutex_lock(&s->lock); + s->send_events = onoff ? 1 : 0; + ast_mutex_unlock(&s->lock); + return s->send_events; +} + + +static int action_events(struct mansession *s, struct message *m) +{ + char *mask = astman_get_header(m, "EventMask"); + char reply[25]; + int res; + int true=0; + + /* ast_true might wanna learn to include 'on' as a true stmt */ + if(!strcasecmp(mask,"on")) + true = 1; + else + true = ast_true(mask); + + res = events_on_off(s,true); + sprintf(reply,"Events are now %s",res ? "on" : "off"); + astman_send_response(s, m,reply, NULL); + return 0; +} + + static int action_logoff(struct mansession *s, struct message *m) { astman_send_response(s, m, "Goodbye", "Thanks for all the fish."); @@ -753,11 +817,15 @@ static void *accept_thread(void *ignore) } memset(s, 0, sizeof(struct mansession)); memcpy(&s->sin, &sin, sizeof(sin)); - /* For safety, make sure socket is non-blocking */ - flags = fcntl(as, F_GETFL); - fcntl(as, F_SETFL, flags | O_NONBLOCK); + + 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); s->fd = as; + s->send_events = 1; ast_mutex_lock(&sessionlock); s->next = sessions; sessions = s; @@ -778,14 +846,16 @@ int manager_event(int category, char *event, char *fmt, ...) ast_mutex_lock(&sessionlock); s = sessions; while(s) { - if ((s->readperm & category) == category) { + 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); - write(s->fd, tmp, strlen(tmp)); + + ast_carefulwrite(s->fd,tmp,strlen(tmp),100); + /*write(s->fd, tmp, strlen(tmp));*/ ast_cli(s->fd, "\r\n"); } ast_mutex_unlock(&s->lock); @@ -871,6 +941,7 @@ int init_manager(void) if (!registered) { /* Register default actions */ ast_manager_register( "Ping", 0, action_ping, "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" ); @@ -898,6 +969,11 @@ int init_manager(void) if (val) enabled = ast_true(val); + val = ast_variable_retrieve(cfg, "general", "block-sockets"); + if(val) + block_sockets = ast_true(val); + + if ((val = ast_variable_retrieve(cfg, "general", "portno"))) { if (sscanf(val, "%d", &portno) != 1) { ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); @@ -915,7 +991,7 @@ int init_manager(void) memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); } } - + if ((asock > -1) && ((portno != oldportno) || !enabled)) { #if 0 /* Can't be done yet */