Allow semi-blocking fd's on manager (bug #1100)
authorMark Spencer <markster@digium.com>
Mon, 1 Mar 2004 21:12:32 +0000 (21:12 +0000)
committerMark Spencer <markster@digium.com>
Mon, 1 Mar 2004 21:12:32 +0000 (21:12 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2287 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/manager.h
manager.c

index ac3a2b2..26abd9d 100755 (executable)
@@ -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);
index ed285ec..ea73858 100755 (executable)
--- 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 */