Properly exit

Properly exit based on the path taken to shutdown master.

Tested that shutting down through sigint or sigterm returns -1
Tested that a segfault exits the program properly
Need to test that players who are trying to connect while master is shutting down are not able to spawn more child worlds.
This commit is contained in:
EmosewaMC 2022-12-15 05:46:03 -08:00
parent 435761f64b
commit 1afe717563
7 changed files with 65 additions and 31 deletions

View File

@ -84,7 +84,7 @@ int main(int argc, char** argv) {
if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, Game::shouldShutdown); Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
//Run it until server gets a kill message from Master: //Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now();

View File

@ -104,7 +104,7 @@ int main(int argc, char** argv) {
if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, Game::shouldShutdown); Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));

View File

@ -150,7 +150,7 @@ void InstanceManager::RemoveInstance(Instance* instance) {
if (m_Instances[i] == instance) { if (m_Instances[i] == instance) {
instance->SetShutdownComplete(true); instance->SetShutdownComplete(true);
RedirectPendingRequests(instance); if (!Game::shouldShutdown) RedirectPendingRequests(instance);
delete m_Instances[i]; delete m_Instances[i];

View File

@ -52,13 +52,14 @@ namespace Game {
} //namespace Game } //namespace Game
bool shutdownSequenceStarted = false; bool shutdownSequenceStarted = false;
void ShutdownSequence(); void ShutdownSequence(int signal = -1);
int FinalizeShutdown(); int FinalizeShutdown(int signal = -1);
dLogger* SetupLogger(); dLogger* SetupLogger();
void StartAuthServer(); void StartAuthServer();
void StartChatServer(); void StartChatServer();
void HandlePacket(Packet* packet); void HandlePacket(Packet* packet);
std::map<uint32_t, std::string> activeSessions; std::map<uint32_t, std::string> activeSessions;
SystemAddress authServerMasterPeerSysAddr;
SystemAddress chatServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr;
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -71,9 +72,9 @@ int main(int argc, char** argv) {
#endif #endif
//Triggers the shutdown sequence at application exit //Triggers the shutdown sequence at application exit
std::atexit(ShutdownSequence); std::atexit([]() { ShutdownSequence(); });
signal(SIGINT, [](int) { ShutdownSequence(); }); signal(SIGINT, [](int signal) { ShutdownSequence(EXIT_FAILURE); });
signal(SIGTERM, [](int) { ShutdownSequence(); }); signal(SIGTERM, [](int signal) { ShutdownSequence(EXIT_FAILURE); });
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Game::logger = SetupLogger(); Game::logger = SetupLogger();
@ -216,7 +217,7 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port"));
Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, Game::shouldShutdown); Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::shouldShutdown);
//Query for the database for a server labeled "master" //Query for the database for a server labeled "master"
auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'");
@ -253,8 +254,8 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("prestart_servers") != "" && Game::config->GetValue("prestart_servers") == "1") { if (Game::config->GetValue("prestart_servers") != "" && Game::config->GetValue("prestart_servers") == "1") {
StartChatServer(); StartChatServer();
Game::im->GetInstance(0, false, 0)->SetIsReady(true); Game::im->GetInstance(0, false, 0);
Game::im->GetInstance(1000, false, 0)->SetIsReady(true); Game::im->GetInstance(1000, false, 0);
StartAuthServer(); StartAuthServer();
} }
@ -350,9 +351,7 @@ int main(int argc, char** argv) {
t += std::chrono::milliseconds(highFrameRate); t += std::chrono::milliseconds(highFrameRate);
std::this_thread::sleep_until(t); std::this_thread::sleep_until(t);
} }
FinalizeShutdown(); return FinalizeShutdown(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
} }
dLogger* SetupLogger() { dLogger* SetupLogger() {
@ -381,9 +380,15 @@ void HandlePacket(Packet* packet) {
Game::im->RemoveInstance(instance); //Delete the old Game::im->RemoveInstance(instance); //Delete the old
} }
if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { if (packet->systemAddress == chatServerMasterPeerSysAddr) {
chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS;
StartChatServer(); StartChatServer();
} }
if (packet->systemAddress == authServerMasterPeerSysAddr) {
authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS;
StartAuthServer();
}
} }
if (packet->data[0] == ID_CONNECTION_LOST) { if (packet->data[0] == ID_CONNECTION_LOST) {
@ -397,9 +402,15 @@ void HandlePacket(Packet* packet) {
//Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new
} }
if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { if (packet->systemAddress == chatServerMasterPeerSysAddr) {
chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS;
StartChatServer(); StartChatServer();
} }
if (packet->systemAddress == authServerMasterPeerSysAddr) {
authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS;
StartAuthServer();
}
} }
if (packet->data[1] == MASTER) { if (packet->data[1] == MASTER) {
@ -495,6 +506,14 @@ void HandlePacket(Packet* packet) {
chatServerMasterPeerSysAddr = copy; chatServerMasterPeerSysAddr = copy;
} }
if (theirServerType == ServerType::Auth) {
SystemAddress copy;
copy.binaryAddress = packet->systemAddress.binaryAddress;
copy.port = packet->systemAddress.port;
authServerMasterPeerSysAddr = copy;
}
Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i", theirInstanceID, theirPort); Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i", theirInstanceID, theirPort);
break; break;
@ -730,6 +749,10 @@ void HandlePacket(Packet* packet) {
} }
void StartChatServer() { void StartChatServer() {
if (Game::shouldShutdown) {
Game::logger->Log("MasterServer", "Currently shutting down. Chat will not be restarted.");
return;
}
#ifdef __APPLE__ #ifdef __APPLE__
//macOS doesn't need sudo to run on ports < 1024 //macOS doesn't need sudo to run on ports < 1024
system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
@ -745,6 +768,10 @@ void StartChatServer() {
} }
void StartAuthServer() { void StartAuthServer() {
if (Game::shouldShutdown) {
Game::logger->Log("MasterServer", "Currently shutting down. Auth will not be restarted.");
return;
}
#ifdef __APPLE__ #ifdef __APPLE__
system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
#elif _WIN32 #elif _WIN32
@ -758,12 +785,13 @@ void StartAuthServer() {
#endif #endif
} }
void ShutdownSequence() { void ShutdownSequence(int signal) {
if (shutdownSequenceStarted) { if (shutdownSequenceStarted) {
return; return;
} }
shutdownSequenceStarted = true; shutdownSequenceStarted = true;
Game::shouldShutdown = true;
{ {
CBITSTREAM; CBITSTREAM;
@ -782,7 +810,14 @@ void ShutdownSequence() {
auto ticks = 0; auto ticks = 0;
if (!Game::im) { if (!Game::im) {
exit(EXIT_SUCCESS); FinalizeShutdown(EXIT_FAILURE);
}
// A server might not be finished spinning up yet, remove all of those here.
for (auto instance : Game::im->GetInstances()) {
if (!instance->GetIsReady()) {
Game::im->RemoveInstance(instance);
}
} }
for (auto instance : Game::im->GetInstances()) { for (auto instance : Game::im->GetInstances()) {
@ -792,7 +827,6 @@ void ShutdownSequence() {
Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...");
while (true) { while (true) {
auto packet = Game::server->Receive(); auto packet = Game::server->Receive();
if (packet) { if (packet) {
HandlePacket(packet); HandlePacket(packet);
@ -812,7 +846,7 @@ void ShutdownSequence() {
} }
} }
if (done) { if (done && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) {
Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); Game::logger->Log("MasterServer", "Finished shutting down MasterServer!");
break; break;
} }
@ -828,10 +862,10 @@ void ShutdownSequence() {
} }
} }
FinalizeShutdown(); FinalizeShutdown(signal);
} }
int FinalizeShutdown() { int FinalizeShutdown(int signal) {
//Delete our objects here: //Delete our objects here:
Database::Destroy("MasterServer"); Database::Destroy("MasterServer");
if (Game::config) delete Game::config; if (Game::config) delete Game::config;
@ -839,6 +873,6 @@ int FinalizeShutdown() {
if (Game::server) delete Game::server; if (Game::server) delete Game::server;
if (Game::logger) delete Game::logger; if (Game::logger) delete Game::logger;
exit(EXIT_SUCCESS); if (signal != EXIT_SUCCESS) exit(signal);
return EXIT_SUCCESS; return signal;
} }

View File

@ -36,7 +36,7 @@ public:
} }
} ReceiveDownloadCompleteCB; } ReceiveDownloadCompleteCB;
dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool& shouldShutdown, unsigned int zoneID) { dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool* shouldShutdown, unsigned int zoneID) {
mIP = ip; mIP = ip;
mPort = port; mPort = port;
mZoneID = zoneID; mZoneID = zoneID;
@ -52,7 +52,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect
mReplicaManager = nullptr; mReplicaManager = nullptr;
mServerType = serverType; mServerType = serverType;
mConfig = config; mConfig = config;
mShouldShutdown = &shouldShutdown; mShouldShutdown = shouldShutdown;
//Attempt to start our server here: //Attempt to start our server here:
mIsOkay = Startup(); mIsOkay = Startup();

View File

@ -30,7 +30,7 @@ public:
int masterPort, int masterPort,
ServerType serverType, ServerType serverType,
dConfig* config, dConfig* config,
bool& shouldShutdown, bool* shouldShutdown,
unsigned int zoneID = 0); unsigned int zoneID = 0);
~dServer(); ~dServer();

View File

@ -208,7 +208,7 @@ int main(int argc, char** argv) {
LootGenerator::Instance(); LootGenerator::Instance();
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, Game::shouldShutdown, zoneID); Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID);
//Connect to the chat server: //Connect to the chat server:
int chatPort = 1501; int chatPort = 1501;