mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-10-27 14:41:28 +01:00
MINOR: rawsock: introduce CO_RFL_TRY_HARDER to detect closures on complete reads
Normally, when reading a full buffer, or exactly the requested size, it is not really possible to know if the peer had closed immediately after, and usually we don't care. There's a problematic case, though, which is with SSL: the SSL layer reads in small chunks of a few bytes, and can consume a client_hello this way, then start computation without knowing yet that the client has aborted. In order to permit knowing more, we now introduce a new read flag, CO_RFL_TRY_HARDER, which says that if we've read up to the permitted limit and the flag is set, then we attempt one extra byte using MSG_PEEK to detect whether the connection was closed immediately after that content or not. The first use case will obviously be related to SSL and client_hello, but it might possibly also make sense on HTTP responses to detect a pending FIN at the end of a response (e.g. if a close was already advertised).
This commit is contained in:
parent
dae4cfe8c5
commit
1afaa7b59d
@ -329,6 +329,7 @@ enum {
|
|||||||
CO_RFL_KEEP_RECV = 0x0008, /* Instruct the mux to still wait for read events */
|
CO_RFL_KEEP_RECV = 0x0008, /* Instruct the mux to still wait for read events */
|
||||||
CO_RFL_BUF_NOT_STUCK = 0x0010, /* Buffer is not stuck. Optims are possible during data copy */
|
CO_RFL_BUF_NOT_STUCK = 0x0010, /* Buffer is not stuck. Optims are possible during data copy */
|
||||||
CO_RFL_MAY_SPLICE = 0x0020, /* The producer can use the kernel splicing */
|
CO_RFL_MAY_SPLICE = 0x0020, /* The producer can use the kernel splicing */
|
||||||
|
CO_RFL_TRY_HARDER = 0x0040, /* Try to read till READ0 even on short reads */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* flags that can be passed to xprt->snd_buf() and mux->snd_buf() */
|
/* flags that can be passed to xprt->snd_buf() and mux->snd_buf() */
|
||||||
|
|||||||
@ -330,9 +330,11 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
|
|||||||
goto read0;
|
goto read0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(fdtab[conn->handle.fd].state & FD_LINGER_RISK) ||
|
if (!(flags & CO_RFL_TRY_HARDER)) {
|
||||||
(cur_poller.flags & HAP_POLL_F_RDHUP)) {
|
if (!(fdtab[conn->handle.fd].state & FD_LINGER_RISK) ||
|
||||||
break;
|
(cur_poller.flags & HAP_POLL_F_RDHUP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count -= ret;
|
count -= ret;
|
||||||
@ -360,6 +362,31 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
|
|||||||
if (unlikely(conn->flags & CO_FL_WAIT_L4_CONN) && done)
|
if (unlikely(conn->flags & CO_FL_WAIT_L4_CONN) && done)
|
||||||
conn->flags &= ~CO_FL_WAIT_L4_CONN;
|
conn->flags &= ~CO_FL_WAIT_L4_CONN;
|
||||||
|
|
||||||
|
if (unlikely((flags & CO_RFL_TRY_HARDER) &&
|
||||||
|
!(conn->flags & CO_FL_SOCK_RD_SH) &&
|
||||||
|
!count)) {
|
||||||
|
/* we've read exactly what was being asked for, which is loewr
|
||||||
|
* than a full buffer, and the caller wants us to really check
|
||||||
|
* if there's something after. This happens in the context of
|
||||||
|
* SSL where the lib reads in tiny chunks without offering the
|
||||||
|
* ability to detect a pending close. Let's just check using
|
||||||
|
* MSG_PEEK so that we don't pull bytes we shouldn't.
|
||||||
|
*/
|
||||||
|
char c;
|
||||||
|
|
||||||
|
ret = recv(conn->handle.fd, &c, 1, MSG_PEEK);
|
||||||
|
if (ret == 0) {
|
||||||
|
conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_shutr);
|
||||||
|
goto read0;
|
||||||
|
}
|
||||||
|
else if (ret < 0 &&
|
||||||
|
(errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOTCONN && errno != EINTR)) {
|
||||||
|
conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
|
||||||
|
conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
|
||||||
|
conn_set_errno(conn, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
return done;
|
return done;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user