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: