Blame SOURCES/Fix-handling-of-non-EPOLLIN-EPOLLOUT-events.patch

c530df
From 8e9756f3cf0d03e5ca43f5212e3d4245ad1d9a00 Mon Sep 17 00:00:00 2001
c530df
From: Alexander Scheel <alexander.m.scheel@gmail.com>
c530df
Date: Thu, 14 Sep 2017 11:16:42 -0500
c530df
Subject: [PATCH] Fix handling of non-EPOLLIN/EPOLLOUT events
c530df
c530df
Signed-off-by: Alexander Scheel <alexander.m.scheel@gmail.com>
c530df
Reviewed-by: Robbie Harwood <rharwood@redhat.com>
c530df
Merges: #213
c530df
(cherry picked from commit b8f5b2f75612a11753cf742ee0477b98df8e6b02)
c530df
---
c530df
 proxy/src/client/gpm_common.c | 49 ++++++++++++++++++++++++++++++-------------
c530df
 1 file changed, 35 insertions(+), 14 deletions(-)
c530df
c530df
diff --git a/proxy/src/client/gpm_common.c b/proxy/src/client/gpm_common.c
c530df
index 7d1158e..b14e846 100644
c530df
--- a/proxy/src/client/gpm_common.c
c530df
+++ b/proxy/src/client/gpm_common.c
c530df
@@ -283,26 +283,47 @@ static int gpm_epoll_wait(struct gpm_ctx *gpmctx, uint32_t event_flags) {
c530df
         gpm_epoll_close(gpmctx);
c530df
     } else if (epoll_ret == 1 && events[0].data.fd == gpmctx->timerfd) {
c530df
         /* Got an event which is only our timer */
c530df
-        ret = read(gpmctx->timerfd, &timer_read, sizeof(uint64_t));
c530df
-        if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
c530df
-            /* In the case when reading from the timer failed, don't hide the
c530df
-             * timer error behind ETIMEDOUT such that it isn't retried */
c530df
-            ret = errno;
c530df
+        if ((events[0].events & EPOLLIN) == 0) {
c530df
+            /* We got an event which was not EPOLLIN; assume this is an error,
c530df
+             * and exit with EBADF: epoll_wait said timerfd had an event,
c530df
+             * but that event is not an EPOLIN event. */
c530df
+            ret = EBADF;
c530df
         } else {
c530df
-            /* If ret == 0, then we definitely timed out. Else, if ret == -1
c530df
-             * and errno == EAGAIN or errno == EWOULDBLOCK, we're in a weird
c530df
-             * edge case where epoll thinks the timer can be read, but it
c530df
-             * is blocking more; treat it like a TIMEOUT and retry, as
c530df
-             * nothing around us would handle EAGAIN from timer and retry
c530df
-             * it. */
c530df
-            ret = ETIMEDOUT;
c530df
+            ret = read(gpmctx->timerfd, &timer_read, sizeof(uint64_t));
c530df
+            if (ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
c530df
+                /* In the case when reading from the timer failed, don't hide the
c530df
+                 * timer error behind ETIMEDOUT such that it isn't retried */
c530df
+                ret = errno;
c530df
+            } else {
c530df
+                /* If ret == 0, then we definitely timed out. Else, if ret == -1
c530df
+                 * and errno == EAGAIN or errno == EWOULDBLOCK, we're in a weird
c530df
+                 * edge case where epoll thinks the timer can be read, but it
c530df
+                 * is blocking more; treat it like a TIMEOUT and retry, as
c530df
+                 * nothing around us would handle EAGAIN from timer and retry
c530df
+                 * it. */
c530df
+                ret = ETIMEDOUT;
c530df
+            }
c530df
         }
c530df
         gpm_epoll_close(gpmctx);
c530df
     } else {
c530df
         /* If ret == 2, then we ignore the timerfd; that way if the next
c530df
          * operation cannot be performed immediately, we timeout and retry.
c530df
-         * If ret == 1 and data.fd == gpmctx->fd, return 0. */
c530df
-        ret = 0;
c530df
+         * Always check the returned event of the socket fd. */
c530df
+        int fd_index = 0;
c530df
+        if (epoll_ret == 2 && events[fd_index].data.fd != gpmctx->fd) {
c530df
+            fd_index = 1;
c530df
+        }
c530df
+
c530df
+        if ((events[fd_index].events & event_flags) == 0) {
c530df
+            /* We cannot call EPOLLIN/EPOLLOUT at this time; assume that this
c530df
+             * is a fatal error; return with EBADFD to distinguish from
c530df
+             * EBADF in timer_fd case. */
c530df
+            ret = EBADFD;
c530df
+            gpm_epoll_close(gpmctx);
c530df
+        } else {
c530df
+            /* We definintely got a EPOLLIN/EPOLLOUT event; return success. */
c530df
+            ret = 0;
c530df
+        }
c530df
     }
c530df
 
c530df
     epoll_ret = epoll_ctl(gpmctx->epollfd, EPOLL_CTL_DEL, gpmctx->fd, NULL);