Skip to content

Commit 1989340

Browse files
authored
Merge pull request #487 from GeneralsOnlineDevelopmentTeam/seer/bugfix/websocket-shutdown-cleanup
bugfix(websocket): Prevent double-shutdown and ensure proper libcurl resource cleanup
2 parents c599731 + 3b995e0 commit 1989340

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/OnlineServices_Init.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,17 +1067,42 @@ std::string NGMP_OnlineServicesManager::GetPatcherDirectoryPath()
10671067

10681068
void WebSocket::Shutdown()
10691069
{
1070+
// Return immediately if already shut down to prevent double-shutdown
1071+
// (e.g., NGMP_OnlineServicesManager::Shutdown() calls this before releasing the shared_ptr,
1072+
// and then the shared_ptr destructor also calls Shutdown() via ~WebSocket())
1073+
if (m_bShuttingDown)
1074+
{
1075+
return;
1076+
}
1077+
10701078
NetworkLog(ELogVerbosity::LOG_RELEASE, "[WebSocket] Shutdown initiated");
10711079

10721080
// Signal that we're shutting down
10731081
m_bShuttingDown = true;
10741082

1075-
// Disconnect from the websocket
1083+
// Disconnect from the websocket (handles the connected case)
10761084
Disconnect();
10771085

1078-
// Free headers
1086+
// Clean up curl easy handle if still active (e.g., mid-connection, not yet fully connected)
1087+
// Disconnect() returns early when m_bConnected is false, so m_pCurlWS may still be alive here
1088+
if (m_pCurlWS != nullptr)
1089+
{
1090+
if (m_pMulti != nullptr)
1091+
{
1092+
curl_multi_remove_handle(m_pMulti, m_pCurlWS);
1093+
}
1094+
curl_easy_cleanup(m_pCurlWS);
1095+
m_pCurlWS = nullptr;
1096+
}
10791097

1098+
// Clean up multi handle
1099+
if (m_pMulti != nullptr)
1100+
{
1101+
curl_multi_cleanup(m_pMulti);
1102+
m_pMulti = nullptr;
1103+
}
10801104

1105+
// Free headers (may already be freed by Disconnect, but check anyway)
10811106
if (m_pHeaders != nullptr)
10821107
{
10831108
curl_slist_free_all(m_pHeaders);

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/OnlineServices_RoomsInterface.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ WebSocket::WebSocket()
1717
WebSocket::~WebSocket()
1818
{
1919
Shutdown();
20+
// Only call Shutdown if it has not been initiated already.
21+
// NGMP_OnlineServicesManager::Shutdown() calls Shutdown() before releasing the shared_ptr,
22+
// so calling it again from the destructor would redundantly block for another 100ms sleep
23+
// and attempt to free already-released curl resources.
24+
if (!m_bShuttingDown)
25+
{
26+
Shutdown();
27+
}
28+
29+
30+
2031

2132
if (m_pHeaders != nullptr)
2233
{
@@ -196,6 +207,14 @@ void WebSocket::Disconnect()
196207
curl_slist_free_all(m_pHeaders);
197208
m_pHeaders = nullptr;
198209
}
210+
211+
212+
// Remove from multi handle before cleanup (required by libcurl)
213+
if (m_pMulti != nullptr)
214+
{
215+
curl_multi_remove_handle(m_pMulti, m_pCurlWS);
216+
}
217+
199218

200219
// cleanup
201220
curl_easy_cleanup(m_pCurlWS);
@@ -1424,4 +1443,5 @@ void NGMP_OnlineServices_RoomsInterface::OnRosterUpdated(std::unordered_map<uint
14241443
m_RosterNeedsRefreshCallback();
14251444
}
14261445
}
1446+
14271447

0 commit comments

Comments
 (0)