From: Neil Horman Date: Sun, 15 Dec 2024 20:26:41 +0000 (-0500) Subject: Do read retries in quic hq-interop server X-Git-Tag: openssl-3.5.0-alpha1~279 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a99c76d94cc4744f94cfbe16cb9e465f9bf35582;p=thirdparty%2Fopenssl.git Do read retries in quic hq-interop server Normally the throughput test in the interop harness requests several hundred very small files, resulting in lots of small stream packets from the client, which are nominally read in a single read operation (as they typically fit into a single stream frame), and the server was written to expect that. However, its still possible, if a stream frame is packed to the end of a datagram, that only part of its content is carried, finished in a subsequent stream packet, which leads to a short read. Augment the server to properly handle SSL_read transient failures so that such an occurance is handled properly. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/26198) --- diff --git a/demos/guide/quic-hq-interop-server.c b/demos/guide/quic-hq-interop-server.c index 226d9d10c2f..bea9c44438b 100644 --- a/demos/guide/quic-hq-interop-server.c +++ b/demos/guide/quic-hq-interop-server.c @@ -332,6 +332,72 @@ err: return NULL; } +/** + * @brief Handles I/O failures on an SSL stream based on the result code. + * + * This function processes the result of an SSL I/O operation and handles + * different types of errors that may occur during the operation. It takes + * appropriate actions such as retrying the operation, reporting errors, or + * returning specific status codes based on the error type. + * + * @param ssl A pointer to the SSL object representing the stream. + * @param res The result code from the SSL I/O operation. + * @return An integer indicating the outcome: + * - 0: EOF, indicating the stream has been closed. + * - -1: A fatal error occurred or the stream has been reset. + * + * + * @note If the failure is due to an SSL verification error, additional + * information will be logged to stderr. + */ +static int handle_io_failure(SSL *ssl, int res) +{ + switch (SSL_get_error(ssl, res)) { + case SSL_ERROR_ZERO_RETURN: + /* EOF */ + return 0; + + case SSL_ERROR_SYSCALL: + return -1; + + case SSL_ERROR_SSL: + /* + * Some stream fatal error occurred. This could be because of a + * stream reset - or some failure occurred on the underlying + * connection. + */ + switch (SSL_get_stream_read_state(ssl)) { + case SSL_STREAM_STATE_RESET_REMOTE: + fprintf(stderr, "Stream reset occurred\n"); + /* + * The stream has been reset but the connection is still + * healthy. + */ + break; + + case SSL_STREAM_STATE_CONN_CLOSED: + fprintf(stderr, "Connection closed\n"); + /* Connection is already closed. */ + break; + + default: + fprintf(stderr, "Unknown stream failure\n"); + break; + } + /* + * If the failure is due to a verification error we can get more + * information about it from SSL_get_verify_result(). + */ + if (SSL_get_verify_result(ssl) != X509_V_OK) + fprintf(stderr, "Verify error: %s\n", + X509_verify_cert_error_string(SSL_get_verify_result(ssl))); + return -1; + + default: + return -1; + } +} + /** * @brief Processes a new incoming QUIC stream for an HTTP/0.9 GET request. * @@ -375,10 +441,27 @@ static void process_new_stream(SSL *stream) size_t bytes_written = 0; size_t offset = 0; int rc; + int ret; + size_t total_read = 0; memset(buf, 0, BUF_SIZE); - if (SSL_read_ex(stream, buf, sizeof(buf) - 1, &nread) <= 0) - return; + for (;;) { + nread = 0; + ret = SSL_read_ex(stream, &buf[total_read], + sizeof(buf) - total_read - 1, &nread); + total_read += nread; + if (ret <= 0) { + ret = handle_io_failure(stream, ret); + if (ret == 0) { + /* EOF condition, fin bit set, we got the whole request */ + break; + } else { + /* permanent failure, abort */ + fprintf(stderr, "Failure on stream\n"); + return; + } + } + } /* We should have a valid http 0.9 GET request here */ fprintf(stderr, "Request is %s\n", req);