From 7bd8feff5db49095f5400efc3eb08488e98a04af Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 3 Feb 2016 20:10:54 +0100 Subject: [PATCH] Implement node serverlist for the client. --- src/Components/Modules/Node.cpp | 232 +++++++++++++++----------- src/Components/Modules/Node.hpp | 6 + src/Components/Modules/ServerList.cpp | 13 ++ 3 files changed, 158 insertions(+), 93 deletions(-) diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 9a661eff..d97b824e 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -214,6 +214,21 @@ namespace Components } } + std::vector Node::GetDediList() + { + std::vector dedis; + + for (auto dedi : Node::Dedis) + { + if (dedi.state == Node::STATE_VALID) + { + dedis.push_back(dedi.address); + } + } + + return dedis; + } + void Node::DeleteInvalidNodes() { std::vector cleanNodes; @@ -237,6 +252,92 @@ namespace Components } } + 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) + { + if (heartbeatCount < HEARTBEATS_FRAME_LIMIT && (!node.lastHeartbeat || (Game::Com_Milliseconds() - node.lastHeartbeat) >(HEARTBEAT_INTERVAL))) + { + 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(); + + count = 0; + } + void Node::DeleteInvalidDedis() { std::vector cleanDedis; @@ -260,10 +361,33 @@ namespace Components } } + 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 ""; + } + Node::Node() { Assert_Size(Node::AddressEntry, 6); + // ZoneBuilder doesn't require node stuff + if (ZoneBuilder::IsEnabled()) return; + Dvar::OnInit([] () { Node::Dedis.clear(); @@ -282,16 +406,17 @@ namespace Components }); } - Network::Handle("nodeRequestLists", [] (Network::Address address, std::string data) + // Only dedis act as nodes! + if (Dedicated::IsDedicated()) { - Logger::Print("Sending our lists to %s\n", address.GetString()); + Network::Handle("nodeRequestLists", [] (Network::Address address, std::string data) + { + Logger::Print("Sending our lists to %s\n", address.GetString()); - // Consider this a node for now! - //Node::AddNode(address, true); - - Node::SendNodeList(address); - Node::SendDediList(address); - }); + Node::SendNodeList(address); + Node::SendDediList(address); + }); + } Network::Handle("nodeNodeList", [] (Network::Address address, std::string data) { @@ -366,96 +491,13 @@ namespace Components } }); - Dedicated::OnFrame([] () - { - 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 - 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 (node.state == Node::STATE_VALID) - { - if (heartbeatCount < HEARTBEATS_FRAME_LIMIT && (!node.lastHeartbeat || (Game::Com_Milliseconds() - node.lastHeartbeat) >(HEARTBEAT_INTERVAL))) - { - 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(); - - count = 0; - }); - Command::Add("listnodes", [] (Command::Params params) { Logger::Print("Nodes: %d\n", Node::Nodes.size()); for (auto node : Node::Nodes) { - Logger::Print("%s\n", node.address.GetString()); + Logger::Print("%s\t(%s)\n", node.address.GetString(), Node::GetStateName(node.state)); } }); @@ -465,7 +507,7 @@ namespace Components for (auto dedi : Node::Dedis) { - Logger::Print("%s\n", dedi.address.GetString()); + Logger::Print("%s\t(%s)\n", dedi.address.GetString(), Node::GetStateName(dedi.state)); } }); @@ -508,6 +550,10 @@ namespace Components } } }); + + // Install frame handlers + Dedicated::OnFrame(Node::FrameHandler); + Renderer::OnFrame(Node::FrameHandler); } Node::~Node() diff --git a/src/Components/Modules/Node.hpp b/src/Components/Modules/Node.hpp index af24ad71..aaa8e2f4 100644 --- a/src/Components/Modules/Node.hpp +++ b/src/Components/Modules/Node.hpp @@ -28,6 +28,8 @@ namespace Components static void ValidateDedi(Network::Address address, Utils::InfoString info); + static std::vector GetDediList(); + private: enum EntryState { @@ -94,5 +96,9 @@ namespace Components static void DeleteInvalidNodes(); static void DeleteInvalidDedis(); + + static void FrameHandler(); + + static const char* GetStateName(EntryState state); }; } diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index d15d79f3..4117033e 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -213,6 +213,7 @@ namespace Components } else if (ServerList::IsOnlineList()) { +#ifdef USE_LEGACY_SERVER_LIST ServerList::RefreshContainer.AwatingList = true; ServerList::RefreshContainer.AwaitTime = Game::Com_Milliseconds(); @@ -225,6 +226,18 @@ namespace Components Network::Send(ServerList::RefreshContainer.Host, Utils::VA("getservers IW4 %i full empty", PROTOCOL)); //Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n"); +#else + ServerList::RefreshContainer.Mutex.lock(); + + auto dedis = Node::GetDediList(); + + for (auto dedi : dedis) + { + ServerList::InsertRequest(dedi, false); + } + + ServerList::RefreshContainer.Mutex.unlock(); +#endif } else if (ServerList::IsFavouriteList()) {