summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium42 <rubidium@openttd.org>2021-05-01 14:41:25 +0200
committerrubidium42 <rubidium42@users.noreply.github.com>2021-05-01 18:30:08 +0200
commit05394d5216f89c9a7e14487b571515e510828657 (patch)
tree5b776de934917aeb88b09486fc1309a22467a6bf
parent83985fe26f1ad87df709f122f74e5d50485095fa (diff)
downloadopenttd-05394d5216f89c9a7e14487b571515e510828657.tar.xz
Fix #6598: Prevent invalid memory accesses when abandoning a join from within a network game
One could join a network game from within an already running network game. This would call a NetworkDisconnect, but keeps the UI alive. If, during that process the join is aborted, e.g. by cancelling on a password dialog, you would still be in your network game but also get shown the server list. Solve all the underlying problems by falling back to the main UI when (re)connecting to a(nother) server.
-rw-r--r--src/network/network.cpp28
-rw-r--r--src/network/network_client.h1
-rw-r--r--src/network/network_func.h1
-rw-r--r--src/openttd.cpp5
-rw-r--r--src/openttd.h1
5 files changed, 32 insertions, 4 deletions
diff --git a/src/network/network.cpp b/src/network/network.cpp
index 32fc4dec9..ce79f4c51 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -760,20 +760,40 @@ bool NetworkClientConnectGame(NetworkAddress &address, CompanyID join_as, const
if (!_network_available) return false;
if (!NetworkValidateClientName()) return false;
- strecpy(_settings_client.network.last_joined, address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined));
-
+ _network_join.address = address;
_network_join.company = join_as;
_network_join.server_password = join_server_password;
_network_join.company_password = join_company_password;
+ if (_game_mode == GM_MENU) {
+ /* From the menu we can immediately continue with the actual join. */
+ NetworkClientJoinGame();
+ } else {
+ /* When already playing a game, first go back to the main menu. This
+ * disconnects the user from the current game, meaning we can safely
+ * load in the new. After all, there is little point in continueing to
+ * play on a server if we are connecting to another one.
+ */
+ _switch_mode = SM_JOIN_GAME;
+ }
+ return true;
+}
+
+/**
+ * Actually perform the joining to the server. Use #NetworkClientConnectGame
+ * when you want to connect to a specific server/company. This function
+ * assumes _network_join is already fully set up.
+ */
+void NetworkClientJoinGame()
+{
NetworkDisconnect();
NetworkInitialize();
+ strecpy(_settings_client.network.last_joined, _network_join.address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined));
_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
ShowJoinStatusWindow();
- new TCPClientConnecter(address);
- return true;
+ new TCPClientConnecter(_network_join.address);
}
static void NetworkInitGameInfo()
diff --git a/src/network/network_client.h b/src/network/network_client.h
index 28d2d0021..81d5b720c 100644
--- a/src/network/network_client.h
+++ b/src/network/network_client.h
@@ -115,6 +115,7 @@ void NetworkClientSetCompanyPassword(const char *password);
/** Information required to join a server. */
struct NetworkJoinInfo {
NetworkJoinInfo() : company(COMPANY_SPECTATOR), server_password(nullptr), company_password(nullptr) {}
+ NetworkAddress address; ///< The address of the server to join.
CompanyID company; ///< The company to join.
const char *server_password; ///< The password of the server to join.
const char *company_password; ///< The password of the company to join.
diff --git a/src/network/network_func.h b/src/network/network_func.h
index 252d207db..5f3e27c12 100644
--- a/src/network/network_func.h
+++ b/src/network/network_func.h
@@ -52,6 +52,7 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
void NetworkUpdateClientInfo(ClientID client_id);
void NetworkClientsToSpectators(CompanyID cid);
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password = nullptr, const char *join_company_password = nullptr);
+void NetworkClientJoinGame();
void NetworkClientRequestMove(CompanyID company, const char *pass = "");
void NetworkClientSendRcon(const char *password, const char *command);
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0);
diff --git a/src/openttd.cpp b/src/openttd.cpp
index fbeeba793..234e3a419 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -1068,6 +1068,11 @@ void SwitchToMode(SwitchMode new_mode)
break;
}
+ case SM_JOIN_GAME: // Join a multiplayer game
+ LoadIntroGame();
+ NetworkClientJoinGame();
+ break;
+
case SM_MENU: // Switch to game intro menu
LoadIntroGame();
if (BaseSounds::ini_set.empty() && BaseSounds::GetUsedSet()->fallback && SoundDriver::GetInstance()->HasOutput()) {
diff --git a/src/openttd.h b/src/openttd.h
index 77fafab1d..2cd9cc1f0 100644
--- a/src/openttd.h
+++ b/src/openttd.h
@@ -36,6 +36,7 @@ enum SwitchMode {
SM_START_HEIGHTMAP, ///< Load a heightmap and start a new game from it.
SM_LOAD_HEIGHTMAP, ///< Load heightmap from scenario editor.
SM_RESTART_HEIGHTMAP, ///< Load a heightmap and start a new game from it with current settings.
+ SM_JOIN_GAME, ///< Join a network game.
};
/** Display Options */