[Asterisk-cvs] asterisk db.c,1.22,1.23 manager.c,1.113,1.114

markster markster
Wed Sep 28 19:13:36 CDT 2005


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);




More information about the svn-commits mailing list