diff options
Diffstat (limited to 'main/channel_internal_api.c')
-rw-r--r-- | main/channel_internal_api.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 50f6c5da9..691dec0a1 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)); |