aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2014-11-28 12:36:10 +0100
committerMartin Willi <martin@revosec.ch>2014-11-28 12:50:34 +0100
commit015fb3134db41ca9901ec5c895b15f5a37590ddc (patch)
treed6567345e1796db903d3d3dcce2b2abc84a0b8d9 /src
parent02fd29acc14630a553ec67f008865859e30859e9 (diff)
downloadstrongswan-015fb3134db41ca9901ec5c895b15f5a37590ddc.tar.bz2
strongswan-015fb3134db41ca9901ec5c895b15f5a37590ddc.tar.xz
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.
Diffstat (limited to 'src')
-rw-r--r--src/libstrongswan/processing/watcher.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/src/libstrongswan/processing/watcher.c b/src/libstrongswan/processing/watcher.c
index 9eaa3f142..5b94208bf 100644
--- a/src/libstrongswan/processing/watcher.c
+++ b/src/libstrongswan/processing/watcher.c
@@ -255,6 +255,26 @@ static int find_revents(struct pollfd *pfd, int count, int fd)
}
/**
+ * 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
*/
static job_requeue_t watch(private_watcher_t *this)
@@ -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;
}