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)
{
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)
{
@ -63,7 +63,7 @@ namespace Components
}
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)
{
@ -105,13 +105,13 @@ namespace Components
void Node::SendNodeList(Network::Address address)
{
if (address.IsSelf() || !Dedicated::IsDedicated()) return;
if (address.IsSelf()) return;
std::vector<Node::AddressEntry> entries;
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;
thisAddress.fromNetAddress(entry.address);
@ -122,7 +122,7 @@ namespace Components
if (entries.size() >= NODE_PACKET_LIMIT)
{
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));
Network::SendRaw(address, packet);
@ -132,7 +132,7 @@ namespace Components
}
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));
Network::SendRaw(address, packet);
@ -144,10 +144,10 @@ namespace Components
for (auto session : Node::Sessions)
{
if (session.terminated) continue;
if ((Game::Com_Milliseconds() - session.lastTime) > SESSION_TIMEOUT) return;
cleanSessions.push_back(session);
if (session.lastTime > 0 && (Game::Com_Milliseconds() - session.lastTime) <= SESSION_TIMEOUT)
{
cleanSessions.push_back(session);
}
}
if (cleanSessions.size() != Node::Sessions.size())
@ -232,7 +232,8 @@ namespace Components
Utils::Message::WriteBuffer(data, node.challenge);
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
{
Logger::Print("Sending session request to %s\n", node.address.GetString());
@ -441,8 +442,8 @@ namespace Components
Node::ClientSession* session = Node::FindSession(address);
if (session)
{
allowed = (session->valid && !session->terminated);
session->terminated = true;
session->lastTime = Game::Com_Milliseconds();
allowed = session->valid;
}
}
@ -453,10 +454,35 @@ namespace Components
else
{
// Unallowed connection
Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetString());
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)
{
// Return if we already have a session for this address
@ -468,7 +494,6 @@ namespace Components
session.address = address;
session.challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
session.lastTime = Game::Com_Milliseconds();
session.terminated = false;
session.valid = false;
Node::Sessions.push_back(session);
@ -480,7 +505,7 @@ namespace Components
{
// Return if we don't have a session for this address
Node::ClientSession* session = Node::FindSession(address);
if (!session || session->terminated || session->valid) return;
if (!session || session->valid) return;
if (session->challenge == data)
{
@ -490,8 +515,8 @@ namespace Components
}
else
{
session->lastTime = -1;
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);
if (!entry) return;
Logger::Print("Session acknowledged, requesting node list...\n", address.GetString());
entry->state = Node::STATE_VALID;
entry->registered = true;
entry->lastTime = Game::Com_Milliseconds();
Logger::Print("Session acknowledged, synchronizing node list...\n", address.GetString());
Network::Send(address, "nodeListRequest\n");
Node::SendNodeList(address);
});
}
@ -554,7 +580,18 @@ namespace Components
}
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)
{
Logger::Print("Nodes: %d\n", Node::Nodes.size());
@ -625,6 +638,13 @@ namespace Components
Network::Address address(params[1]);
Node::AddNode(address);
Node::NodeEntry* entry = Node::FindNode(address);
if (entry)
{
entry->state = Node::STATE_UNKNOWN;
entry->registered = false;
}
});
// Install frame handlers
@ -655,7 +675,7 @@ namespace Components
printf("Success\n");
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 signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, message);
@ -671,7 +691,7 @@ namespace Components
printf("Success\n");
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 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
// 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;
};
@ -50,7 +49,7 @@ namespace Components
Network::Address address;
std::string challenge;
bool valid;
bool terminated;
//bool terminated; // Sessions can't explicitly be terminated, they can only timeout
int lastTime;
};

View File

@ -41,7 +41,7 @@ namespace Components
// This whole procedure is potentially unsafe.
// If any index changes, everything gets shifted and the stats are fucked.
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)
{
@ -56,7 +56,7 @@ namespace Components
StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(StructuredData::IndexCount[type]);
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;
@ -129,7 +129,7 @@ namespace Components
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())
{
@ -164,7 +164,7 @@ namespace Components
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();
}

View File

@ -271,7 +271,7 @@ namespace Game
char* zoneIndices = reinterpret_cast<char*>(0x16B8A34);
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);

View File

@ -35,7 +35,7 @@ namespace Utils
{
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)
{