From 78ffd99ab1dc524bbfe7e0896875cd390bdf99c0 Mon Sep 17 00:00:00 2001 From: Richard Stanway Date: Sun, 11 Aug 2024 20:43:41 +0200 Subject: [PATCH] happy-eyeballs: Move happy_eyeballs_destroy to a thread On Windows, shutdown() will not interrupt a blocking connect() call, so happy_eyeballs_destroy could block until the remaining candidates timed out. As happy_eyeballs_destroy is called in the RTMP connect path, this would stall the RTMP connection and cause the winning candidate's socket to be disconnected due to a timeout. --- shared/happy-eyeballs/happy-eyeballs.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/shared/happy-eyeballs/happy-eyeballs.c b/shared/happy-eyeballs/happy-eyeballs.c index 7877a9f99985d5..538226ce5dff1d 100644 --- a/shared/happy-eyeballs/happy-eyeballs.c +++ b/shared/happy-eyeballs/happy-eyeballs.c @@ -650,11 +650,11 @@ int happy_eyeballs_timedwait(struct happy_eyeballs_ctx *context, return status; } -int happy_eyeballs_destroy(struct happy_eyeballs_ctx *context) +static void *destroy_thread(void *param) { - if (context == NULL) - return STATUS_INVALID_ARGUMENT; + struct happy_eyeballs_ctx *context = param; + os_set_thread_name("happy-eyeballs destroy thread"); #ifdef _WIN32 #define SHUT_RDWR SD_BOTH #else @@ -698,6 +698,21 @@ int happy_eyeballs_destroy(struct happy_eyeballs_ctx *context) da_free(context->candidates); free(context); + + return NULL; +} + +int happy_eyeballs_destroy(struct happy_eyeballs_ctx *context) +{ + if (context == NULL) + return STATUS_INVALID_ARGUMENT; + + /* The destroy happens asynchronously in another thread due to the + * connect() call blocking on Windows. */ + pthread_t thread; + pthread_create(&thread, NULL, destroy_thread, context); + pthread_detach(thread); + return STATUS_SUCCESS; }