Skip to content

Commit

Permalink
C4CurlSystem: Unset CURLMOPT_SOCKETFUNCTION and CURLMOPT_TIMERFUNCTIO…
Browse files Browse the repository at this point in the history
…N 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.
  • Loading branch information
Fulgen301 committed Nov 14, 2024
1 parent 746a906 commit 2d95715
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
37 changes: 30 additions & 7 deletions src/C4CurlSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand Down Expand Up @@ -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)
{
Expand All @@ -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();
}

Expand Down
20 changes: 19 additions & 1 deletion src/C4CurlSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Awaiter>
{
public:
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 2d95715

Please sign in to comment.