Implement client side node synchronization.

This commit is contained in:
momo5502 2016-02-10 01:22:00 +01:00
parent 40d6c6d715
commit d87a6ced42
5 changed files with 72 additions and 53 deletions

View File

@ -50,7 +50,7 @@ namespace Components
Node::NodeEntry* Node::FindNode(Network::Address address) Node::NodeEntry* Node::FindNode(Network::Address address)
{ {
for (auto i = Node::Nodes.begin(); i != Node::Nodes.end(); i++) for (auto i = Node::Nodes.begin(); i != Node::Nodes.end(); ++i)
{ {
if (i->address == address) if (i->address == address)
{ {
@ -63,7 +63,7 @@ namespace Components
} }
Node::ClientSession* Node::FindSession(Network::Address address) Node::ClientSession* Node::FindSession(Network::Address address)
{ {
for (auto i = Node::Sessions.begin(); i != Node::Sessions.end(); i++) for (auto i = Node::Sessions.begin(); i != Node::Sessions.end(); ++i)
{ {
if (i->address == address) if (i->address == address)
{ {
@ -105,13 +105,13 @@ namespace Components
void Node::SendNodeList(Network::Address address) void Node::SendNodeList(Network::Address address)
{ {
if (address.IsSelf() || !Dedicated::IsDedicated()) return; if (address.IsSelf()) return;
std::vector<Node::AddressEntry> entries; std::vector<Node::AddressEntry> entries;
for (auto entry : Node::Nodes) for (auto entry : Node::Nodes)
{ {
if (entry.state == Node::STATE_VALID && entry.registered) // Only send valid nodes, or shall we send invalid ones as well? if (entry.state == Node::STATE_VALID && entry.registered)
{ {
Node::AddressEntry thisAddress; Node::AddressEntry thisAddress;
thisAddress.fromNetAddress(entry.address); thisAddress.fromNetAddress(entry.address);
@ -122,7 +122,7 @@ namespace Components
if (entries.size() >= NODE_PACKET_LIMIT) if (entries.size() >= NODE_PACKET_LIMIT)
{ {
std::string packet = "nodeListResponse\n"; std::string packet = "nodeListResponse\n";
packet.append("\x01", 1); // Yes, we are a dedi packet.append((Dedicated::IsDedicated() ? "\x01" : "\0"), 1);
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry)); packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
Network::SendRaw(address, packet); Network::SendRaw(address, packet);
@ -132,7 +132,7 @@ namespace Components
} }
std::string packet = "nodeListResponse\n"; std::string packet = "nodeListResponse\n";
packet.append("\x01", 1); // Yes, we are a dedi packet.append((Dedicated::IsDedicated() ? "\x01" : "\0"), 1);
packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry)); packet.append(reinterpret_cast<char*>(entries.data()), entries.size() * sizeof(Node::AddressEntry));
Network::SendRaw(address, packet); Network::SendRaw(address, packet);
@ -144,11 +144,11 @@ namespace Components
for (auto session : Node::Sessions) for (auto session : Node::Sessions)
{ {
if (session.terminated) continue; if (session.lastTime > 0 && (Game::Com_Milliseconds() - session.lastTime) <= SESSION_TIMEOUT)
if ((Game::Com_Milliseconds() - session.lastTime) > SESSION_TIMEOUT) return; {
cleanSessions.push_back(session); cleanSessions.push_back(session);
} }
}
if (cleanSessions.size() != Node::Sessions.size()) if (cleanSessions.size() != Node::Sessions.size())
{ {
@ -232,7 +232,8 @@ namespace Components
Utils::Message::WriteBuffer(data, node.challenge); Utils::Message::WriteBuffer(data, node.challenge);
Logger::Print("Sending registration request to %s\n", node.address.GetString()); Logger::Print("Sending registration request to %s\n", node.address.GetString());
Network::SendRaw(node.address, "nodeRegisterRequest\n" + data); } Network::SendRaw(node.address, "nodeRegisterRequest\n" + data);
}
else else
{ {
Logger::Print("Sending session request to %s\n", node.address.GetString()); Logger::Print("Sending session request to %s\n", node.address.GetString());
@ -441,8 +442,8 @@ namespace Components
Node::ClientSession* session = Node::FindSession(address); Node::ClientSession* session = Node::FindSession(address);
if (session) if (session)
{ {
allowed = (session->valid && !session->terminated); session->lastTime = Game::Com_Milliseconds();
session->terminated = true; allowed = session->valid;
} }
} }
@ -453,10 +454,35 @@ namespace Components
else else
{ {
// Unallowed connection // Unallowed connection
Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetString());
Network::Send(address, "nodeListError\n"); Network::Send(address, "nodeListError\n");
} }
}); });
Network::Handle("nodeDeregister", [] (Network::Address address, std::string data)
{
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry || !entry->registered) return;
std::string challenge, signature;
if (!Utils::Message::ReadBuffer(data, challenge)) return;
if (!Utils::Message::ReadBuffer(data, signature)) return;
if (Utils::Cryptography::ECDSA::VerifyMessage(entry->publicKey, challenge, signature))
{
entry->lastHeard = Game::Com_Milliseconds();
entry->lastTime = Game::Com_Milliseconds();
entry->registered = false;
entry->state = Node::STATE_INVALID;
Logger::Print("Node %s unregistered\n", address.GetString());
}
else
{
Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetString());
}
});
Network::Handle("sessionRequest", [] (Network::Address address, std::string data) Network::Handle("sessionRequest", [] (Network::Address address, std::string data)
{ {
// Return if we already have a session for this address // Return if we already have a session for this address
@ -468,7 +494,6 @@ namespace Components
session.address = address; session.address = address;
session.challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt()); session.challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
session.lastTime = Game::Com_Milliseconds(); session.lastTime = Game::Com_Milliseconds();
session.terminated = false;
session.valid = false; session.valid = false;
Node::Sessions.push_back(session); Node::Sessions.push_back(session);
@ -480,7 +505,7 @@ namespace Components
{ {
// Return if we don't have a session for this address // Return if we don't have a session for this address
Node::ClientSession* session = Node::FindSession(address); Node::ClientSession* session = Node::FindSession(address);
if (!session || session->terminated || session->valid) return; if (!session || session->valid) return;
if (session->challenge == data) if (session->challenge == data)
{ {
@ -490,8 +515,8 @@ namespace Components
} }
else else
{ {
session->lastTime = -1;
Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetString()); Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetString());
session->terminated = true;
} }
}); });
} }
@ -513,12 +538,13 @@ namespace Components
Node::NodeEntry* entry = Node::FindNode(address); Node::NodeEntry* entry = Node::FindNode(address);
if (!entry) return; if (!entry) return;
Logger::Print("Session acknowledged, requesting node list...\n", address.GetString());
entry->state = Node::STATE_VALID; entry->state = Node::STATE_VALID;
entry->registered = true; entry->registered = true;
entry->lastTime = Game::Com_Milliseconds(); entry->lastTime = Game::Com_Milliseconds();
Logger::Print("Session acknowledged, synchronizing node list...\n", address.GetString());
Network::Send(address, "nodeListRequest\n"); Network::Send(address, "nodeListRequest\n");
Node::SendNodeList(address);
}); });
} }
@ -554,7 +580,18 @@ namespace Components
} }
else else
{ {
Node::AddNode(address); //Node::AddNode(address);
Node::ClientSession* session = Node::FindSession(address);
if (session && session->valid)
{
session->lastTime = Game::Com_Milliseconds();
for (unsigned int i = 0; i < size; ++i)
{
Node::AddNode(addresses[i].toNetAddress());
}
}
} }
}); });
@ -585,30 +622,6 @@ namespace Components
} }
}); });
Network::Handle("nodeDeregister", [] (Network::Address address, std::string data)
{
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry || !entry->registered) return;
std::string challenge, signature;
if (!Utils::Message::ReadBuffer(data, challenge)) return;
if (!Utils::Message::ReadBuffer(data, signature)) return;
if (Utils::Cryptography::ECDSA::VerifyMessage(entry->publicKey, challenge, signature))
{
entry->lastHeard = Game::Com_Milliseconds();
entry->lastTime = Game::Com_Milliseconds();
entry->registered = false;
entry->state = Node::STATE_INVALID;
Logger::Print("Node %s unregistered\n", address.GetString());
}
else
{
Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetString());
}
});
Command::Add("listnodes", [] (Command::Params params) Command::Add("listnodes", [] (Command::Params params)
{ {
Logger::Print("Nodes: %d\n", Node::Nodes.size()); Logger::Print("Nodes: %d\n", Node::Nodes.size());
@ -625,6 +638,13 @@ namespace Components
Network::Address address(params[1]); Network::Address address(params[1]);
Node::AddNode(address); Node::AddNode(address);
Node::NodeEntry* entry = Node::FindNode(address);
if (entry)
{
entry->state = Node::STATE_UNKNOWN;
entry->registered = false;
}
}); });
// Install frame handlers // Install frame handlers
@ -655,7 +675,7 @@ namespace Components
printf("Success\n"); printf("Success\n");
printf("Testing 10 valid signatures..."); printf("Testing 10 valid signatures...");
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; ++i)
{ {
std::string message = Utils::VA("%d", Utils::Cryptography::Rand::GenerateInt()); std::string message = Utils::VA("%d", Utils::Cryptography::Rand::GenerateInt());
std::string signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, message); std::string signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, message);
@ -671,7 +691,7 @@ namespace Components
printf("Success\n"); printf("Success\n");
printf("Testing 10 invalid signatures..."); printf("Testing 10 invalid signatures...");
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; ++i)
{ {
std::string message = Utils::VA("%d", Utils::Cryptography::Rand::GenerateInt()); std::string message = Utils::VA("%d", Utils::Cryptography::Rand::GenerateInt());
std::string signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, message); std::string signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, message);

View File

@ -41,7 +41,6 @@ namespace Components
int lastListQuery; // Last time we got the list of the node int lastListQuery; // Last time we got the list of the node
// This is only relevant for clients // This is only relevant for clients
// Other nodes or dedis don't need to know if the entry is a dedi or not.
bool isDedi; bool isDedi;
}; };
@ -50,7 +49,7 @@ namespace Components
Network::Address address; Network::Address address;
std::string challenge; std::string challenge;
bool valid; bool valid;
bool terminated; //bool terminated; // Sessions can't explicitly be terminated, they can only timeout
int lastTime; int lastTime;
}; };

View File

@ -41,7 +41,7 @@ namespace Components
// This whole procedure is potentially unsafe. // This whole procedure is potentially unsafe.
// If any index changes, everything gets shifted and the stats are fucked. // If any index changes, everything gets shifted and the stats are fucked.
int lastIndex = 0; int lastIndex = 0;
for (int i = 0; i < dataEnum->numIndices; i++) for (int i = 0; i < dataEnum->numIndices; ++i)
{ {
if (dataEnum->indices[i].index > lastIndex) if (dataEnum->indices[i].index > lastIndex)
{ {
@ -56,7 +56,7 @@ namespace Components
StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(StructuredData::IndexCount[type]); StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(StructuredData::IndexCount[type]);
memcpy(StructuredData::Indices[type], dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices); memcpy(StructuredData::Indices[type], dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices);
for (unsigned int i = 0; i < entries.size(); i++) for (unsigned int i = 0; i < entries.size(); ++i)
{ {
unsigned int pos = 0; unsigned int pos = 0;
@ -129,7 +129,7 @@ namespace Components
if (data) if (data)
{ {
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); i++) for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i)
{ {
if (StructuredData::Entries[i].size()) if (StructuredData::Entries[i].size())
{ {
@ -164,7 +164,7 @@ namespace Components
StructuredData::~StructuredData() StructuredData::~StructuredData()
{ {
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); i++) for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i)
{ {
StructuredData::Entries[i].clear(); StructuredData::Entries[i].clear();
} }

View File

@ -271,7 +271,7 @@ namespace Game
char* zoneIndices = reinterpret_cast<char*>(0x16B8A34); char* zoneIndices = reinterpret_cast<char*>(0x16B8A34);
char* zoneData = reinterpret_cast<char*>(0x14C0F80); char* zoneData = reinterpret_cast<char*>(0x14C0F80);
for (int i = 0; i < zoneCount; i++) for (int i = 0; i < zoneCount; ++i)
{ {
std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF); std::string name = zoneData + 4 + 0xA4 * (zoneIndices[i] & 0xFF);

View File

@ -35,7 +35,7 @@ namespace Utils
{ {
char* memArr = reinterpret_cast<char*>(mem); char* memArr = reinterpret_cast<char*>(mem);
for (size_t i = 0; i < length; i++) for (size_t i = 0; i < length; ++i)
{ {
if (memArr[i] != chr) if (memArr[i] != chr)
{ {