From 2d957156e78afb7524a3d03010f39c4460861689 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Thu, 14 Nov 2024 20:10:54 +0100 Subject: [PATCH] C4CurlSystem: Unset CURLMOPT_SOCKETFUNCTION and CURLMOPT_TIMERFUNCTION before calling curl_multi_cleanup curl_multi_cleanup may call the socket function with an internal easy handle, which will then attempt to insert that handle into the map. However, at that point the map has already been destroyed, as curl_multi_cleanup is called from the destructor of C4CurlSystem's multiHandle member. As we don't want to know about that extra handle at this stage anyway, we ensure that all user callbacks are reset to their default (nullptr) before curl_multi_cleanup is called. --- src/C4CurlSystem.cpp | 37 ++++++++++++++++++++++++++++++------- src/C4CurlSystem.h | 20 +++++++++++++++++++- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/C4CurlSystem.cpp b/src/C4CurlSystem.cpp index 6c1ff55de..525521c9e 100644 --- a/src/C4CurlSystem.cpp +++ b/src/C4CurlSystem.cpp @@ -84,6 +84,35 @@ C4CurlSystem::AddedEasyHandle::~AddedEasyHandle() } } +C4CurlSystem::MultiHandleWithCallbacks::MultiHandleWithCallbacks( + MultiHandle multiHandle, + C4CurlSystem &system, + SocketFunction *const socketFunction, + TimerFunction *const timerFunction) + : multiHandle{std::move(multiHandle)} +{ + if (this->multiHandle) + { + curl_multi_setopt(this->multiHandle.get(), CURLMOPT_SOCKETFUNCTION, socketFunction); + curl_multi_setopt(this->multiHandle.get(), CURLMOPT_SOCKETDATA, &system); + + curl_multi_setopt(this->multiHandle.get(), CURLMOPT_TIMERFUNCTION, timerFunction); + curl_multi_setopt(this->multiHandle.get(), CURLMOPT_TIMERDATA, &system); + } +} + +C4CurlSystem::MultiHandleWithCallbacks::~MultiHandleWithCallbacks() +{ + if (multiHandle) + { + curl_multi_setopt(multiHandle.get(), CURLMOPT_SOCKETFUNCTION, nullptr); + curl_multi_setopt(multiHandle.get(), CURLMOPT_SOCKETDATA, nullptr); + + curl_multi_setopt(multiHandle.get(), CURLMOPT_TIMERFUNCTION, nullptr); + curl_multi_setopt(multiHandle.get(), CURLMOPT_TIMERDATA, nullptr); + } +} + C4CurlSystem::Awaiter::Awaiter(C4CurlSystem &system, EasyHandle &&easyHandle) : system{system}, easyHandle{std::move(easyHandle)}, @@ -145,7 +174,7 @@ void C4CurlSystem::Awaiter::Resume() } C4CurlSystem::C4CurlSystem() - : multiHandle{curl_multi_init()} + : multiHandle{MultiHandle{curl_multi_init()}, *this, &C4CurlSystem::SocketFunction, &C4CurlSystem::TimerFunction} { if (!multiHandle) { @@ -154,12 +183,6 @@ C4CurlSystem::C4CurlSystem() throw CStdApp::StartupException{std::move(message)}; } - curl_multi_setopt(multiHandle.get(), CURLMOPT_SOCKETFUNCTION, &C4CurlSystem::SocketFunction); - curl_multi_setopt(multiHandle.get(), CURLMOPT_SOCKETDATA, this); - - curl_multi_setopt(multiHandle.get(), CURLMOPT_TIMERFUNCTION, &C4CurlSystem::TimerFunction); - curl_multi_setopt(multiHandle.get(), CURLMOPT_TIMERDATA, this); - multiTask = Execute(); } diff --git a/src/C4CurlSystem.h b/src/C4CurlSystem.h index 4378b34c5..f52412d0e 100644 --- a/src/C4CurlSystem.h +++ b/src/C4CurlSystem.h @@ -97,6 +97,24 @@ class C4CurlSystem ~GlobalInit(); }; + class MultiHandleWithCallbacks + { + public: + using SocketFunction = int(CURL *, curl_socket_t, int, void *) noexcept; + using TimerFunction = int(CURLM *, long, void *) noexcept; + + public: + MultiHandleWithCallbacks(MultiHandle multiHandle, C4CurlSystem &system, SocketFunction *socketFunction, TimerFunction *timerFunction); + ~MultiHandleWithCallbacks(); + + public: + auto get() const { return multiHandle.get(); } + explicit operator bool() const noexcept { return !!multiHandle; } + + private: + MultiHandle multiHandle; + }; + class Awaiter : public C4Task::CancellableAwaiter { public: @@ -171,7 +189,7 @@ class C4CurlSystem std::atomic_uint32_t timeout{StdSync::Infinite}; [[NO_UNIQUE_ADDRESS]] GlobalInit globalInit; - MultiHandle multiHandle; + MultiHandleWithCallbacks multiHandle; #ifdef _WIN32 CStdEvent event;