Fix race between network client disconnect and network window deletion

This commit is contained in:
Jonathan G Rennison
2022-06-22 19:23:20 +01:00
parent ccef4baea6
commit ff064e06b8
7 changed files with 25 additions and 7 deletions

View File

@@ -15,6 +15,7 @@
#include "../network_internal.h" #include "../network_internal.h"
#include "../../debug.h" #include "../../debug.h"
#include "../../error.h" #include "../../error.h"
#include "../../window_func.h"
#include "table/strings.h" #include "table/strings.h"
@@ -109,6 +110,7 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
if (!_network_server && _networking) { if (!_network_server && _networking) {
extern void ClientNetworkEmergencySave(); // from network_client.cpp extern void ClientNetworkEmergencySave(); // from network_client.cpp
ClientNetworkEmergencySave(); ClientNetworkEmergencySave();
DeleteNetworkClientWindows();
_switch_mode = SM_MENU; _switch_mode = SM_MENU;
_networking = false; _networking = false;
ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL); ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL);

View File

@@ -522,7 +522,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = {
static WindowDesc _chat_window_desc( static WindowDesc _chat_window_desc(
WDP_MANUAL, nullptr, 0, 0, WDP_MANUAL, nullptr, 0, 0,
WC_SEND_NETWORK_MSG, WC_NONE, WC_SEND_NETWORK_MSG, WC_NONE,
0, WDF_NETWORK,
_nested_chat_window_widgets, lengthof(_nested_chat_window_widgets) _nested_chat_window_widgets, lengthof(_nested_chat_window_widgets)
); );

View File

@@ -257,6 +257,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
ClientNetworkEmergencySave(); ClientNetworkEmergencySave();
} }
DeleteNetworkClientWindows();
_switch_mode = SM_MENU; _switch_mode = SM_MENU;
_networking = false; _networking = false;
} }

View File

@@ -1016,7 +1016,7 @@ static const NWidgetPart _nested_network_game_widgets[] = {
static WindowDesc _network_game_window_desc( static WindowDesc _network_game_window_desc(
WDP_CENTER, "list_servers", 1000, 730, WDP_CENTER, "list_servers", 1000, 730,
WC_NETWORK_WINDOW, WC_NONE, WC_NETWORK_WINDOW, WC_NONE,
0, WDF_NETWORK,
_nested_network_game_widgets, lengthof(_nested_network_game_widgets) _nested_network_game_widgets, lengthof(_nested_network_game_widgets)
); );
@@ -1289,7 +1289,7 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = {
static WindowDesc _network_start_server_window_desc( static WindowDesc _network_start_server_window_desc(
WDP_CENTER, nullptr, 0, 0, WDP_CENTER, nullptr, 0, 0,
WC_NETWORK_WINDOW, WC_NONE, WC_NETWORK_WINDOW, WC_NONE,
0, WDF_NETWORK,
_nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets) _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets)
); );
@@ -1366,7 +1366,7 @@ static const NWidgetPart _nested_client_list_widgets[] = {
static WindowDesc _client_list_desc( static WindowDesc _client_list_desc(
WDP_AUTO, "list_clients", 220, 300, WDP_AUTO, "list_clients", 220, 300,
WC_CLIENT_LIST, WC_NONE, WC_CLIENT_LIST, WC_NONE,
0, WDF_NETWORK,
_nested_client_list_widgets, lengthof(_nested_client_list_widgets) _nested_client_list_widgets, lengthof(_nested_client_list_widgets)
); );
@@ -2259,7 +2259,7 @@ static const NWidgetPart _nested_network_join_status_window_widgets[] = {
static WindowDesc _network_join_status_window_desc( static WindowDesc _network_join_status_window_desc(
WDP_CENTER, nullptr, 0, 0, WDP_CENTER, nullptr, 0, 0,
WC_NETWORK_STATUS_WINDOW, WC_NONE, WC_NETWORK_STATUS_WINDOW, WC_NONE,
WDF_MODAL, WDF_MODAL | WDF_NETWORK,
_nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets) _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets)
); );
@@ -2382,7 +2382,7 @@ static const NWidgetPart _nested_network_company_password_window_widgets[] = {
static WindowDesc _network_company_password_window_desc( static WindowDesc _network_company_password_window_desc(
WDP_AUTO, nullptr, 0, 0, WDP_AUTO, nullptr, 0, 0,
WC_COMPANY_PASSWORD_WINDOW, WC_NONE, WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
0, WDF_NETWORK,
_nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets) _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets)
); );
@@ -2484,7 +2484,7 @@ static const NWidgetPart _nested_network_ask_relay_widgets[] = {
static WindowDesc _network_ask_relay_desc( static WindowDesc _network_ask_relay_desc(
WDP_CENTER, nullptr, 0, 0, WDP_CENTER, nullptr, 0, 0,
WC_NETWORK_ASK_RELAY, WC_NONE, WC_NETWORK_ASK_RELAY, WC_NONE,
WDF_MODAL, WDF_MODAL | WDF_NETWORK,
_nested_network_ask_relay_widgets, lengthof(_nested_network_ask_relay_widgets) _nested_network_ask_relay_widgets, lengthof(_nested_network_ask_relay_widgets)
); );

View File

@@ -3510,6 +3510,19 @@ void DeleteConstructionWindows()
} }
} }
/**
* Delete all windows that use network client functionality.
*/
void DeleteNetworkClientWindows()
{
/* Note: the container remains stable, even when deleting windows. */
for (const Window *w : Window::IterateUnordered()) {
if (w->window_desc->flags & WDF_NETWORK) {
delete w;
}
}
}
/** Delete all always on-top windows to get an empty screen */ /** Delete all always on-top windows to get an empty screen */
void HideVitalWindows() void HideVitalWindows()
{ {

View File

@@ -40,6 +40,7 @@ void DeleteNonVitalWindows();
void DeleteAllNonVitalWindows(); void DeleteAllNonVitalWindows();
void DeleteAllMessages(); void DeleteAllMessages();
void DeleteConstructionWindows(); void DeleteConstructionWindows();
void DeleteNetworkClientWindows();
void HideVitalWindows(); void HideVitalWindows();
void ShowVitalWindows(); void ShowVitalWindows();

View File

@@ -229,6 +229,7 @@ enum WindowDefaultFlag {
WDF_CONSTRUCTION = 1 << 0, ///< This window is used for construction; close it whenever changing company. WDF_CONSTRUCTION = 1 << 0, ///< This window is used for construction; close it whenever changing company.
WDF_MODAL = 1 << 1, ///< The window is a modal child of some other window, meaning the parent is 'inactive' WDF_MODAL = 1 << 1, ///< The window is a modal child of some other window, meaning the parent is 'inactive'
WDF_NO_FOCUS = 1 << 2, ///< This window won't get focus/make any other window lose focus when click WDF_NO_FOCUS = 1 << 2, ///< This window won't get focus/make any other window lose focus when click
WDF_NETWORK = 1 << 3, ///< This window is used for network client functionality
}; };
/** /**