Update of /usr/cvsroot/asterisk
In directory mongoose.digium.com:/tmp/cvs-serv7993

Modified Files:
        db.c manager.c 
Log Message:
Remove possibility of manager deadlocks from manager actions


Index: db.c
===================================================================
RCS file: /usr/cvsroot/asterisk/db.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- db.c        14 Sep 2005 20:46:49 -0000      1.22
+++ db.c        28 Sep 2005 23:10:13 -0000      1.23
@@ -565,7 +565,6 @@
                astman_send_error(s, m, "Database entry not found");
        } else {
                astman_send_ack(s, m, "Result will follow");
-               ast_mutex_lock(&s->lock);
                ast_cli(s->fd, "Event: DBGetResponse\r\n"
                                "Family: %s\r\n"
                                "Key: %s\r\n"
@@ -573,7 +572,6 @@
                                "%s"
                                "\r\n",
                                family, key, tmp, idText);
-               ast_mutex_unlock(&s->lock);
        }
        return 0;
 }

Index: manager.c
===================================================================
RCS file: /usr/cvsroot/asterisk/manager.c,v
retrieving revision 1.113
retrieving revision 1.114
diff -u -d -r1.113 -r1.114
--- manager.c   25 Sep 2005 16:58:56 -0000      1.113
+++ manager.c   28 Sep 2005 23:10:13 -0000      1.114
@@ -255,6 +255,20 @@
        { { "show", "manager", "connected", NULL },
        handle_showmanconn, "Show connected manager interface users", 
showmanconn_help };
 
+static void free_session(struct mansession *s)
+{
+       struct eventqent *eqe;
+       if (s->fd > -1)
+               close(s->fd);
+       ast_mutex_destroy(&s->__lock);
+       while(s->eventq) {
+               eqe = s->eventq;
+               s->eventq = s->eventq->next;
+               free(eqe);
+       }
+       free(s);
+}
+
 static void destroy_session(struct mansession *s)
 {
        struct mansession *cur, *prev = NULL;
@@ -271,10 +285,7 @@
                        prev->next = cur->next;
                else
                        sessions = cur->next;
-               if (s->fd > -1)
-                       close(s->fd);
-               ast_mutex_destroy(&s->lock);
-               free(s);
+               free_session(s);
        } else
                ast_log(LOG_WARNING, "Trying to delete nonexistent session 
%p?\n", s);
        ast_mutex_unlock(&sessionlock);
@@ -323,18 +334,18 @@
 void astman_send_error(struct mansession *s, struct message *m, char *error)
 {
        char *id = astman_get_header(m,"ActionID");
-       ast_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->__lock);
        ast_cli(s->fd, "Response: Error\r\n");
        if (id && !ast_strlen_zero(id))
                ast_cli(s->fd, "ActionID: %s\r\n",id);
        ast_cli(s->fd, "Message: %s\r\n\r\n", error);
-       ast_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->__lock);
 }
 
 void astman_send_response(struct mansession *s, struct message *m, char *resp, 
char *msg)
 {
        char *id = astman_get_header(m,"ActionID");
-       ast_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->__lock);
        ast_cli(s->fd, "Response: %s\r\n", resp);
        if (id && !ast_strlen_zero(id))
                ast_cli(s->fd, "ActionID: %s\r\n",id);
@@ -342,7 +353,7 @@
                ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
        else
                ast_cli(s->fd, "\r\n");
-       ast_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->__lock);
 }
 
 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
@@ -440,10 +451,10 @@
 {
        int maskint = ast_strings_to_mask(eventmask);
 
-       ast_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->__lock);
        if (maskint >= 0)       
                s->send_events = maskint;
-       ast_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->__lock);
        
        return maskint;
 }
@@ -559,7 +570,6 @@
        if (id && !ast_strlen_zero(id))
                snprintf(idText,256,"ActionID: %s\r\n",id);
        ast_cli(s->fd, "Response: Success\r\n%s", idText);
-       ast_mutex_lock(&s->lock);
        ast_mutex_lock(&actionlock);
        while (cur) { /* Walk the list of actions */
                if ((s->writeperm & cur->authority) == cur->authority)
@@ -568,7 +578,6 @@
        }
        ast_mutex_unlock(&actionlock);
        ast_cli(s->fd, "\r\n");
-       ast_mutex_unlock(&s->lock);
 
        return 0;
 }
@@ -702,13 +711,11 @@
        if (!varval2)
                varval2 = "";
        ast_mutex_unlock(&c->lock);
-       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Response: Success\r\n"
                "Variable: %s\r\nValue: %s\r\n" ,varname,varval2);
        if (id && !ast_strlen_zero(id))
                ast_cli(s->fd, "ActionID: %s\r\n",id);
        ast_cli(s->fd, "\r\n");
-       ast_mutex_unlock(&s->lock);
 
        return 0;
 }
@@ -745,7 +752,6 @@
                        snprintf(bridge, sizeof(bridge), "Link: %s\r\n", 
c->_bridge->name);
                else
                        bridge[0] = '\0';
-               ast_mutex_lock(&s->lock);
                if (c->pbx) {
                        if (c->cdr) {
                                elapsed_seconds = now.tv_sec - 
c->cdr->start.tv_sec;
@@ -791,18 +797,15 @@
                        c->accountcode,
                        ast_state2str(c->_state), bridge, c->uniqueid, idText);
                }
-               ast_mutex_unlock(&s->lock);
                ast_mutex_unlock(&c->lock);
                if (!all)
                        break;
                c = ast_channel_walk_locked(c);
        }
-       ast_mutex_lock(&s->lock);
        ast_cli(s->fd,
        "Event: StatusComplete\r\n"
        "%s"
        "\r\n",idText);
-       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
@@ -878,18 +881,12 @@
 {
        char *cmd = astman_get_header(m, "Command");
        char *id = astman_get_header(m, "ActionID");
-       ast_mutex_lock(&s->lock);
-       s->blocking = 1;
-       ast_mutex_unlock(&s->lock);
        ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
        if (id && !ast_strlen_zero(id))
                ast_cli(s->fd, "ActionID: %s\r\n", id);
        /* FIXME: Wedge a ActionID response in here, waiting for later changes 
*/
        ast_cli_command(s->fd, cmd);
        ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
-       ast_mutex_lock(&s->lock);
-       s->blocking = 0;
-       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
@@ -1087,13 +1084,11 @@
         if (id && !ast_strlen_zero(id))
                 snprintf(idText,256,"ActionID: %s\r\n",id);
        ret = ast_app_has_voicemail(mailbox, NULL);
-       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Response: Success\r\n"
                                   "%s"
                                   "Message: Mailbox Status\r\n"
                                   "Mailbox: %s\r\n"
                                   "Waiting: %d\r\n\r\n", idText, mailbox, ret);
-       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
@@ -1119,10 +1114,9 @@
                return 0;
        }
        ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
-        if (id && !ast_strlen_zero(id)) {
-                snprintf(idText,256,"ActionID: %s\r\n",id);
-        }
-       ast_mutex_lock(&s->lock);
+       if (id && !ast_strlen_zero(id)) {
+               snprintf(idText,256,"ActionID: %s\r\n",id);
+       }
        ast_cli(s->fd, "Response: Success\r\n"
                                   "%s"
                                   "Message: Mailbox Message Count\r\n"
@@ -1131,7 +1125,6 @@
                                   "OldMessages: %d\r\n" 
                                   "\r\n",
                                    idText,mailbox, newmsgs, oldmsgs);
-       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
@@ -1165,7 +1158,6 @@
         if (id && !ast_strlen_zero(id)) {
                 snprintf(idText,256,"ActionID: %s\r\n",id);
         }
-       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Response: Success\r\n"
                                   "%s"
                                   "Message: Extension Status\r\n"
@@ -1174,7 +1166,6 @@
                                   "Hint: %s\r\n"
                                   "Status: %d\r\n\r\n",
                                   idText,exten, context, hint, status);
-       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
@@ -1233,16 +1224,16 @@
                        authtype = astman_get_header(m, "AuthType");
                        if (!strcasecmp(authtype, "MD5")) {
                                if (!s->challenge || 
ast_strlen_zero(s->challenge)) {
-                                       ast_mutex_lock(&s->lock);
+                                       ast_mutex_lock(&s->__lock);
                                        snprintf(s->challenge, 
sizeof(s->challenge), "%d", rand());
-                                       ast_mutex_unlock(&s->lock);
+                                       ast_mutex_unlock(&s->__lock);
                                }
-                               ast_mutex_lock(&s->lock);
+                               ast_mutex_lock(&s->__lock);
                                ast_cli(s->fd, "Response: Success\r\n"
                                                "%s"
                                                "Challenge: %s\r\n\r\n",
                                                idText,s->challenge);
-                               ast_mutex_unlock(&s->lock);
+                               ast_mutex_unlock(&s->__lock);
                                return 0;
                        } else {
                                astman_send_error(s, m, "Must specify 
AuthType");
@@ -1269,19 +1260,40 @@
                } else
                        astman_send_error(s, m, "Authentication Required");
        } else {
+               int ret=0;
+               struct eventqent *eqe;
+               ast_mutex_lock(&s->__lock);
+               s->busy = 1;
+               ast_mutex_unlock(&s->__lock);
                while( tmp ) {          
                        if (!strcasecmp(action, tmp->action)) {
                                if ((s->writeperm & tmp->authority) == 
tmp->authority) {
                                        if (tmp->func(s, m))
-                                               return -1;
+                                               ret = -1;
                                } else {
                                        astman_send_error(s, m, "Permission 
denied");
                                }
-                               return 0;
+                               break;
                        }
                        tmp = tmp->next;
                }
-               astman_send_error(s, m, "Invalid/unknown command");
+               ast_mutex_lock(&s->__lock);
+               s->busy = 0;
+               while(s->eventq) {
+                       if (ast_carefulwrite(s->fd, s->eventq->eventdata, 
strlen(s->eventq->eventdata), 100)) {
+                               ret = -1;
+                               break;
+                       }
+                       eqe = s->eventq;
+                       s->eventq = s->eventq->next;
+                       free(eqe);
+               }
+               ast_mutex_unlock(&s->__lock);
+               if (!ret)
+                       astman_send_error(s, m, "Invalid/unknown command");
+               else
+                       ret = 0;
+               return ret;
        }
        return 0;
 }
@@ -1319,9 +1331,9 @@
                        ast_log(LOG_WARNING, "Select returned error: %s\n", 
strerror(errno));
                        return -1;
                } else if (res > 0) {
-                       ast_mutex_lock(&s->lock);
+                       ast_mutex_lock(&s->__lock);
                        res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) 
- 1 - s->inlen);
-                       ast_mutex_unlock(&s->lock);
+                       ast_mutex_unlock(&s->__lock);
                        if (res < 1)
                                return -1;
                        break;
@@ -1339,9 +1351,9 @@
        char iabuf[INET_ADDRSTRLEN];
        int res;
        
-       ast_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->__lock);
        ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
-       ast_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->__lock);
        memset(&m, 0, sizeof(&m));
        for (;;) {
                res = get_input(s, m.headers[m.hdrcount]);
@@ -1416,7 +1428,7 @@
                        flags = fcntl(as, F_GETFL);
                        fcntl(as, F_SETFL, flags | O_NONBLOCK);
                }
-               ast_mutex_init(&s->lock);
+               ast_mutex_init(&s->__lock);
                s->fd = as;
                s->send_events = -1;
                ast_mutex_lock(&sessionlock);
@@ -1430,36 +1442,71 @@
        return NULL;
 }
 
+static int append_event(struct mansession *s, const char *str)
+{
+       struct eventqent *tmp, *prev=NULL;
+       tmp = malloc(sizeof(struct eventqent) + strlen(str));
+       if (tmp) {
+               tmp->next = NULL;
+               strcpy(tmp->eventdata, str);
+               if (s->eventq) {
+                       prev = s->eventq;
+                       while(prev->next) 
+                               prev = prev->next;
+                       prev->next = tmp;
+               } else {
+                       s->eventq = tmp;
+               }
+               return 0;
+       }
+       return -1;
+}
+
 /*--- manager_event: Send AMI event to client */
 int manager_event(int category, char *event, char *fmt, ...)
 {
        struct mansession *s;
        char tmp[4096];
        va_list ap;
+       struct mansession *next, *prev = NULL;
 
        ast_mutex_lock(&sessionlock);
        s = sessions;
        while(s) {
+               next = s->next;
                if (((s->readperm & category) == category) && ((s->send_events 
& category) == category) ) {
-                       ast_mutex_lock(&s->lock);
-                       if (!s->blocking) {
-                               ast_cli(s->fd, "Event: %s\r\n", event);
-                               ast_cli(s->fd, "Privilege: %s\r\n", 
authority_to_str(category, tmp, sizeof(tmp)));
-                               va_start(ap, fmt);
-                               vsnprintf(tmp, sizeof(tmp), fmt, ap);
-                               va_end(ap);
-                               ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
-                               ast_cli(s->fd, "\r\n");
+                       ast_mutex_lock(&s->__lock);
+                       ast_cli(s->fd, "Event: %s\r\n", event);
+                       ast_cli(s->fd, "Privilege: %s\r\n", 
authority_to_str(category, tmp, sizeof(tmp)));
+                       va_start(ap, fmt);
+                       vsnprintf(tmp, sizeof(tmp) - 3, fmt, ap);
+                       va_end(ap);
+                       strcat(tmp, "\r\n");
+                       if (s->busy) {
+                               append_event(s, tmp);
+                       } else if (ast_carefulwrite(s->fd,tmp,strlen(tmp),100) 
< 0) {
+                               ast_log(LOG_WARNING, "Disconnecting slow 
manager session!\n");
+                               /* Unlink from list */
+                               if (prev)
+                                       prev->next = next;
+                               else
+                                       sessions = next;
+                               ast_mutex_unlock(&s->__lock);
+                               free_session(s);
+                               s = next;
+                               continue;
                        }
-                       ast_mutex_unlock(&s->lock);
+                       ast_mutex_unlock(&s->__lock);
                }
-               s = s->next;
+               prev = s;
+               s = next;
        }
        ast_mutex_unlock(&sessionlock);
        return 0;
 }
 
-int ast_manager_unregister( char *action ) {
+int ast_manager_unregister( char *action ) 
+{
        struct manager_action *cur = first_action, *prev = first_action;
 
        ast_mutex_lock(&actionlock);

_______________________________________________
Asterisk-Cvs mailing list
[email protected]
http://lists.digium.com/mailman/listinfo/asterisk-cvs

Reply via email to