From: Martin Willi Date: Fri, 28 Nov 2014 11:36:10 +0000 (+0100) Subject: watcher: Proper handle poll() POLLHUP/NVAL signaling X-Git-Tag: 5.2.2dr1~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=015fb3134db41ca9901ec5c895b15f5a37590ddc;p=thirdparty%2Fstrongswan.git watcher: Proper handle poll() POLLHUP/NVAL signaling poll() may return POLLHUP or POLLNVAL for given file descriptors. To handle these properly, we signal them to the EXCEPT watcher state, if registered. If not, we call the read/write callbacks, so they can properly fail when trying to read from or write to the file descriptor. --- diff --git a/src/libstrongswan/processing/watcher.c b/src/libstrongswan/processing/watcher.c index 9eaa3f142b..5b94208bfb 100644 --- a/src/libstrongswan/processing/watcher.c +++ b/src/libstrongswan/processing/watcher.c @@ -254,6 +254,26 @@ static int find_revents(struct pollfd *pfd, int count, int fd) return 0; } +/** + * Check if entry is waiting for a specific event, and if it got signaled + */ +static bool entry_ready(entry_t *entry, watcher_event_t event, int revents) +{ + if (entry->events & event) + { + switch (event) + { + case WATCHER_READ: + return (revents & (POLLIN | POLLHUP | POLLNVAL)) != 0; + case WATCHER_WRITE: + return (revents & (POLLOUT | POLLHUP | POLLNVAL)) != 0; + case WATCHER_EXCEPT: + return (revents & (POLLERR | POLLHUP | POLLNVAL)) != 0; + } + } + return FALSE; +} + /** * Dispatching function */ @@ -320,7 +340,7 @@ static job_requeue_t watch(private_watcher_t *this) ssize_t len; job_t *job; - DBG2(DBG_JOB, "watcher going to select()"); + DBG2(DBG_JOB, "watcher going to poll() %d fds", count); thread_cleanup_push((void*)activate_all, this); old = thread_cancelability(TRUE); @@ -360,21 +380,24 @@ static job_requeue_t watch(private_watcher_t *this) break; } revents = find_revents(pfd, count, entry->fd); - if ((revents & POLLIN) && (entry->events & WATCHER_READ)) - { - DBG2(DBG_JOB, "watched FD %d ready to read", entry->fd); - notify(this, entry, WATCHER_READ); - } - if ((revents & POLLOUT) && (entry->events & WATCHER_WRITE)) - { - DBG2(DBG_JOB, "watched FD %d ready to write", entry->fd); - notify(this, entry, WATCHER_WRITE); - } - if ((revents & POLLERR) && (entry->events & WATCHER_EXCEPT)) + if (entry_ready(entry, WATCHER_EXCEPT, revents)) { DBG2(DBG_JOB, "watched FD %d has exception", entry->fd); notify(this, entry, WATCHER_EXCEPT); } + else + { + if (entry_ready(entry, WATCHER_READ, revents)) + { + DBG2(DBG_JOB, "watched FD %d ready to read", entry->fd); + notify(this, entry, WATCHER_READ); + } + if (entry_ready(entry, WATCHER_WRITE, revents)) + { + DBG2(DBG_JOB, "watched FD %d ready to write", entry->fd); + notify(this, entry, WATCHER_WRITE); + } + } } enumerator->destroy(enumerator); this->mutex->unlock(this->mutex); @@ -394,7 +417,7 @@ static job_requeue_t watch(private_watcher_t *this) { if (!this->pending && errno != EINTR) { /* complain only if no pending updates */ - DBG1(DBG_JOB, "watcher select() error: %s", strerror(errno)); + DBG1(DBG_JOB, "watcher poll() error: %s", strerror(errno)); } return JOB_REQUEUE_DIRECT; }