Commit 5d61a36a94 for openssl.org

commit 5d61a36a9425c7615f9b8510967db330ee5ed6fc
Author: MichaƂ Trojnara <Michal.Trojnara@stunnel.org>
Date:   Sat Jun 27 22:39:44 2026 +0200

    s_client: skip TCP shutdown drain for datagram protocols

    The shutdown-side drain uses a TCP half-close and a fixed 500 ms
    select() timeout to let peers consume buffered alerts before close.
    Running it for DTLS/QUIC datagram connections causes an unnecessary
    delay after the connection has otherwise completed.

    Limit this workaround to non-DTLS, non-QUIC connections.

    CLA: trivial

    Reviewed-by: Matt Caswell <matt@openssl.foundation>
    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    MergeDate: Wed Jul  1 13:35:53 2026
    (Merged from https://github.com/openssl/openssl/pull/31558)

diff --git a/apps/s_client.c b/apps/s_client.c
index 2d1f61a179..d247cd836d 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -3520,29 +3520,32 @@ shut:
         print_stuff(bio_c_out, con, full_log);
     do_ssl_shutdown(con);

-    /*
-     * If we ended with an alert being sent, but still with data in the
-     * network buffer to be read, then calling BIO_closesocket() will
-     * result in a TCP-RST being sent. On some platforms (notably
-     * Windows) then this will result in the peer immediately abandoning
-     * the connection including any buffered alert data before it has
-     * had a chance to be read. Shutting down the sending side first,
-     * and then closing the socket sends TCP-FIN first followed by
-     * TCP-RST. This seems to allow the peer to read the alert data.
-     */
-    shutdown(SSL_get_fd(con), 1); /* SHUT_WR */
-    /*
-     * We just said we have nothing else to say, but it doesn't mean that
-     * the other side has nothing. It's even recommended to consume incoming
-     * data. [In testing context this ensures that alerts are passed on...]
-     */
-    timeout.tv_sec = 0;
-    timeout.tv_usec = 500000; /* some extreme round-trip */
-    do {
-        FD_ZERO(&readfds);
-        openssl_fdset(sock, &readfds);
-    } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0
-        && BIO_read(sbio, sbuf, BUFSIZZ) > 0);
+    /* The following half-close/drain workaround is TCP-specific. */
+    if (!isdtls && !isquic) {
+        /*
+         * If we ended with an alert being sent, but still with data in the
+         * network buffer to be read, then calling BIO_closesocket() will
+         * result in a TCP-RST being sent. On some platforms (notably
+         * Windows) then this will result in the peer immediately abandoning
+         * the connection including any buffered alert data before it has
+         * had a chance to be read. Shutting down the sending side first,
+         * and then closing the socket sends TCP-FIN first followed by
+         * TCP-RST. This seems to allow the peer to read the alert data.
+         */
+        shutdown(SSL_get_fd(con), 1); /* SHUT_WR */
+        /*
+         * We just said we have nothing else to say, but it doesn't mean that
+         * the other side has nothing. It's even recommended to consume incoming
+         * data. [In testing context this ensures that alerts are passed on...]
+         */
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 500000; /* some extreme round-trip */
+        do {
+            FD_ZERO(&readfds);
+            openssl_fdset(sock, &readfds);
+        } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0
+            && BIO_read(sbio, sbuf, BUFSIZZ) > 0);
+    }

     BIO_closesocket(SSL_get_fd(con));
 end: