forked from teamnwah/openmw-tes3coop
[Server] Reworking MasterClient to new master server
This commit is contained in:
parent
9643eb6026
commit
3e00d42067
6 changed files with 161 additions and 143 deletions
|
@ -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";
|
|
||||||
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;
|
|
||||||
|
|
||||||
RakNet::RakString transmitted, hostTransmitted;
|
|
||||||
RakNet::RakString response;
|
|
||||||
RakNet::SystemAddress hostReceived;
|
|
||||||
int contentOffset;
|
|
||||||
|
|
||||||
while (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))
|
|
||||||
{
|
|
||||||
if (contentOffset < 0)
|
|
||||||
return "NO_CONTENT"; // no content
|
|
||||||
tcpInterface.CloseConnection(sa);
|
|
||||||
return (response.C_String() + contentOffset);
|
|
||||||
}
|
|
||||||
RakSleep(30);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MasterClient::Update()
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MasterClient::Process(RakNet::Packet *packet)
|
||||||
|
{
|
||||||
|
if (!sRun || packet->systemAddress != masterServer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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(500);
|
||||||
|
}
|
||||||
|
pma.SetFunc(func);
|
||||||
|
pma.Send(masterServer);
|
||||||
|
updated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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…
Reference in a new issue