Commit 0b01ed76aa for ffmpeg

commit 0b01ed76aa6a64e95ec4b87297aaa374a72de34e
Author: Martin Storsjö <martin@martin.st>
Date:   Mon Sep 21 15:56:51 2026 +0300

    tls_openssl: Only do SSL_shutdown if the connection was healthy

    If SSL_connect or SSL_accept haven't completed, or if we've run
    into a fatal error, we aren't supposed to call this function.

    This should avoid accumulating errors in the OpenSSL thread
    specific error queues, when we clean up after an unsuccessful
    connection.

    The documentation for SSL_get_error,
    https://docs.openssl.org/3.4/man3/SSL_get_error/, explicitly says:

    > SSL_ERROR_SYSCALL
    >
    > [...] If this error occurs then no further I/O operations should
    > be performed on the connection and SSL_shutdown() must not be called.
    >
    > SSL_ERROR_SSL
    >
    > [...] If this error occurs then no further I/O operations should
    > be performed on the connection and SSL_shutdown() must not be called.

diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c
index f417953404..789dae48a0 100644
--- a/libavformat/tls_openssl.c
+++ b/libavformat/tls_openssl.c
@@ -425,6 +425,7 @@ typedef struct TLSContext {
     TLSShared tls_shared;
     SSL_CTX *ctx;
     SSL *ssl;
+    int do_shutdown;
     BIO_METHOD* url_bio_method;
     int io_err;
     char error_message[256];
@@ -483,11 +484,17 @@ static int print_ssl_error(URLContext *h, int ret)
 {
     TLSContext *c = h->priv_data;
     int printed = 0, e, averr = AVERROR(EIO);
+    int err = SSL_get_error(c->ssl, ret);
     if (h->flags & AVIO_FLAG_NONBLOCK) {
-        int err = SSL_get_error(c->ssl, ret);
         if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
             return AVERROR(EAGAIN);
     }
+    switch (err) {
+    case SSL_ERROR_SSL:
+    case SSL_ERROR_SYSCALL:
+        c->do_shutdown = 0;
+        break;
+    }
     while ((e = ERR_get_error()) != 0) {
         av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(e, NULL));
         printed = 1;
@@ -507,7 +514,8 @@ static int tls_close(URLContext *h)
 {
     TLSContext *c = h->priv_data;
     if (c->ssl) {
-        SSL_shutdown(c->ssl);
+        if (c->do_shutdown)
+            SSL_shutdown(c->ssl);
         SSL_free(c->ssl);
     }
     if (c->ctx)
@@ -653,6 +661,7 @@ static int dtls_handshake(URLContext *h)
         ret = SSL_do_handshake(c->ssl);
         if (ret == 1) {
             av_log(c, AV_LOG_TRACE, "Handshake success\n");
+            c->do_shutdown = 1;
             break;
         }
         err = SSL_get_error(c->ssl, ret);
@@ -918,6 +927,7 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
             ret = print_ssl_error(h, ret);
             goto fail;
         }
+        c->do_shutdown = 1;
     }

     return 0;