Fix busy-wait on client SSL connection

Errors and EOF returned by 'recv' are now properly handled, isolated
from the return value ('r') from the later and conditional 'SSL_read'.

Previously, a busy loop was possible in the following scenario:

1. A client connection was closed, leading to a return of 0 by 'recv',
   and 'errno' to be set with 'EAGAIN'.
2. Error handling is performed taking into account a never performed
   call to 'SSL_read' (as if this '0' was a result for this call).
3. The call to 'SSL_get_error' returns with 'SSL_ERROR_SYSCALL', as a
   result of using this invalid param of '0' (which for 'SSL_read' would
   mean non-retryable error), and the non-reset 'errno' would still be
   'EAGAIN'.
4. This would create the illusion of an interrupted read. So a new read
   is tried again, while in reality the socket is closed. This busy loop
   will continue until 'POLLHUP' is received when we attempt to write
   back to the client and a 'RST' is received as a response.
v2.x-client_ssl_busy_wait
Javier Jaramago Fernández 2 years ago
parent 27e71d2972
commit ccfca5a3f9

@ -611,18 +611,15 @@ int MySQL_Data_Stream::read_from_net() {
return 0; // no enough space for reads
}
char buf[MY_SSL_BUFFER];
//ssize_t n = read(fd, buf, sizeof(buf));
int n = recv(fd, buf, sizeof(buf), 0);
//proxy_info("SSL recv of %d bytes\n", n);
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p: recv() read %d bytes. num_write: %lu , num_read: %lu\n", sess, n, rbio_ssl->num_write , rbio_ssl->num_read);
if (n > 0 || rbio_ssl->num_write > rbio_ssl->num_read) {
//on_read_cb(buf, (size_t)n);
int ssl_recv_bytes = recv(fd, buf, sizeof(buf), 0);
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p: recv() read %d bytes. num_write: %lu , num_read: %lu\n", sess, ssl_recv_bytes, rbio_ssl->num_write , rbio_ssl->num_read);
if (ssl_recv_bytes > 0 || rbio_ssl->num_write > rbio_ssl->num_read) {
char buf2[MY_SSL_BUFFER];
int n2;
enum sslstatus status;
char *src = buf;
int len = n;
int len = ssl_recv_bytes;
while (len > 0) {
n2 = BIO_write(rbio_ssl, src, len);
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p: write %d bytes into BIO %p, len=%d\n", sess, n2, rbio_ssl, len);
@ -681,9 +678,13 @@ int MySQL_Data_Stream::read_from_net() {
return -1;
}
} else {
r = n;
//r += SSL_read (ssl, queue_w_ptr(queueIN), s);
//proxy_info("Read %d bytes from SSL\n", r);
// Shutdown if we either received the EOF, or operation failed with non-retryable error.
if (ssl_recv_bytes==0 || (ssl_recv_bytes==-1 && errno != EINTR && errno != EAGAIN)) {
proxy_debug(PROXY_DEBUG_NET, 5, "Received EOF, shutting down soft socket -- Session=%p, Datastream=%p\n", sess, this);
shut_soft();
return -1;
}
r = ssl_recv_bytes;
}
}
//__exit_read_from_next:

Loading…
Cancel
Save