2016-01-28 10:19:43 -05:00
|
|
|
#include "STDInclude.hpp"
|
|
|
|
|
|
|
|
namespace Components
|
|
|
|
{
|
|
|
|
std::vector<Node::NodeEntry> Node::Nodes;
|
|
|
|
std::vector<Node::DediEntry> Node::Dedis;
|
|
|
|
|
|
|
|
void Node::LoadNodes()
|
|
|
|
{
|
2016-01-28 15:37:48 -05:00
|
|
|
std::string nodes = Utils::ReadFile("players/nodes.dat");
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
// Invalid
|
|
|
|
if (!nodes.size() || nodes.size() % 6) return;
|
|
|
|
|
|
|
|
unsigned int size = (nodes.size() / sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Node::AddressEntry* addresses = reinterpret_cast<Node::AddressEntry*>(const_cast<char*>(nodes.data()));
|
|
|
|
for (unsigned int i = 0; i < size; ++i)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
2016-01-28 15:37:48 -05:00
|
|
|
Node::AddNode(addresses[i].toNetAddress());
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-06 18:48:39 -05:00
|
|
|
void Node::StoreNodes(bool force)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
2016-02-06 18:48:39 -05:00
|
|
|
static int lastStorage = 0;
|
|
|
|
|
|
|
|
// Don't store nodes if the delta is too small and were not forcing it
|
|
|
|
if ((Game::Com_Milliseconds() - lastStorage) < NODE_STORE_INTERVAL && !force) return;
|
|
|
|
lastStorage = Game::Com_Milliseconds();
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
std::vector<Node::AddressEntry> entries;
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
for (auto entry : Node::Nodes)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
2016-01-28 17:36:57 -05:00
|
|
|
if (entry.state == Node::STATE_VALID)
|
|
|
|
{
|
|
|
|
Node::AddressEntry thisAddress;
|
|
|
|
thisAddress.fromNetAddress(entry.address);
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-01-28 17:36:57 -05:00
|
|
|
entries.push_back(thisAddress);
|
|
|
|
}
|
2016-01-28 15:37:48 -05:00
|
|
|
}
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
std::string nodeStream(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
CreateDirectoryW(L"players", NULL);
|
|
|
|
Utils::WriteFile("players/nodes.dat", nodeStream);
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Node::AddNode(Network::Address address, bool valid)
|
|
|
|
{
|
2016-01-28 21:49:51 -05:00
|
|
|
#ifdef DEBUG
|
2016-01-28 15:37:48 -05:00
|
|
|
if (address.IsSelf()) return;
|
2016-01-28 21:49:51 -05:00
|
|
|
#else
|
|
|
|
if (address.IsLocal() || address.IsSelf()) return;
|
|
|
|
#endif
|
2016-01-28 10:19:43 -05:00
|
|
|
|
|
|
|
Node::NodeEntry entry;
|
|
|
|
|
2016-02-01 15:59:45 -05:00
|
|
|
entry.lastHeard = Game::Com_Milliseconds();
|
2016-01-28 15:37:48 -05:00
|
|
|
entry.lastHeartbeat = 0;
|
2016-01-28 21:49:51 -05:00
|
|
|
entry.lastTime = (valid ? Game::Com_Milliseconds() : 0);
|
2016-01-28 10:19:43 -05:00
|
|
|
entry.state = (valid ? Node::STATE_VALID : Node::STATE_UNKNOWN);
|
|
|
|
entry.address = address;
|
|
|
|
|
|
|
|
// Search if we already know that node
|
|
|
|
bool duplicate = false;
|
|
|
|
for (auto &ourEntry : Node::Nodes)
|
|
|
|
{
|
|
|
|
if (ourEntry.address == entry.address)
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
ourEntry.lastHeard = Game::Com_Milliseconds();
|
|
|
|
|
|
|
|
// if (ourEntry.state == Node::STATE_INVALID)
|
|
|
|
// {
|
|
|
|
// Logger::Print("Node %s was invalidated, but we still received a reference from another node. Suspicous...\n", address.GetString());
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Validate it
|
2016-01-28 10:19:43 -05:00
|
|
|
if (valid)
|
|
|
|
{
|
|
|
|
ourEntry.state = Node::STATE_VALID;
|
2016-01-28 21:49:51 -05:00
|
|
|
ourEntry.lastTime = Game::Com_Milliseconds();
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
duplicate = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert if we don't
|
|
|
|
if (!duplicate)
|
|
|
|
{
|
|
|
|
Node::Nodes.push_back(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
void Node::AddDedi(Network::Address address, bool dirty)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
|
|
|
Node::DediEntry entry;
|
|
|
|
|
2016-02-01 15:59:45 -05:00
|
|
|
entry.lastHeard = Game::Com_Milliseconds();
|
2016-01-28 21:49:51 -05:00
|
|
|
entry.lastTime = 0;
|
2016-01-28 10:19:43 -05:00
|
|
|
entry.state = Node::STATE_UNKNOWN;
|
|
|
|
entry.address = address;
|
|
|
|
|
|
|
|
// Search if we already know that node
|
|
|
|
bool duplicate = false;
|
2016-01-28 15:37:48 -05:00
|
|
|
for (auto &ourEntry : Node::Dedis)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
|
|
|
if (ourEntry.address == entry.address)
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
ourEntry.lastHeard = Game::Com_Milliseconds();
|
|
|
|
|
|
|
|
// if (ourEntry.state == Node::STATE_INVALID)
|
|
|
|
// {
|
|
|
|
// Logger::Print("Dedi %s was invalidated, but we still received a reference from another node. Suspicous...\n", address.GetString());
|
|
|
|
// }
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
if (dirty)
|
|
|
|
{
|
2016-01-28 21:49:51 -05:00
|
|
|
ourEntry.lastTime = Game::Com_Milliseconds();
|
2016-01-28 15:37:48 -05:00
|
|
|
ourEntry.state = Node::STATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2016-01-28 10:19:43 -05:00
|
|
|
duplicate = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert if we don't
|
|
|
|
if (!duplicate)
|
|
|
|
{
|
|
|
|
Node::Dedis.push_back(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Node::SendNodeList(Network::Address target)
|
|
|
|
{
|
|
|
|
if (target.IsSelf()) return;
|
|
|
|
|
|
|
|
std::vector<Node::AddressEntry> entries;
|
|
|
|
|
|
|
|
for (auto entry : Node::Nodes)
|
|
|
|
{
|
2016-01-28 17:36:57 -05:00
|
|
|
if (entry.state == Node::STATE_VALID) // Only send valid nodes, or shall we send invalid ones as well?
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
|
|
|
Node::AddressEntry thisAddress;
|
|
|
|
thisAddress.fromNetAddress(entry.address);
|
|
|
|
|
|
|
|
entries.push_back(thisAddress);
|
|
|
|
}
|
|
|
|
|
2016-02-01 15:59:45 -05:00
|
|
|
if (entries.size() >= NODE_PACKET_LIMIT)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
|
|
|
std::string packet = "nodeNodeList\n";
|
|
|
|
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Network::SendRaw(target, packet);
|
|
|
|
|
|
|
|
entries.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string packet = "nodeNodeList\n";
|
|
|
|
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Network::SendRaw(target, packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Node::SendDediList(Network::Address target)
|
|
|
|
{
|
|
|
|
if (target.IsSelf()) return;
|
|
|
|
|
|
|
|
std::vector<Node::AddressEntry> entries;
|
|
|
|
|
|
|
|
for (auto entry : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (entry.state == Node::STATE_VALID) // Only send valid dedis
|
|
|
|
{
|
|
|
|
Node::AddressEntry thisAddress;
|
|
|
|
thisAddress.fromNetAddress(entry.address);
|
|
|
|
|
|
|
|
entries.push_back(thisAddress);
|
|
|
|
}
|
2016-02-01 15:59:45 -05:00
|
|
|
|
|
|
|
if (entries.size() >= DEDI_PACKET_LIMIT)
|
|
|
|
{
|
|
|
|
std::string packet = "nodeDediList\n";
|
|
|
|
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Network::SendRaw(target, packet);
|
|
|
|
|
|
|
|
entries.clear();
|
|
|
|
}
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string packet = "nodeDediList\n";
|
|
|
|
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Network::SendRaw(target, packet);
|
|
|
|
}
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
void Node::ValidateDedi(Network::Address address, Utils::InfoString info)
|
|
|
|
{
|
|
|
|
for (auto &dedi : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (dedi.address == address)
|
|
|
|
{
|
2016-02-05 07:10:22 -05:00
|
|
|
if (dedi.state == Node::STATE_QUERYING)
|
2016-01-28 15:37:48 -05:00
|
|
|
{
|
2016-02-05 07:10:22 -05:00
|
|
|
dedi.state = (info.Get("challenge") == dedi.challenge ? Node::STATE_VALID : Node::STATE_INVALID);
|
|
|
|
dedi.lastTime = Game::Com_Milliseconds();
|
|
|
|
|
|
|
|
if (dedi.state == Node::STATE_VALID)
|
|
|
|
{
|
|
|
|
Logger::Print("Validated dedi %s\n", address.GetString());
|
|
|
|
}
|
2016-01-28 15:37:48 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
std::vector<Network::Address> Node::GetDediList()
|
|
|
|
{
|
|
|
|
std::vector<Network::Address> dedis;
|
|
|
|
|
|
|
|
for (auto dedi : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (dedi.state == Node::STATE_VALID)
|
|
|
|
{
|
|
|
|
dedis.push_back(dedi.address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dedis;
|
|
|
|
}
|
|
|
|
|
2016-01-28 17:36:57 -05:00
|
|
|
void Node::DeleteInvalidNodes()
|
|
|
|
{
|
|
|
|
std::vector<Node::NodeEntry> cleanNodes;
|
|
|
|
|
|
|
|
for (auto node : Node::Nodes)
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
if (node.state == Node::STATE_INVALID && (Game::Com_Milliseconds() - node.lastHeard) > NODE_INVALID_DELETE)
|
2016-01-28 17:36:57 -05:00
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
Logger::Print("Removing invalid node %s\n", node.address.GetString());
|
2016-01-28 17:36:57 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
cleanNodes.push_back(node);
|
2016-01-28 17:36:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cleanNodes.size() != Node::Nodes.size())
|
|
|
|
{
|
|
|
|
Node::Nodes.clear();
|
|
|
|
Utils::Merge(&Node::Nodes, cleanNodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
void Node::FrameHandler()
|
|
|
|
{
|
|
|
|
int heartbeatCount = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
// Send requests
|
|
|
|
for (auto &node : Node::Nodes)
|
|
|
|
{
|
|
|
|
if (count < NODE_FRAME_QUERY_LIMIT && (node.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */node.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) >(NODE_VALIDITY_EXPIRE))))
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
|
|
|
|
node.lastTime = Game::Com_Milliseconds();
|
|
|
|
node.state = Node::STATE_QUERYING;
|
|
|
|
|
|
|
|
Logger::Print("Syncing with node %s...\n", node.address.GetString());
|
|
|
|
|
|
|
|
// Request new lists
|
|
|
|
Network::Send(node.address, "nodeRequestLists");
|
|
|
|
|
|
|
|
// Send our lists (only if dedi)
|
|
|
|
if (Dedicated::IsDedicated())
|
|
|
|
{
|
|
|
|
Node::SendNodeList(node.address);
|
|
|
|
Node::SendDediList(node.address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) > (NODE_QUERY_TIMEOUT))
|
|
|
|
{
|
|
|
|
node.state = Node::STATE_INVALID;
|
|
|
|
node.lastTime = Game::Com_Milliseconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dedicated::IsDedicated() && node.state == Node::STATE_VALID)
|
|
|
|
{
|
2016-02-06 18:48:39 -05:00
|
|
|
if (heartbeatCount < HEARTBEATS_FRAME_LIMIT && (!node.lastHeartbeat || (Game::Com_Milliseconds() - node.lastHeartbeat) > (HEARTBEAT_INTERVAL)))
|
2016-02-03 14:10:54 -05:00
|
|
|
{
|
|
|
|
heartbeatCount++;
|
|
|
|
|
|
|
|
Logger::Print("Sending heartbeat to node %s...\n", node.address.GetString());
|
|
|
|
node.lastHeartbeat = Game::Com_Milliseconds();
|
|
|
|
Network::Send(node.address, "heartbeat\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (auto &dedi : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (count < DEDI_FRAME_QUERY_LIMIT && (dedi.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */dedi.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) >(DEDI_VALIDITY_EXPIRE))))
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
|
|
|
|
dedi.lastTime = Game::Com_Milliseconds();
|
|
|
|
dedi.challenge = Utils::VA("%d", dedi.lastTime);
|
|
|
|
dedi.state = Node::STATE_QUERYING;
|
|
|
|
|
|
|
|
Logger::Print("Verifying dedi %s...\n", dedi.address.GetString());
|
|
|
|
|
|
|
|
// Request new lists
|
|
|
|
Network::Send(dedi.address, Utils::VA("getinfo %s\n", dedi.challenge.data()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// No query response
|
|
|
|
if (dedi.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) > (DEDI_QUERY_TIMEOUT))
|
|
|
|
{
|
|
|
|
dedi.state = Node::STATE_INVALID;
|
|
|
|
dedi.lastTime = Game::Com_Milliseconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lack of heartbeats
|
|
|
|
if (dedi.state == Node::STATE_VALID && (Game::Com_Milliseconds() - dedi.lastTime) > (HEARTBEAT_DEADLINE))
|
|
|
|
{
|
|
|
|
Logger::Print("Invalidating dedi %s\n", dedi.address.GetString());
|
|
|
|
dedi.state = Node::STATE_INVALID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Node::DeleteInvalidNodes();
|
|
|
|
Node::DeleteInvalidDedis();
|
2016-02-06 18:48:39 -05:00
|
|
|
Node::StoreNodes(false);
|
2016-02-03 14:10:54 -05:00
|
|
|
}
|
|
|
|
|
2016-01-28 17:36:57 -05:00
|
|
|
void Node::DeleteInvalidDedis()
|
|
|
|
{
|
|
|
|
std::vector<Node::DediEntry> cleanDedis;
|
|
|
|
|
|
|
|
for (auto dedi : Node::Dedis)
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
if (dedi.state == Node::STATE_INVALID && (Game::Com_Milliseconds() - dedi.lastHeard) > DEDI_INVALID_DELETE)
|
2016-01-28 17:36:57 -05:00
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
Logger::Print("Removing invalid dedi %s\n", dedi.address.GetString());
|
2016-01-28 17:36:57 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-01 15:59:45 -05:00
|
|
|
cleanDedis.push_back(dedi);
|
2016-01-28 17:36:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cleanDedis.size() != Node::Dedis.size())
|
|
|
|
{
|
|
|
|
Node::Dedis.clear();
|
|
|
|
Utils::Merge(&Node::Dedis, cleanDedis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
const char* Node::GetStateName(EntryState state)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case Node::STATE_UNKNOWN:
|
|
|
|
return "Unknown";
|
|
|
|
|
|
|
|
case Node::STATE_QUERYING:
|
|
|
|
return "Querying";
|
|
|
|
|
|
|
|
case Node::STATE_INVALID:
|
|
|
|
return "Invalid";
|
|
|
|
|
|
|
|
case Node::STATE_VALID:
|
|
|
|
return "Valid";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2016-01-28 10:19:43 -05:00
|
|
|
Node::Node()
|
|
|
|
{
|
|
|
|
Assert_Size(Node::AddressEntry, 6);
|
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
// ZoneBuilder doesn't require node stuff
|
|
|
|
if (ZoneBuilder::IsEnabled()) return;
|
|
|
|
|
2016-01-28 10:19:43 -05:00
|
|
|
Dvar::OnInit([] ()
|
|
|
|
{
|
2016-01-28 15:37:48 -05:00
|
|
|
Node::Dedis.clear();
|
2016-01-28 10:19:43 -05:00
|
|
|
Node::Nodes.clear();
|
|
|
|
Node::LoadNodes();
|
|
|
|
});
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
if (Dedicated::IsDedicated())
|
|
|
|
{
|
|
|
|
QuickPatch::OnShutdown([] ()
|
|
|
|
{
|
|
|
|
for (auto node : Node::Nodes)
|
|
|
|
{
|
2016-01-28 17:36:57 -05:00
|
|
|
Network::Send(node.address, "deadline\n");
|
2016-01-28 15:37:48 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
// Only dedis act as nodes!
|
|
|
|
if (Dedicated::IsDedicated())
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
2016-02-03 14:10:54 -05:00
|
|
|
Network::Handle("nodeRequestLists", [] (Network::Address address, std::string data)
|
|
|
|
{
|
|
|
|
Logger::Print("Sending our lists to %s\n", address.GetString());
|
2016-01-28 10:19:43 -05:00
|
|
|
|
2016-02-03 14:10:54 -05:00
|
|
|
Node::SendNodeList(address);
|
|
|
|
Node::SendDediList(address);
|
2016-02-05 07:10:22 -05:00
|
|
|
|
|
|
|
// Send our heartbeat as well :P
|
|
|
|
// Otherwise, if there's only 1 node in the network (us), we might not get listed as dedi
|
|
|
|
Network::Send(address, "heartbeat\n");
|
2016-02-03 14:10:54 -05:00
|
|
|
});
|
|
|
|
}
|
2016-01-28 10:19:43 -05:00
|
|
|
|
|
|
|
Network::Handle("nodeNodeList", [] (Network::Address address, std::string data)
|
|
|
|
{
|
|
|
|
if (data.size() % sizeof(Node::AddressEntry))
|
|
|
|
{
|
|
|
|
Logger::Print("Received invalid node list from %s!\n", address.GetString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int size = (data.size() / sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Logger::Print("Received valid node list with %d entries from %s\n", size, address.GetString());
|
|
|
|
|
|
|
|
// Insert the node itself and mark it as valid
|
|
|
|
Node::AddNode(address, true);
|
|
|
|
|
|
|
|
Node::AddressEntry* addresses = reinterpret_cast<Node::AddressEntry*>(const_cast<char*>(data.data()));
|
|
|
|
for (unsigned int i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
Node::AddNode(addresses[i].toNetAddress());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Network::Handle("nodeDediList", [] (Network::Address address, std::string data)
|
|
|
|
{
|
|
|
|
if (data.size() % sizeof(Node::AddressEntry))
|
|
|
|
{
|
|
|
|
Logger::Print("Received invalid dedi list from %s!\n", address.GetString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int size = (data.size() / sizeof(Node::AddressEntry));
|
|
|
|
|
|
|
|
Logger::Print("Received valid dedi list with %d entries from %s\n", size, address.GetString());
|
|
|
|
|
|
|
|
// Insert the node and mark it as valid
|
|
|
|
Node::AddNode(address, true);
|
|
|
|
|
|
|
|
Node::AddressEntry* addresses = reinterpret_cast<Node::AddressEntry*>(const_cast<char*>(data.data()));
|
|
|
|
for (unsigned int i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
Node::AddDedi(addresses[i].toNetAddress());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
Network::Handle("heartbeat", [] (Network::Address address, std::string data)
|
|
|
|
{
|
|
|
|
Logger::Print("Received heartbeat from %s\n", address.GetString());
|
|
|
|
Node::AddDedi(address, true);
|
|
|
|
});
|
|
|
|
|
2016-01-28 17:36:57 -05:00
|
|
|
Network::Handle("deadline", [] (Network::Address address, std::string data)
|
2016-01-28 15:37:48 -05:00
|
|
|
{
|
2016-01-28 17:36:57 -05:00
|
|
|
Logger::Print("Invalidation message received from %s\n", address.GetString());
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
for (auto &dedi : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (dedi.address == address)
|
|
|
|
{
|
|
|
|
dedi.state = Node::STATE_INVALID;
|
2016-01-28 21:49:51 -05:00
|
|
|
dedi.lastTime = Game::Com_Milliseconds();
|
2016-01-28 15:37:48 -05:00
|
|
|
}
|
|
|
|
}
|
2016-01-28 17:36:57 -05:00
|
|
|
|
|
|
|
for (auto &node : Node::Nodes)
|
|
|
|
{
|
|
|
|
if (node.address == address)
|
|
|
|
{
|
|
|
|
node.state = Node::STATE_INVALID;
|
2016-01-28 21:49:51 -05:00
|
|
|
node.lastTime = Game::Com_Milliseconds();
|
2016-01-28 17:36:57 -05:00
|
|
|
}
|
|
|
|
}
|
2016-01-28 15:37:48 -05:00
|
|
|
});
|
|
|
|
|
2016-01-28 10:19:43 -05:00
|
|
|
Command::Add("listnodes", [] (Command::Params params)
|
|
|
|
{
|
|
|
|
Logger::Print("Nodes: %d\n", Node::Nodes.size());
|
|
|
|
|
|
|
|
for (auto node : Node::Nodes)
|
|
|
|
{
|
2016-02-03 14:10:54 -05:00
|
|
|
Logger::Print("%s\t(%s)\n", node.address.GetString(), Node::GetStateName(node.state));
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-01-28 15:37:48 -05:00
|
|
|
Command::Add("listdedis", [] (Command::Params params)
|
|
|
|
{
|
|
|
|
Logger::Print("Dedi: %d\n", Node::Dedis.size());
|
|
|
|
|
|
|
|
for (auto dedi : Node::Dedis)
|
|
|
|
{
|
2016-02-03 14:10:54 -05:00
|
|
|
Logger::Print("%s\t(%s)\n", dedi.address.GetString(), Node::GetStateName(dedi.state));
|
2016-01-28 15:37:48 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-02-01 15:59:45 -05:00
|
|
|
Command::Add("addnode", [] (Command::Params params)
|
2016-01-28 10:19:43 -05:00
|
|
|
{
|
|
|
|
if (params.Length() < 2) return;
|
|
|
|
|
2016-01-28 21:49:51 -05:00
|
|
|
Network::Address address(params[1]);
|
|
|
|
Node::AddNode(address);
|
|
|
|
|
|
|
|
// Invalidate it
|
|
|
|
for (auto &node : Node::Nodes)
|
|
|
|
{
|
|
|
|
if (node.address == address)
|
|
|
|
{
|
|
|
|
node.state = Node::STATE_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-01-28 10:19:43 -05:00
|
|
|
});
|
2016-02-01 15:59:45 -05:00
|
|
|
|
|
|
|
Command::Add("syncnodes", [] (Command::Params params)
|
|
|
|
{
|
|
|
|
for (auto &node : Node::Nodes)
|
|
|
|
{
|
|
|
|
if (node.state != Node::STATE_INVALID)
|
|
|
|
{
|
|
|
|
node.state = Node::STATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Command::Add("syncdedis", [] (Command::Params params)
|
|
|
|
{
|
|
|
|
for (auto &dedi : Node::Dedis)
|
|
|
|
{
|
|
|
|
if (dedi.state != Node::STATE_INVALID)
|
|
|
|
{
|
|
|
|
dedi.state = Node::STATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2016-02-03 14:10:54 -05:00
|
|
|
|
|
|
|
// Install frame handlers
|
|
|
|
Dedicated::OnFrame(Node::FrameHandler);
|
|
|
|
Renderer::OnFrame(Node::FrameHandler);
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Node::~Node()
|
|
|
|
{
|
2016-02-06 18:48:39 -05:00
|
|
|
Node::StoreNodes(true);
|
2016-01-28 10:19:43 -05:00
|
|
|
Node::Nodes.clear();
|
2016-02-06 18:48:39 -05:00
|
|
|
Node::Dedis.clear();
|
2016-01-28 10:19:43 -05:00
|
|
|
}
|
|
|
|
}
|