From ca8f0059a3a2e851c864a48e4d1e48b540eeabd2 Mon Sep 17 00:00:00 2001 From: Nexus Date: Tue, 14 Dec 2021 11:05:33 +0800 Subject: [PATCH] Add port recycling to instance creation Made instance creation use previously used ports when available, to prevent crashes caused by ports being used that are outside of the assigned range. --- dMasterServer/InstanceManager.cpp | 33 +++++++++++++++++++++++-------- dMasterServer/InstanceManager.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 218d21b6..41d34cfc 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -43,7 +43,8 @@ Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, L maxPlayers = GetHardCap(mapID); } - instance = new Instance(mExternalIP, ++m_LastPort, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers); + uint32_t port = GetFreePort(); + instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers); //Start the actual process: #ifdef _WIN32 @@ -59,7 +60,7 @@ Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, L cmd.append(std::to_string(mapID)); cmd.append(" -port "); - cmd.append(std::to_string(m_LastPort)); + cmd.append(std::to_string(port)); cmd.append(" -instance "); cmd.append(std::to_string(m_LastInstanceID)); cmd.append(" -maxclients "); @@ -74,8 +75,6 @@ Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, L system(cmd.c_str()); - m_LastPort++; //Increment it again because the next port is for World<->Server comm. - m_LastPort++; //Increment it again because the next port is for World<->Chat comm. m_Instances.push_back(instance); if (instance) { @@ -97,6 +96,25 @@ bool InstanceManager::IsPortInUse(uint32_t port) { return false; } +uint32_t InstanceManager::GetFreePort() { + uint32_t port = m_LastPort; + std::vector usedPorts; + for (Instance* i : m_Instances) { + usedPorts.push_back(i->GetPort()); + } + + std::sort(usedPorts.begin(), usedPorts.end()); + + int portIdx = 0; + while (portIdx < usedPorts.size() && port == usedPorts[portIdx]) { + //increment by 3 since each instance uses 3 ports (instance, world-server, world-chat) + port += 3; + portIdx++; + } + + return port; +} + void InstanceManager::AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID) { Instance* inst = FindInstance(mapID, instanceID); if (inst) { @@ -291,7 +309,8 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon int maxPlayers = 999; - instance = new Instance(mExternalIP, ++m_LastPort, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password); + uint32_t port = GetFreePort(); + instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password); //Start the actual process: std::string cmd = "start ./WorldServer.exe -zone "; @@ -302,7 +321,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon cmd.append(std::to_string(mapID)); cmd.append(" -port "); - cmd.append(std::to_string(m_LastPort)); + cmd.append(std::to_string(port)); cmd.append(" -instance "); cmd.append(std::to_string(m_LastInstanceID)); cmd.append(" -maxclients "); @@ -317,8 +336,6 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon system(cmd.c_str()); - m_LastPort++; //Increment it again because the next port is for World<->Server comm. - m_LastPort++; //Increment it again because the next port is for World<->Chat comm. m_Instances.push_back(instance); if (instance) return instance; diff --git a/dMasterServer/InstanceManager.h b/dMasterServer/InstanceManager.h index 4475f11c..5dc93849 100644 --- a/dMasterServer/InstanceManager.h +++ b/dMasterServer/InstanceManager.h @@ -102,6 +102,7 @@ public: Instance* GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID); //Creates an instance if none found bool IsPortInUse(uint32_t port); + uint32_t GetFreePort(); void AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID); void RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID);