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