From 44e72c9d44c37a29dda73abc7bdca1cb34252555 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 12 Dec 2016 18:38:42 -0600 Subject: [PATCH] MESSAGE: Flush Message/ast_msg_queue channel alert pipe. ASTERISK-25083 Change-Id: Id54baa57a8dbca84e29f28bcd2ffc0a5ac12d8b2 --- include/asterisk/channel.h | 1 + main/channel_internal_api.c | 62 ++++++++++++++++++++++++++++++++----- main/message.c | 9 ++++++ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 6f220271a5..1b7246b98b 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4229,6 +4229,7 @@ typedef enum { } ast_alert_status_t; int ast_channel_alert_write(struct ast_channel *chan); int ast_channel_alert_writable(struct ast_channel *chan); +ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan); ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan); int ast_channel_internal_alert_readable(struct ast_channel *chan); void ast_channel_internal_alertpipe_clear(struct ast_channel *chan); diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 50f6c5da99..691dec0a17 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -1239,14 +1239,9 @@ int ast_channel_alert_write(struct ast_channel *chan) return write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah); } -ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) +static int channel_internal_alert_check_nonblock(struct ast_channel *chan) { int flags; - char blah; - - if (!ast_channel_internal_alert_readable(chan)) { - return AST_ALERT_NOT_READABLE; - } flags = fcntl(chan->alertpipe[0], F_GETFL); /* For some odd reason, the alertpipe occasionally loses nonblocking status, @@ -1255,9 +1250,62 @@ ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", ast_channel_name(chan)); if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) { ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno)); - return AST_ALERT_READ_FATAL; + return -1; } } + return 0; +} + +ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan) +{ + int bytes_read; + char blah[100]; + + if (!ast_channel_internal_alert_readable(chan)) { + return AST_ALERT_NOT_READABLE; + } + if (channel_internal_alert_check_nonblock(chan)) { + return AST_ALERT_READ_FATAL; + } + + /* Read the alertpipe until it is exhausted. */ + for (;;) { + bytes_read = read(chan->alertpipe[0], blah, sizeof(blah)); + if (bytes_read < 0) { + if (errno == EINTR) { + continue; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* + * Would block so nothing left to read. + * This is the normal loop exit. + */ + break; + } + ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n", + strerror(errno)); + return AST_ALERT_READ_FAIL; + } + if (!bytes_read) { + /* Read nothing so we are done */ + break; + } + } + + return AST_ALERT_READ_SUCCESS; +} + +ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan) +{ + char blah; + + if (!ast_channel_internal_alert_readable(chan)) { + return AST_ALERT_NOT_READABLE; + } + if (channel_internal_alert_check_nonblock(chan)) { + return AST_ALERT_READ_FATAL; + } + if (read(chan->alertpipe[0], &blah, sizeof(blah)) < 0) { if (errno != EINTR && errno != EAGAIN) { ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno)); diff --git a/main/message.c b/main/message.c index a326fb97ea..a6b0488282 100644 --- a/main/message.c +++ b/main/message.c @@ -775,11 +775,20 @@ static void chan_cleanup(struct ast_channel *chan) if (msg_ds) { ast_channel_datastore_add(chan, msg_ds); } + /* * Clear softhangup flags. */ ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ALL); + /* + * Flush the alert pipe in case we miscounted somewhere when + * messing with frames on the read queue, we had to flush the + * read queue above, or we had an "Exceptionally long queue + * length" event. + */ + ast_channel_internal_alert_flush(chan); + ast_channel_unlock(chan); }