[svn-commits] twilson: branch 10 r362537 - in /branches/10: ./ main/asterisk.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Apr 19 09:32:06 CDT 2012


Author: twilson
Date: Thu Apr 19 09:31:59 2012
New Revision: 362537

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=362537
Log:
Handle multiple commands per connection via netconsole

Asterisk would accept multiple NULL-delimited CLI commands via the
netconsole socket, but would occasionally miss a command due to the
command not being completely read into the buffer. This patch ensures
that any partial commands get moved to the front of the read buffer,
appended to, and properly sent.

(closes issue ASTERISK-18308)
Review: https://reviewboard.asterisk.org/r/1876/
........

Merged revisions 362536 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    branches/10/   (props changed)
    branches/10/main/asterisk.c

Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: branches/10/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/asterisk.c?view=diff&rev=362537&r1=362536&r2=362537
==============================================================================
--- branches/10/main/asterisk.c (original)
+++ branches/10/main/asterisk.c Thu Apr 19 09:31:59 2012
@@ -1264,14 +1264,17 @@
 {
 	struct console *con = vconsole;
 	char hostname[MAXHOSTNAMELEN] = "";
-	char tmp[512];
+	char inbuf[512];
+	char outbuf[512];
+	const char *end_buf = inbuf + sizeof(inbuf);
+	char *start_read = inbuf;
 	int res;
 	struct pollfd fds[2];
-	
+
 	if (gethostname(hostname, sizeof(hostname)-1))
 		ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
-	snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
-	fdprint(con->fd, tmp);
+	snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
+	fdprint(con->fd, outbuf);
 	for (;;) {
 		fds[0].fd = con->fd;
 		fds[0].events = POLLIN;
@@ -1287,24 +1290,49 @@
 			continue;
 		}
 		if (fds[0].revents) {
-			res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
-			if (res < 1) {
+			int cmds_read, bytes_read;
+			if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
 				break;
 			}
-			tmp[res] = 0;
-			if (strncmp(tmp, "cli quit after ", 15) == 0) {
-				ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
+			/* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
+			if (strncmp(inbuf, "cli quit after ", 15) == 0) {
+				ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
 				break;
 			}
-			ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
+			/* ast_cli_command_multiple_full will only process individual commands terminated by a
+			 * NULL and not trailing partial commands. */
+			if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
+				/* No commands were read. We either have a short read on the first command
+				 * with space left, or a command that is too long */
+				if (start_read + bytes_read < end_buf) {
+					start_read += bytes_read;
+				} else {
+					ast_log(LOG_ERROR, "Command too long! Skipping\n");
+					start_read = inbuf;
+				}
+				continue;
+			}
+			if (start_read[bytes_read - 1] == '\0') {
+				/* The read ended on a command boundary, start reading again at the head of inbuf */
+				start_read = inbuf;
+				continue;
+			}
+			/* If we get this far, we have left over characters that have not been processed.
+			 * Advance to the character after the last command read by ast_cli_command_multiple_full.
+			 * We are guaranteed to have at least cmds_read NULLs */
+			while (cmds_read-- && (start_read = rawmemchr(start_read, '\0'))) {
+				start_read++;
+			}
+			memmove(inbuf, start_read, end_buf - start_read);
+			start_read = end_buf - start_read + inbuf;
 		}
 		if (fds[1].revents) {
-			res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
+			res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
 			if (res < 1) {
 				ast_log(LOG_ERROR, "read returned %d\n", res);
 				break;
 			}
-			res = write(con->fd, tmp, res);
+			res = write(con->fd, outbuf, res);
 			if (res < 1)
 				break;
 		}




More information about the svn-commits mailing list