iw4x-client/src/Components/Modules/Node.cpp

320 lines
7.4 KiB
C++
Raw Normal View History

2017-01-19 16:23:59 -05:00
#include "STDInclude.hpp"
namespace Components
{
2017-06-25 15:54:35 -04:00
std::recursive_mutex Node::Mutex;
std::vector<Node::Entry> Node::Nodes;
bool Node::Entry::isValid()
{
return (this->lastResponse.has_value() && !this->lastResponse->elapsed(NODE_HALFLIFE * 2));
}
bool Node::Entry::isDead()
{
if (!this->lastResponse.has_value())
{
if (this->lastRequest.has_value() && this->lastRequest->elapsed(NODE_HALFLIFE) && this->creationPoint.elapsed(NODE_HALFLIFE))
{
return true;
}
}
else if(this->lastResponse->elapsed(NODE_HALFLIFE * 2) && this->lastRequest.has_value() && this->lastRequest->after(*this->lastResponse))
{
return true;
}
return false;
}
bool Node::Entry::requiresRequest()
{
return (!this->isDead() && (!this->lastRequest.has_value() || this->lastRequest->elapsed(NODE_HALFLIFE)));
}
void Node::Entry::sendRequest()
{
if (!this->lastRequest.has_value()) this->lastRequest.emplace(Utils::Time::Point());
this->lastRequest->update();
Session::Send(this->address, "nodeListRequest");
Node::SendList(this->address);
}
void Node::Entry::reset()
{
// this->lastResponse.reset(); // This would invalidate the node, but maybe we don't want that?
this->lastRequest.reset();
}
2017-01-19 16:23:59 -05:00
void Node::LoadNodeRemotePreset()
{
std::string nodes = Utils::Cache::GetFile("/iw4/nodes.txt");
if (nodes.empty()) return;
auto nodeList = Utils::String::Explode(nodes, '\n');
2017-05-30 14:31:00 -04:00
for (auto& node : nodeList)
2017-01-19 16:23:59 -05:00
{
Utils::String::Replace(node, "\r", "");
node = Utils::String::Trim(node);
2017-06-25 15:54:35 -04:00
Node::Add(node);
2017-01-19 16:23:59 -05:00
}
}
void Node::LoadNodePreset()
{
Proto::Node::List list;
2017-02-25 09:58:43 -05:00
if (Monitor::IsEnabled())
{
std::string nodes = Utils::IO::ReadFile("players/nodes_default.dat");
if (nodes.empty() || !list.ParseFromString(Utils::Compression::Deflate::ZStd::Decompress(nodes))) return;
2017-02-25 09:58:43 -05:00
}
else
{
FileSystem::File defaultNodes("nodes_default.dat");
if (!defaultNodes.exists() || !list.ParseFromString(Utils::Compression::Deflate::ZStd::Decompress(defaultNodes.getBuffer()))) return;
2017-02-25 09:58:43 -05:00
}
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
for (int i = 0; i < list.nodes_size(); ++i)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
const std::string& addr = list.nodes(i);
if (addr.size() == sizeof(sockaddr))
{
Node::Add(reinterpret_cast<sockaddr*>(const_cast<char*>(addr.data())));
}
2017-01-19 16:23:59 -05:00
}
}
void Node::LoadNodes()
{
Proto::Node::List list;
std::string nodes = Utils::IO::ReadFile("players/nodes.dat");
if (nodes.empty() || !list.ParseFromString(Utils::Compression::Deflate::ZStd::Decompress(nodes))) return;
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
for (int i = 0; i < list.nodes_size(); ++i)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
const std::string& addr = list.nodes(i);
if (addr.size() == sizeof(sockaddr))
{
Node::Add(reinterpret_cast<sockaddr*>(const_cast<char*>(addr.data())));
}
2017-01-19 16:23:59 -05:00
}
}
2017-06-25 15:54:35 -04:00
2017-01-19 16:23:59 -05:00
void Node::StoreNodes(bool force)
{
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return;
2017-06-25 15:54:35 -04:00
static Utils::Time::Interval interval;
if (!force && !interval.elapsed(1min)) return;
2017-06-26 17:23:08 -04:00
interval.update();
2017-01-19 16:23:59 -05:00
Proto::Node::List list;
2017-07-03 09:07:47 -04:00
Node::Mutex.lock();
2017-05-30 14:31:00 -04:00
for (auto& node : Node::Nodes)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (node.isValid())
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
std::string* str = list.add_nodes();
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
sockaddr addr = node.address.getSockAddr();
str->append(reinterpret_cast<char*>(&addr), sizeof(addr));
2017-01-19 16:23:59 -05:00
}
}
2017-07-03 09:07:47 -04:00
Node::Mutex.unlock();
2017-01-19 16:23:59 -05:00
Utils::IO::WriteFile("players/nodes.dat", Utils::Compression::Deflate::ZStd::Compress(list.SerializeAsString()));
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
void Node::Add(Network::Address address)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
#ifndef DEBUG
if (address.isLocal() || address.isSelf()) return;
2017-01-19 16:23:59 -05:00
#endif
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
for (auto& session : Node::Nodes)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (session.address == address) return;
2017-01-19 16:23:59 -05:00
}
2017-02-14 08:10:57 -05:00
2017-06-25 15:54:35 -04:00
Node::Entry node;
node.address = address;
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
Node::Nodes.push_back(node);
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
void Node::RunFrame()
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return;
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
int sentRequests = 0;
for (auto i = Node::Nodes.begin(); i != Node::Nodes.end();)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (i->isDead())
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
i = Node::Nodes.erase(i);
continue;
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
else if (sentRequests < NODE_REQUEST_LIMIT && i->requiresRequest())
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
++sentRequests;
i->sendRequest();
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
++i;
}
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
void Node::Synchronize()
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
for (auto& node : Node::Nodes)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
//if (node.isValid()) // Comment out to simulate 'syncnodes' behaviour
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
node.reset();
2017-01-19 16:23:59 -05:00
}
}
}
2017-06-25 15:54:35 -04:00
void Node::HandleResponse(Network::Address address, std::string data)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
Proto::Node::List list;
if (!list.ParseFromString(data)) return;
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
for (int i = 0; i < list.nodes_size(); ++i)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
const std::string& addr = list.nodes(i);
if (addr.size() == sizeof(sockaddr))
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
Node::Add(reinterpret_cast<sockaddr*>(const_cast<char*>(addr.data())));
2017-01-19 16:23:59 -05:00
}
}
2017-06-25 15:54:35 -04:00
if (list.isnode() && (!list.port() || list.port() == address.getPort()))
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (!Dedicated::IsEnabled() && ServerList::IsOnlineList() && list.protocol() == PROTOCOL)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
ServerList::InsertRequest(address);
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
for (auto& node : Node::Nodes)
{
if (address == node.address)
{
if (!node.lastResponse.has_value()) node.lastResponse.emplace(Utils::Time::Point());
node.lastResponse->update();
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
node.data.protocol = list.protocol();
return;
}
}
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
Node::Entry entry;
entry.address = address;
entry.data.protocol = list.protocol();
entry.lastResponse.emplace(Utils::Time::Point());
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
Node::Nodes.push_back(entry);
2017-01-19 16:23:59 -05:00
}
}
2017-06-25 15:54:35 -04:00
void Node::SendList(Network::Address address)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
Proto::Node::List list;
list.set_isnode(Dedicated::IsEnabled());
list.set_protocol(PROTOCOL);
list.set_port(Node::GetPort());
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
for (auto& node : Node::Nodes)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
if (node.isValid())
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
std::string* str = list.add_nodes();
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
sockaddr addr = node.address.getSockAddr();
str->append(reinterpret_cast<char*>(&addr), sizeof(addr));
2017-01-19 16:23:59 -05:00
}
}
2017-06-25 15:54:35 -04:00
Session::Send(address, "nodeListResponse", list.SerializeAsString());
2017-01-19 16:23:59 -05:00
}
2017-06-25 15:54:35 -04:00
unsigned short Node::GetPort()
{
if (Dvar::Var("net_natFix").get<bool>()) return 0;
return Network::GetPort();
2017-01-19 16:23:59 -05:00
}
Node::Node()
{
if (ZoneBuilder::IsEnabled()) return;
2017-05-31 17:45:30 -04:00
Dvar::Register<bool>("net_natFix", false, 0, "Fix node registration for certain firewalls/routers");
2017-01-19 16:23:59 -05:00
2017-07-03 09:07:47 -04:00
Scheduler::OnFrameAsync([]()
{
Node::StoreNodes(false);
});
2017-06-25 15:54:35 -04:00
Scheduler::OnFrame(Node::RunFrame);
Session::Handle("nodeListResponse", Node::HandleResponse);
2017-06-25 18:01:58 -04:00
Session::Handle("nodeListRequest", [](Network::Address address, std::string)
{
Node::SendList(address);
});
2017-01-19 16:23:59 -05:00
// Load stored nodes
2017-02-25 09:58:43 -05:00
auto loadNodes = []()
2017-01-19 16:23:59 -05:00
{
Node::LoadNodePreset();
Node::LoadNodes();
2017-02-25 09:58:43 -05:00
};
if (Monitor::IsEnabled()) Network::OnStart(loadNodes);
else Dvar::OnInit(loadNodes);
2017-01-19 16:23:59 -05:00
2017-06-25 15:54:35 -04:00
Network::OnStart([]()
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
std::thread([]()
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
Node::LoadNodeRemotePreset();
}).detach();
2017-01-19 16:23:59 -05:00
});
Command::Add("listnodes", [](Command::Params*)
2017-01-19 16:23:59 -05:00
{
2017-06-25 15:54:35 -04:00
Logger::Print("Nodes: %d\n", Node::Nodes.size());
2017-06-25 06:44:09 -04:00
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
2017-06-25 06:44:09 -04:00
for (auto& node : Node::Nodes)
{
2017-06-25 15:54:35 -04:00
Logger::Print("%s\t(%s)\n", node.address.getCString(), node.isValid() ? "Valid" : "Invalid");
2017-06-25 06:44:09 -04:00
}
});
Command::Add("addnode", [](Command::Params* params)
2017-01-19 16:23:59 -05:00
{
if (params->length() < 2) return;
2017-06-25 15:54:35 -04:00
Node::Add({ params->get(1) });
2017-01-19 16:23:59 -05:00
});
}
Node::~Node()
{
2017-06-25 15:54:35 -04:00
std::lock_guard<std::recursive_mutex> _(Node::Mutex);
2017-01-19 16:23:59 -05:00
Node::StoreNodes(true);
2017-06-25 15:54:35 -04:00
Node::Nodes.clear();
2017-01-19 16:23:59 -05:00
}
}