summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorTerry Wilson <twilson@digium.com>2012-04-19 14:35:56 +0000
committerTerry Wilson <twilson@digium.com>2012-04-19 14:35:56 +0000
commit772ad8a641f281b81bfab9a118f6cfb1a3b4b4c4 (patch)
tree9123f888d75ba39fd80e43f663bea9abd30b3f03 /main
parentf78290068a078aa867d95f4d6cc7aa94d7c2c949 (diff)
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 ........ Merged revisions 362537 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@362538 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index 937259cda..539a37ee5 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1264,14 +1264,17 @@ static void *netconsole(void *vconsole)
{
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 @@ static void *netconsole(void *vconsole)
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;
}