mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-10-26 22:20:59 +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_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_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() */
|
||||
|
||||
@ -330,9 +330,11 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
|
||||
goto read0;
|
||||
}
|
||||
|
||||
if (!(fdtab[conn->handle.fd].state & FD_LINGER_RISK) ||
|
||||
(cur_poller.flags & HAP_POLL_F_RDHUP)) {
|
||||
break;
|
||||
if (!(flags & CO_RFL_TRY_HARDER)) {
|
||||
if (!(fdtab[conn->handle.fd].state & FD_LINGER_RISK) ||
|
||||
(cur_poller.flags & HAP_POLL_F_RDHUP)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
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:
|
||||
return done;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user