MESSAGE: Flush Message/ast_msg_queue channel alert pipe.
authorRichard Mudgett <rmudgett@digium.com>
Tue, 13 Dec 2016 00:38:42 +0000 (18:38 -0600)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 14 Dec 2016 17:38:06 +0000 (11:38 -0600)
ASTERISK-25083

Change-Id: Id54baa57a8dbca84e29f28bcd2ffc0a5ac12d8b2

include/asterisk/channel.h
main/channel_internal_api.c
main/message.c

index 6f22027..1b7246b 100644 (file)
@@ -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);
index 50f6c5d..691dec0 100644 (file)
@@ -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));
index a326fb9..a6b0488 100644 (file)
@@ -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);
 }