Implement client side node synchronization.
This commit is contained in:
parent
40d6c6d715
commit
d87a6ced42
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user