There are two ways we can tell one of our sockets has received a FIN. We
can either see an EPOLLRDHUP epoll event, or we can get a zero-length read
(EOF) on the socket. We currently use both, in a mildly confusing way:
we only set the FIN_RCVD() flag based on the EPOLLRDHUP event, but then
some other close out logic is based on seeing an EOF.
Simplify this by setting the flag based on only the EOF. To make sure we
don't miss an event if we get an EPOLLRDHUP with no data, we trigger the
forwarding path for EPOLLRDHUP as well as EPOLLIN.
Signed-off-by: David Gibson
---
tcp_splice.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/tcp_splice.c b/tcp_splice.c
index 8fbd490f..b45f0060 100644
--- a/tcp_splice.c
+++ b/tcp_splice.c
@@ -487,7 +487,6 @@ static int tcp_splice_forward(struct ctx *c, struct
uint8_t lowat_set_flag = RCVLOWAT_SET(fromsidei);
uint8_t lowat_act_flag = RCVLOWAT_ACT(fromsidei);
int never_read = 1;
- int eof = 0;
while (1) {
ssize_t readlen, written;
@@ -510,7 +509,7 @@ retry:
flow_trace(conn, "%zi from read-side call", readlen);
if (!readlen) {
- eof = 1;
+ conn_event(conn, FIN_RCVD(fromsidei));
} else if (readlen > 0) {
never_read = 0;
@@ -579,11 +578,12 @@ retry:
written < conn->pending[fromsidei])
goto retry;
- if (eof)
+ if (conn->events & FIN_RCVD(fromsidei))
break;
}
- if (!conn->pending[fromsidei] && eof) {
+ if (!conn->pending[fromsidei] &&
+ conn->events & FIN_RCVD(fromsidei)) {
unsigned sidei;
flow_foreach_sidei(sidei) {
@@ -643,17 +643,13 @@ void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref,
goto reset;
}
- if (events & EPOLLRDHUP)
- /* For side 0 this is fake, but implied */
- conn_event(conn, FIN_RCVD(evsidei));
-
if (events & EPOLLOUT) {
if (tcp_splice_forward(c, conn, !evsidei))
goto reset;
conn_event(conn, ~OUT_WAIT(evsidei));
}
- if (events & EPOLLIN) {
+ if (events & (EPOLLIN | EPOLLRDHUP)) {
if (tcp_splice_forward(c, conn, evsidei))
goto reset;
}
--
2.54.0