[Server] Reworking MasterClient to new master server

0.6.1
Koncord 8 years ago
parent 9643eb6026
commit 3e00d42067

@ -11,171 +11,187 @@
#include "MasterClient.hpp" #include "MasterClient.hpp"
#include <components/openmw-mp/Log.hpp> #include <components/openmw-mp/Log.hpp>
#include <components/openmw-mp/Version.hpp> #include <components/openmw-mp/Version.hpp>
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
#include "Networking.hpp" #include "Networking.hpp"
using namespace std; using namespace std;
using namespace mwmp;
using namespace RakNet;
bool MasterClient::sRun = false; bool MasterClient::sRun = false;
MasterClient::MasterClient(std::string queryAddr, unsigned short queryPort, std::string serverAddr, MasterClient::MasterClient(RakNet::RakPeerInterface *peer, std::string queryAddr, unsigned short queryPort) :
unsigned short serverPort) : queryAddr(queryAddr), queryPort(queryPort), masterServer(queryAddr.c_str(), queryPort), peer(peer), pma(peer)
serverAddr(serverAddr), serverPort(serverPort)
{ {
players = 0; timeout = 15000; // every 15 seconds
maxPlayers = 0; pma.SetSendStream(&writeStream);
hostname = ""; pma.SetServer(&queryData);
modname = ""; updated = true;
timeout = 1000; // every 1 seconds
} }
void MasterClient::SetPlayers(unsigned pl) void MasterClient::SetPlayers(unsigned pl)
{ {
mutexData.lock(); mutexData.lock();
players = pl; if (queryData.GetPlayers() != pl)
{
queryData.SetPlayers(pl);
updated = true;
}
mutexData.unlock(); mutexData.unlock();
} }
void MasterClient::SetMaxPlayers(unsigned pl) void MasterClient::SetMaxPlayers(unsigned pl)
{ {
mutexData.lock(); mutexData.lock();
maxPlayers = pl; if (queryData.GetMaxPlayers() != pl)
{
queryData.SetMaxPlayers(pl);
updated = true;
}
mutexData.unlock(); mutexData.unlock();
} }
void MasterClient::SetHostname(std::string hostname) void MasterClient::SetHostname(std::string hostname)
{ {
mutexData.lock(); 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(); mutexData.unlock();
} }
void MasterClient::SetModname(std::string modname) void MasterClient::SetModname(std::string modname)
{ {
mutexData.lock(); 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(); mutexData.unlock();
} }
RakNet::RakString void MasterClient::SetRuleString(std::string key, std::string value)
MasterClient::Send(std::string hostname, std::string modname, unsigned maxPlayers, bool update, unsigned players)
{ {
/*static unsigned short oldServerPort, oldQueryPort;
static string oldMotd;
static unsigned oldPlayers, oldMaxPlayers;*/
std::stringstream sstr;
mutexData.lock(); mutexData.lock();
sstr << "{"; if (queryData.rules.find(key) == queryData.rules.end() || queryData.rules[key].type != 's'
sstr << "\"port\": " << serverPort << ", "; || queryData.rules[key].str != value)
sstr << "\"query_port\": " << queryPort << ", "; {
sstr << "\"hostname\": \"" << hostname.c_str() << "\", "; ServerRule rule;
sstr << "\"modname\": \"" << modname.c_str() << "\", "; rule.str = value;
sstr << "\"players\": " << players << ", "; rule.type = 's';
sstr << "\"max_players\": " << maxPlayers << ", "; queryData.rules.insert({key, rule});
sstr << "\"version\": \"" << TES3MP_VERSION << "\", "; }
sstr << "\"passw\": " << (mwmp::Networking::get().isPassworded() ? "true" : "false");
sstr << "}";
mutexData.unlock(); mutexData.unlock();
}
std::string contentType = "application/json"; void MasterClient::SetRuleValue(std::string key, double value)
RakNet::RakString createRequest; {
mutexData.lock();
if (update) if (queryData.rules.find(key) == queryData.rules.end() || queryData.rules[key].type != 'v'
createRequest = RakNet::RakString::FormatForPUT( || queryData.rules[key].val != value)
string("/api/servers/" + serverAddr + ":" + to_string(serverPort)).c_str(), contentType.c_str(), return;
sstr.str().c_str()); ServerRule rule;
else rule.str = value;
createRequest = RakNet::RakString::FormatForPOST("/api/servers", contentType.c_str(), rule.type = 'v';
sstr.str().c_str()); queryData.rules.insert({key, rule});
mutexData.unlock();
httpConnection->TransmitRequest(createRequest.C_String(), queryAddr.c_str(), queryPort); }
RakNet::Packet *packet;
RakNet::SystemAddress sa;
RakNet::RakString transmitted, hostTransmitted; bool MasterClient::Process(RakNet::Packet *packet)
RakNet::RakString response; {
RakNet::SystemAddress hostReceived; if (!sRun || packet->systemAddress != masterServer)
int contentOffset; 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, void MasterClient::Send(mwmp::PacketMasterAnnounce::Func func)
// then Receive(), then HasFailedConnectionAttempt(),HasLostConnection() {
sa = tcpInterface.HasCompletedConnectionAttempt(); peer->Connect(masterServer.ToString(false), masterServer.GetPort(), "pass", strlen("pass"), 0, 0, 5, 500);
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) bool waitForConnect = true;
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Connected to master server: %s", sa.ToString()); while (waitForConnect)
{
sa = tcpInterface.HasFailedConnectionAttempt(); ConnectionState state = peer->GetConnectionState(masterServer);
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) switch (state)
{
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))
{ {
if (contentOffset < 0) case IS_CONNECTED:
return "NO_CONTENT"; // no content waitForConnect = false;
tcpInterface.CloseConnection(sa); break;
return (response.C_String() + contentOffset); 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); 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; sRun = true;
queryData.SetPassword((int) Networking::get().isPassworded());
queryData.SetVersion(TES3MP_VERSION);
while (sRun) while (sRun)
{ {
if (response == "Created") SetPlayers((int) Players::getPlayers()->size());
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Server registered on the master server."); if (updated)
else if (response == "Accepted") Send(PacketMasterAnnounce::FUNCTION_ANNOUNCE);
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;
}
else else
{ Send(PacketMasterAnnounce::FUNCTION_KEEP);
/*cout << "Error: \""<< response << "\"" << endl;
cout << response.GetLength() << endl;*/
}
RakSleep(timeout); RakSleep(timeout);
players = Players::getPlayers()->size();
response = Send(hostname, modname, maxPlayers, update, players);
update = true;
} }
} }
void MasterClient::Start() void MasterClient::Start()
{ {
thrQuery = thread(&MasterClient::Update, this); thrQuery = thread(&MasterClient::Thread, this);
} }
void MasterClient::Stop() void MasterClient::Stop()

@ -6,46 +6,46 @@
#define OPENMW_MASTERCLIENT_HPP #define OPENMW_MASTERCLIENT_HPP
#include <string> #include <string>
#include <HTTPConnection2.h>
#include <TCPInterface.h>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <components/openmw-mp/Master/MasterData.hpp>
#include <RakString.h>
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
class MasterClient class MasterClient
{ {
public: public:
static const unsigned int step_rate = 1000; static const unsigned int step_rate = 1000;
static const unsigned int min_rate = 1000; static const unsigned int min_rate = 1000;
static const unsigned int max_rate = 30000; static const unsigned int max_rate = 60000;
public: 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 SetPlayers(unsigned pl);
void SetMaxPlayers(unsigned pl); void SetMaxPlayers(unsigned pl);
void SetHostname(std::string hostname); void SetHostname(std::string hostname);
void SetModname(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 Start();
void Stop(); void Stop();
void SetUpdateRate(unsigned int rate); void SetUpdateRate(unsigned int rate);
private: private:
RakNet::RakString void Send(mwmp::PacketMasterAnnounce::Func func);
Send(std::string hostname, std::string modname, unsigned maxPlayers, bool update, unsigned players); void Thread();
private: private:
std::string queryAddr; RakNet::SystemAddress masterServer;
unsigned short queryPort; RakNet::RakPeerInterface *peer;
std::string serverAddr; QueryData queryData;
unsigned short serverPort;
std::string hostname;
std::string modname;
unsigned players, maxPlayers;
RakNet::HTTPConnection2 *httpConnection;
RakNet::TCPInterface tcpInterface;
unsigned int timeout; unsigned int timeout;
static bool sRun; static bool sRun;
std::mutex mutexData; std::mutex mutexData;
std::thread thrQuery; std::thread thrQuery;
mwmp::PacketMasterAnnounce pma;
RakNet::BitStream writeStream;
bool updated;
}; };

@ -365,6 +365,9 @@ int Networking::mainLoop()
break; break;
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive()) for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{ {
if (getMasterClient()->Process(packet))
continue;
switch (packet->data[0]) switch (packet->data[0])
{ {
case ID_REMOTE_DISCONNECTION_NOTIFICATION: case ID_REMOTE_DISCONNECTION_NOTIFICATION:
@ -398,7 +401,7 @@ int Networking::mainLoop()
case ID_CONNECTED_PING: case ID_CONNECTED_PING:
case ID_UNCONNECTED_PING: case ID_UNCONNECTED_PING:
break; break;
case ID_MASTER_QUERY: /*case ID_MASTER_QUERY:
{ {
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Query request from %s", packet->systemAddress.ToString()); LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Query request from %s", packet->systemAddress.ToString());
RakNet::BitStream bs; RakNet::BitStream bs;
@ -409,7 +412,7 @@ int Networking::mainLoop()
bs.Write(0); // plugins bs.Write(0); // plugins
peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false); peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
break; break;
} }*/
default: default:
update(packet); update(packet);
break; break;
@ -448,8 +451,7 @@ MasterClient *Networking::getMasterClient()
return mclient; return mclient;
} }
void Networking::InitQuery(std::string queryAddr, unsigned short queryPort, std::string serverAddr, void Networking::InitQuery(std::string queryAddr, unsigned short queryPort)
unsigned short serverPort)
{ {
mclient = new MasterClient(queryAddr, queryPort, serverAddr, serverPort); mclient = new MasterClient(peer, queryAddr, queryPort);
} }

@ -48,7 +48,7 @@ namespace mwmp
int incrementMpNum(); int incrementMpNum();
MasterClient *getMasterClient(); 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; void setServerPassword(std::string passw) noexcept;
bool isPassworded() const; bool isPassworded() const;

@ -243,7 +243,7 @@ int main(int argc, char *argv[])
string masterAddr = mgr.getString("address", "MasterServer"); string masterAddr = mgr.getString("address", "MasterServer");
int masterPort = mgr.getInt("port", "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); networking.getMasterClient()->SetMaxPlayers((unsigned)players);
string hostname = mgr.getString("hostname", "General"); string hostname = mgr.getString("hostname", "General");
networking.getMasterClient()->SetHostname(hostname); networking.getMasterClient()->SetHostname(hostname);

@ -15,5 +15,5 @@ plugins = server.lua
[MasterServer] [MasterServer]
enabled = true enabled = true
address = master.tes3mp.com address = master.tes3mp.com
port = 8080 port = 25560
rate = 1000 rate = 1000

Loading…
Cancel
Save