1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-21 00:19:29 +02:00

Fixed handling of match server crash

This commit is contained in:
Ivan Savenko
2024-02-04 19:56:04 +02:00
parent 7dee24edae
commit d4bedd8d8d
10 changed files with 69 additions and 81 deletions

View File

@ -144,6 +144,7 @@ CServerHandler::CServerHandler()
, applier(std::make_unique<CApplier<CBaseForLobbyApply>>())
, threadNetwork(&CServerHandler::threadRunNetwork, this)
, state(EClientState::NONE)
, serverPort(0)
, campaignStateToSend(nullptr)
, screenType(ESelectionScreen::unknown)
, serverMode(EServerMode::NONE)
@ -165,7 +166,7 @@ void CServerHandler::threadRunNetwork()
void CServerHandler::resetStateForLobby(EStartMode mode, ESelectionScreen screen, EServerMode newServerMode, const std::vector<std::string> & names)
{
hostClientId = -1;
state = EClientState::NONE;
setState(EClientState::NONE);
serverMode = newServerMode;
mapToStart = nullptr;
th = std::make_unique<CStopWatch>();
@ -263,7 +264,7 @@ void CServerHandler::startLocalServerAndConnect(bool connectToLobby)
void CServerHandler::connectToServer(const std::string & addr, const ui16 port)
{
logNetwork->info("Establishing connection to %s:%d...", addr, port);
state = EClientState::CONNECTING;
setState(EClientState::CONNECTING);
serverHostname = addr;
serverPort = port;
@ -281,7 +282,7 @@ void CServerHandler::connectToServer(const std::string & addr, const ui16 port)
void CServerHandler::onConnectionFailed(const std::string & errorMessage)
{
assert(state == EClientState::CONNECTING);
assert(getState() == EClientState::CONNECTING);
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
if (isServerLocal())
@ -293,7 +294,7 @@ void CServerHandler::onConnectionFailed(const std::string & errorMessage)
else
{
// remote server refused connection - show error message
state = EClientState::CONNECTION_FAILED;
setState(EClientState::NONE);
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.mainMenu.serverConnectionFailed"), {});
}
}
@ -302,7 +303,7 @@ void CServerHandler::onTimer()
{
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
if(state == EClientState::CONNECTION_CANCELLED)
if(getState() == EClientState::CONNECTION_CANCELLED)
{
logNetwork->info("Connection aborted by player!");
return;
@ -314,7 +315,7 @@ void CServerHandler::onTimer()
void CServerHandler::onConnectionEstablished(const NetworkConnectionPtr & netConnection)
{
assert(state == EClientState::CONNECTING);
assert(getState() == EClientState::CONNECTING);
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
@ -361,6 +362,16 @@ ui8 CServerHandler::myFirstId() const
return clientFirstId(c->connectionID);
}
EClientState CServerHandler::getState() const
{
return state;
}
void CServerHandler::setState(EClientState newState)
{
state = newState;
}
bool CServerHandler::isServerLocal() const
{
return threadRunLocalServer.joinable();
@ -418,13 +429,13 @@ void CServerHandler::sendClientConnecting() const
void CServerHandler::sendClientDisconnecting()
{
// FIXME: This is workaround needed to make sure client not trying to sent anything to non existed server
if(state == EClientState::DISCONNECTING)
if(getState() == EClientState::DISCONNECTING)
{
assert(0);
return;
}
state = EClientState::DISCONNECTING;
setState(EClientState::DISCONNECTING);
mapToStart = nullptr;
LobbyClientDisconnected lcd;
lcd.clientId = c->connectionID;
@ -439,13 +450,14 @@ void CServerHandler::sendClientDisconnecting()
logNetwork->info("Sent leaving signal to the server");
}
sendLobbyPack(lcd);
networkConnection->close();
networkConnection.reset();
c.reset();
}
void CServerHandler::setCampaignState(std::shared_ptr<CampaignState> newCampaign)
{
state = EClientState::LOBBY_CAMPAIGN;
setState(EClientState::LOBBY_CAMPAIGN);
LobbySetCampaign lsc;
lsc.ourCampaign = newCampaign;
sendLobbyPack(lsc);
@ -453,7 +465,7 @@ void CServerHandler::setCampaignState(std::shared_ptr<CampaignState> newCampaign
void CServerHandler::setCampaignMap(CampaignScenarioID mapId) const
{
if(state == EClientState::GAMEPLAY) // FIXME: UI shouldn't sent commands in first place
if(getState() == EClientState::GAMEPLAY) // FIXME: UI shouldn't sent commands in first place
return;
LobbySetCampaignMap lscm;
@ -463,7 +475,7 @@ void CServerHandler::setCampaignMap(CampaignScenarioID mapId) const
void CServerHandler::setCampaignBonus(int bonusId) const
{
if(state == EClientState::GAMEPLAY) // FIXME: UI shouldn't sent commands in first place
if(getState() == EClientState::GAMEPLAY) // FIXME: UI shouldn't sent commands in first place
return;
LobbySetCampaignBonus lscb;
@ -673,7 +685,7 @@ void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameSta
}
// After everything initialized we can accept CPackToClient netpacks
c->enterGameplayConnectionMode(client->gameState());
state = EClientState::GAMEPLAY;
setState(EClientState::GAMEPLAY);
}
void CServerHandler::endGameplay()
@ -780,7 +792,7 @@ int CServerHandler::howManyPlayerInterfaces()
ELoadMode CServerHandler::getLoadMode()
{
if(loadMode != ELoadMode::TUTORIAL && state == EClientState::GAMEPLAY)
if(loadMode != ELoadMode::TUTORIAL && getState() == EClientState::GAMEPLAY)
{
if(si->campState)
return ELoadMode::CAMPAIGN;
@ -874,7 +886,7 @@ void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection>
{
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
if(state == EClientState::DISCONNECTING)
if(getState() == EClientState::DISCONNECTING)
{
assert(0); //Should not be possible - socket must be closed at this point
return;
@ -887,7 +899,7 @@ void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection>
void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
{
if(state == EClientState::DISCONNECTING)
if(getState() == EClientState::DISCONNECTING)
{
assert(networkConnection == nullptr);
// Note: this branch can be reached on app shutdown, when main thread holds mutex till destruction
@ -898,18 +910,13 @@ void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> &
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
logNetwork->error("Lost connection to server! Connection has been closed");
networkConnection.reset();
if(client)
{
state = EClientState::DISCONNECTING;
GH.dispatchMainThread([]()
{
CSH->endGameplay();
GH.defActionsDef = 63;
CMM->menu->switchToTab("main");
});
CSH->endGameplay();
GH.defActionsDef = 63;
CMM->menu->switchToTab("main");
CSH->showServerError(CGI->generaltexth->translate("vcmi.server.errors.disconnected"));
}
else
{
@ -917,6 +924,8 @@ void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> &
lcd.clientId = c->connectionID;
applyPackOnLobbyScreen(lcd);
}
networkConnection.reset();
}
void CServerHandler::visitForLobby(CPackForLobby & lobbyPack)
@ -970,15 +979,13 @@ void CServerHandler::threadRunServer(bool connectToLobby)
}
else
{
if (state != EClientState::DISCONNECTING)
{
if (state == EClientState::CONNECTING)
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.server.errors.existingProcess"), {});
else
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.server.errors.serverCrashed"), {});
}
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
state = EClientState::CONNECTION_CANCELLED; // stop attempts to reconnect
if (getState() == EClientState::CONNECTING)
{
showServerError(CGI->generaltexth->translate("vcmi.server.errors.existingProcess"));
setState(EClientState::CONNECTION_CANCELLED); // stop attempts to reconnect
}
logNetwork->error("Error: server failed to close correctly or crashed!");
logNetwork->error("Check %s for more info", logName);
}
@ -987,6 +994,6 @@ void CServerHandler::threadRunServer(bool connectToLobby)
void CServerHandler::sendLobbyPack(const CPackForLobby & pack) const
{
if(state != EClientState::STARTING)
if(getState() != EClientState::STARTING)
c->sendPack(&pack);
}