From 3e00d42067338cd79caa1c05cac0ebf7fd52d9bd Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 24 Apr 2017 20:01:05 +0800 Subject: [PATCH] [Server] Reworking MasterClient to new master server --- apps/openmw-mp/MasterClient.cpp | 228 +++++++++++++------------ apps/openmw-mp/MasterClient.hpp | 34 ++-- apps/openmw-mp/Networking.cpp | 12 +- apps/openmw-mp/Networking.hpp | 2 +- apps/openmw-mp/main.cpp | 2 +- files/tes3mp/tes3mp-server-default.cfg | 2 +- 6 files changed, 149 insertions(+), 131 deletions(-) diff --git a/apps/openmw-mp/MasterClient.cpp b/apps/openmw-mp/MasterClient.cpp index 72a50af84..5ba5cf5b5 100644 --- a/apps/openmw-mp/MasterClient.cpp +++ b/apps/openmw-mp/MasterClient.cpp @@ -11,171 +11,187 @@ #include "MasterClient.hpp" #include #include +#include #include "Networking.hpp" using namespace std; +using namespace mwmp; +using namespace RakNet; bool MasterClient::sRun = false; -MasterClient::MasterClient(std::string queryAddr, unsigned short queryPort, std::string serverAddr, - unsigned short serverPort) : queryAddr(queryAddr), queryPort(queryPort), - serverAddr(serverAddr), serverPort(serverPort) +MasterClient::MasterClient(RakNet::RakPeerInterface *peer, std::string queryAddr, unsigned short queryPort) : + masterServer(queryAddr.c_str(), queryPort), peer(peer), pma(peer) { - players = 0; - maxPlayers = 0; - hostname = ""; - modname = ""; - timeout = 1000; // every 1 seconds + timeout = 15000; // every 15 seconds + pma.SetSendStream(&writeStream); + pma.SetServer(&queryData); + updated = true; } void MasterClient::SetPlayers(unsigned pl) { mutexData.lock(); - players = pl; + if (queryData.GetPlayers() != pl) + { + queryData.SetPlayers(pl); + updated = true; + } mutexData.unlock(); } void MasterClient::SetMaxPlayers(unsigned pl) { mutexData.lock(); - maxPlayers = pl; + if (queryData.GetMaxPlayers() != pl) + { + queryData.SetMaxPlayers(pl); + updated = true; + } mutexData.unlock(); } void MasterClient::SetHostname(std::string hostname) { mutexData.lock(); - this->hostname = hostname.substr(0, 200); + string substr = hostname.substr(0, 200); + if (queryData.GetName() != substr) + { + queryData.SetName(substr.c_str()); + updated = true; + } mutexData.unlock(); } void MasterClient::SetModname(std::string modname) { mutexData.lock(); - this->modname = modname.substr(0, 200); + string substr = modname.substr(0, 200); + if (queryData.GetGameMode() != substr) + { + queryData.SetGameMode(substr.c_str()); + updated = true; + } mutexData.unlock(); } -RakNet::RakString -MasterClient::Send(std::string hostname, std::string modname, unsigned maxPlayers, bool update, unsigned players) +void MasterClient::SetRuleString(std::string key, std::string value) { - /*static unsigned short oldServerPort, oldQueryPort; - static string oldMotd; - static unsigned oldPlayers, oldMaxPlayers;*/ - std::stringstream sstr; mutexData.lock(); - sstr << "{"; - sstr << "\"port\": " << serverPort << ", "; - sstr << "\"query_port\": " << queryPort << ", "; - sstr << "\"hostname\": \"" << hostname.c_str() << "\", "; - sstr << "\"modname\": \"" << modname.c_str() << "\", "; - sstr << "\"players\": " << players << ", "; - sstr << "\"max_players\": " << maxPlayers << ", "; - sstr << "\"version\": \"" << TES3MP_VERSION << "\", "; - sstr << "\"passw\": " << (mwmp::Networking::get().isPassworded() ? "true" : "false"); - sstr << "}"; + if (queryData.rules.find(key) == queryData.rules.end() || queryData.rules[key].type != 's' + || queryData.rules[key].str != value) + { + ServerRule rule; + rule.str = value; + rule.type = 's'; + queryData.rules.insert({key, rule}); + } mutexData.unlock(); +} - std::string contentType = "application/json"; - RakNet::RakString createRequest; - - if (update) - createRequest = RakNet::RakString::FormatForPUT( - string("/api/servers/" + serverAddr + ":" + to_string(serverPort)).c_str(), contentType.c_str(), - sstr.str().c_str()); - else - createRequest = RakNet::RakString::FormatForPOST("/api/servers", contentType.c_str(), - sstr.str().c_str()); - - httpConnection->TransmitRequest(createRequest.C_String(), queryAddr.c_str(), queryPort); - - RakNet::Packet *packet; - RakNet::SystemAddress sa; +void MasterClient::SetRuleValue(std::string key, double value) +{ + mutexData.lock(); + if (queryData.rules.find(key) == queryData.rules.end() || queryData.rules[key].type != 'v' + || queryData.rules[key].val != value) + return; + ServerRule rule; + rule.str = value; + rule.type = 'v'; + queryData.rules.insert({key, rule}); + mutexData.unlock(); +} - RakNet::RakString transmitted, hostTransmitted; - RakNet::RakString response; - RakNet::SystemAddress hostReceived; - int contentOffset; +bool MasterClient::Process(RakNet::Packet *packet) +{ + if (!sRun || packet->systemAddress != masterServer) + return false; - while (true) + BitStream rs(packet->data, packet->length, false); + unsigned char pid; + rs.Read(pid); + switch (pid) { + case ID_CONNECTION_REQUEST_ACCEPTED: + case ID_DISCONNECTION_NOTIFICATION: + break; + case ID_MASTER_QUERY: + break; + case ID_MASTER_ANNOUNCE: + pma.SetReadStream(&rs); + pma.Read(); + if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_KEEP) + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Server data successfully updated on master server"); + else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_DELETE) + { + if (timeout != 0) + { + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Update rate is too low," + " and the master server has deleted information about the server. Trying low rate..."); + if ((timeout - step_rate) >= step_rate) + SetUpdateRate(timeout - step_rate); + updated = true; + } + } + break; + default: + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Received wrong packet from master server with id: %d", packet->data[0]); + return false; + } + return true; +} - // This is kind of crappy, but for TCP plugins, always do HasCompletedConnectionAttempt, - // then Receive(), then HasFailedConnectionAttempt(),HasLostConnection() - sa = tcpInterface.HasCompletedConnectionAttempt(); - if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Connected to master server: %s", sa.ToString()); - - sa = tcpInterface.HasFailedConnectionAttempt(); - if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) - { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Failed to connect to master server: %s", sa.ToString()); - return "FAIL_CONNECT"; - } - sa = tcpInterface.HasLostConnection(); - if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) - { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Lost connection to master server: %s", sa.ToString()); - return "LOST_CONNECTION"; - } - - for (packet = tcpInterface.Receive(); packet; tcpInterface.DeallocatePacket( - packet), packet = tcpInterface.Receive()); - - if (httpConnection->GetResponse(transmitted, hostTransmitted, response, hostReceived, contentOffset)) +void MasterClient::Send(mwmp::PacketMasterAnnounce::Func func) +{ + peer->Connect(masterServer.ToString(false), masterServer.GetPort(), "pass", strlen("pass"), 0, 0, 5, 500); + bool waitForConnect = true; + while (waitForConnect) + { + ConnectionState state = peer->GetConnectionState(masterServer); + switch (state) { - if (contentOffset < 0) - return "NO_CONTENT"; // no content - tcpInterface.CloseConnection(sa); - return (response.C_String() + contentOffset); + case IS_CONNECTED: + waitForConnect = false; + break; + case IS_NOT_CONNECTED: + case IS_DISCONNECTED: + case IS_SILENTLY_DISCONNECTING: + case IS_DISCONNECTING: + { + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Cannot connect to master server: %d", masterServer.ToString()); + return; + } } - RakSleep(30); + RakSleep(500); } - + pma.SetFunc(func); + pma.Send(masterServer); + updated = false; } -void MasterClient::Update() +void MasterClient::Thread() { assert(!sRun); - httpConnection = RakNet::HTTPConnection2::GetInstance(); - tcpInterface.Start(0, 64); - tcpInterface.AttachPlugin(httpConnection); - - RakNet::RakString response = Send(hostname, modname, maxPlayers, false, players); - bool update = true; sRun = true; + + queryData.SetPassword((int) Networking::get().isPassworded()); + queryData.SetVersion(TES3MP_VERSION); + while (sRun) { - if (response == "Created") - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Server registered on the master server."); - else if (response == "Accepted") - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Sent info update to master server."); - else if (response == "bad request") - { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Update rate is too low, and the master server has deleted information about" - " the server. Trying low rate..."); - if ((timeout - step_rate) >= step_rate) - SetUpdateRate(timeout - step_rate); - update = false; - } + SetPlayers((int) Players::getPlayers()->size()); + if (updated) + Send(PacketMasterAnnounce::FUNCTION_ANNOUNCE); else - { - /*cout << "Error: \""<< response << "\"" << endl; - cout << response.GetLength() << endl;*/ - } - + Send(PacketMasterAnnounce::FUNCTION_KEEP); RakSleep(timeout); - - players = Players::getPlayers()->size(); - response = Send(hostname, modname, maxPlayers, update, players); - update = true; } } void MasterClient::Start() { - thrQuery = thread(&MasterClient::Update, this); + thrQuery = thread(&MasterClient::Thread, this); } void MasterClient::Stop() diff --git a/apps/openmw-mp/MasterClient.hpp b/apps/openmw-mp/MasterClient.hpp index c34c8b9e1..02c3c9c6a 100644 --- a/apps/openmw-mp/MasterClient.hpp +++ b/apps/openmw-mp/MasterClient.hpp @@ -6,46 +6,46 @@ #define OPENMW_MASTERCLIENT_HPP #include -#include -#include #include #include +#include +#include +#include class MasterClient { public: static const unsigned int step_rate = 1000; static const unsigned int min_rate = 1000; - static const unsigned int max_rate = 30000; + static const unsigned int max_rate = 60000; public: - MasterClient(std::string queryAddr, unsigned short queryPort, std::string serverAddr, unsigned short serverPort); + MasterClient(RakNet::RakPeerInterface *peer, std::string queryAddr, unsigned short queryPort); void SetPlayers(unsigned pl); void SetMaxPlayers(unsigned pl); void SetHostname(std::string hostname); void SetModname(std::string hostname); - void Update(); + void SetRuleString(std::string key, std::string value); + void SetRuleValue(std::string key, double value); + + bool Process(RakNet::Packet *packet); void Start(); void Stop(); void SetUpdateRate(unsigned int rate); private: - RakNet::RakString - Send(std::string hostname, std::string modname, unsigned maxPlayers, bool update, unsigned players); + void Send(mwmp::PacketMasterAnnounce::Func func); + void Thread(); private: - std::string queryAddr; - unsigned short queryPort; - std::string serverAddr; - unsigned short serverPort; - std::string hostname; - std::string modname; - unsigned players, maxPlayers; - RakNet::HTTPConnection2 *httpConnection; - RakNet::TCPInterface tcpInterface; + RakNet::SystemAddress masterServer; + RakNet::RakPeerInterface *peer; + QueryData queryData; unsigned int timeout; static bool sRun; std::mutex mutexData; std::thread thrQuery; - + mwmp::PacketMasterAnnounce pma; + RakNet::BitStream writeStream; + bool updated; }; diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index 7e10d0bc2..62cfeb1e4 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -365,6 +365,9 @@ int Networking::mainLoop() break; for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive()) { + if (getMasterClient()->Process(packet)) + continue; + switch (packet->data[0]) { case ID_REMOTE_DISCONNECTION_NOTIFICATION: @@ -398,7 +401,7 @@ int Networking::mainLoop() case ID_CONNECTED_PING: case ID_UNCONNECTED_PING: break; - case ID_MASTER_QUERY: + /*case ID_MASTER_QUERY: { LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Query request from %s", packet->systemAddress.ToString()); RakNet::BitStream bs; @@ -409,7 +412,7 @@ int Networking::mainLoop() bs.Write(0); // plugins peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false); break; - } + }*/ default: update(packet); break; @@ -448,8 +451,7 @@ MasterClient *Networking::getMasterClient() return mclient; } -void Networking::InitQuery(std::string queryAddr, unsigned short queryPort, std::string serverAddr, - unsigned short serverPort) +void Networking::InitQuery(std::string queryAddr, unsigned short queryPort) { - mclient = new MasterClient(queryAddr, queryPort, serverAddr, serverPort); + mclient = new MasterClient(peer, queryAddr, queryPort); } diff --git a/apps/openmw-mp/Networking.hpp b/apps/openmw-mp/Networking.hpp index b12ac5d1f..bcdfede6d 100644 --- a/apps/openmw-mp/Networking.hpp +++ b/apps/openmw-mp/Networking.hpp @@ -48,7 +48,7 @@ namespace mwmp int incrementMpNum(); MasterClient *getMasterClient(); - void InitQuery(std::string queryAddr, unsigned short queryPort, std::string serverAddr, unsigned short serverPort); + void InitQuery(std::string queryAddr, unsigned short queryPort); void setServerPassword(std::string passw) noexcept; bool isPassworded() const; diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index 6e54e1c6d..e21005e14 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -243,7 +243,7 @@ int main(int argc, char *argv[]) string masterAddr = mgr.getString("address", "MasterServer"); int masterPort = mgr.getInt("port", "MasterServer"); - networking.InitQuery(masterAddr, (unsigned short) masterPort, addr, (unsigned short) port); + networking.InitQuery(masterAddr, (unsigned short) masterPort); networking.getMasterClient()->SetMaxPlayers((unsigned)players); string hostname = mgr.getString("hostname", "General"); networking.getMasterClient()->SetHostname(hostname); diff --git a/files/tes3mp/tes3mp-server-default.cfg b/files/tes3mp/tes3mp-server-default.cfg index 759c050a8..02439710e 100644 --- a/files/tes3mp/tes3mp-server-default.cfg +++ b/files/tes3mp/tes3mp-server-default.cfg @@ -15,5 +15,5 @@ plugins = server.lua [MasterServer] enabled = true address = master.tes3mp.com -port = 8080 +port = 25560 rate = 1000