Skip to content

Commit

Permalink
PacketDefragmentation: correctly move code to correct file, use vecto…
Browse files Browse the repository at this point in the history
…r instead of map, add fragmentation to ServerSideNetUdp
  • Loading branch information
JonathSpirit committed Feb 5, 2025
1 parent 64ec26d commit 562388e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 107 deletions.
3 changes: 1 addition & 2 deletions examples/clientServerLifeSimulator_004/server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
client->pushPacket(std::move(transmissionPacket));

//We will send a full scene update to the client too
transmissionPacket = fge::net::TransmissionPacket::create();
transmissionPacket->packet().setHeaderId(ls::LS_PROTOCOL_S_UPDATE_ALL);
transmissionPacket = fge::net::TransmissionPacket::create(ls::LS_PROTOCOL_S_UPDATE_ALL);
transmissionPacket->doNotDiscard();
mainScene.pack(transmissionPacket->packet(), packet->getIdentity());

Expand Down
8 changes: 4 additions & 4 deletions includes/FastEngine/network/C_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include "FastEngine/fge_extern.hpp"
#include "FastEngine/network/C_identity.hpp"
#include "FastEngine/network/C_packet.hpp"
#include <map>
#include <memory>
#include <optional>
#include <queue>
Expand Down Expand Up @@ -187,12 +186,13 @@ class PacketDefragmentation
{
Data(ProtocolPacket::RealmType id, ProtocolPacket::CounterType total) :
_id(id),
_total(total)
_count(1),
_fragments(total)
{}

ProtocolPacket::RealmType _id;
decltype(InternalFragmentedPacketData::_fragmentTotal) _total;
std::map<ProtocolPacket::CounterType, ProtocolPacketPtr> _fragments;
decltype(InternalFragmentedPacketData::_fragmentTotal) _count;
std::vector<ProtocolPacketPtr> _fragments;
};
std::vector<Data> g_data;
};
Expand Down
84 changes: 84 additions & 0 deletions sources/network/C_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,90 @@
namespace fge::net
{

//PacketDefragmentation

void PacketDefragmentation::clear()
{
this->g_data.clear();
}

PacketDefragmentation::Result PacketDefragmentation::process(ProtocolPacketPtr&& packet)
{
auto const id = packet->retrieveRealm().value();
auto const counter = packet->retrieveCounter().value();

for (auto itData = this->g_data.begin(); itData != this->g_data.end(); ++itData)
{
auto& data = *itData;
if (data._id != id)
{
continue;
}

if (counter >= data._fragments.size())
{
//Invalid fragment counter, overflows the total
this->g_data.erase(itData);
return {Results::DISCARDED, id};
}

auto& fragment = data._fragments[counter];
if (fragment != nullptr)
{
//Already received, some duplicate, discarded
this->g_data.erase(itData);
return {Results::DISCARDED, id};
}

//Insert the new fragment
fragment = std::move(packet);
++data._count;

//Check if we have all the fragments
if (data._fragments.size() == data._count)
{
return {Results::RETRIEVABLE, id};
}
return {Results::WAITING, id};
}

//New fragment
InternalFragmentedPacketData fragmentedData{};
packet->packet().unpack(ProtocolPacket::HeaderSize, &fragmentedData, sizeof(fragmentedData));

this->g_data.emplace_back(id, fragmentedData._fragmentTotal)._fragments[counter] = std::move(packet);
///TODO: remove the oldest data if the cache is full
return {Results::WAITING, id};
}
ProtocolPacketPtr PacketDefragmentation::retrieve(ProtocolPacket::RealmType id, Identity const& client)
{
for (auto itData = this->g_data.begin(); itData != this->g_data.end(); ++itData)
{
if (itData->_id == id)
{
Packet unfragmentedPacket;

for (auto const& fragment: itData->_fragments)
{
unfragmentedPacket.append(fragment->packet().getData() + ProtocolPacket::HeaderSize +
sizeof(InternalFragmentedPacketData),
fragment->packet().getDataSize() - ProtocolPacket::HeaderSize -
sizeof(InternalFragmentedPacketData));
}

unfragmentedPacket.skip(ProtocolPacket::HeaderSize);
auto unfragmentedPacketPtr = std::make_unique<ProtocolPacket>(std::move(unfragmentedPacket), client);
unfragmentedPacketPtr->setTimestamp(Client::getTimestamp_ms());

this->g_data.erase(itData);
return unfragmentedPacketPtr;
}
}
return nullptr;
}

//PacketReorderer

void PacketReorderer::clear()
{
this->g_forceRetrieve = false;
Expand Down
134 changes: 33 additions & 101 deletions sources/network/C_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,76 +21,6 @@
namespace fge::net
{

//PacketDefragmentation

void PacketDefragmentation::clear()
{
this->g_data.clear();
}

PacketDefragmentation::Result PacketDefragmentation::process(ProtocolPacketPtr&& packet)
{
auto const id = packet->retrieveRealm().value();
auto const counter = packet->retrieveCounter().value();

for (auto itData = this->g_data.begin(); itData != this->g_data.end(); ++itData)
{
auto& data = *itData;
if (data._id != id)
{
continue;
}

auto const it = data._fragments.find(counter);
if (it != data._fragments.end())
{
//Already received, some duplicate, discarded
this->g_data.erase(itData);
return {Results::DISCARDED, id};
}

//Insert the new fragment
data._fragments[counter] = std::move(packet);

//Check if we have all the fragments
if (data._fragments.size() == data._total)
{
return {Results::RETRIEVABLE, id};
}
return {Results::WAITING, id};
}

//New fragment
InternalFragmentedPacketData fragmentedData{};
packet->packet().unpack(ProtocolPacket::HeaderSize, &fragmentedData, sizeof(fragmentedData));

this->g_data.emplace_back(id, fragmentedData._fragmentTotal)._fragments[counter] = std::move(packet);
///TODO: remove the oldest data if the cache is full
return {Results::WAITING, id};
}
ProtocolPacketPtr PacketDefragmentation::retrieve(ProtocolPacket::RealmType id, Identity const& client)
{
for (auto itData = this->g_data.begin(); itData != this->g_data.end(); ++itData)
{
if (itData->_id == id)
{
Packet unfragmentedPacket;

for (auto const& fragment: itData->_fragments | std::views::values)
{
unfragmentedPacket.append(fragment->packet().getData() + ProtocolPacket::HeaderSize +
sizeof(InternalFragmentedPacketData),
fragment->packet().getDataSize() - ProtocolPacket::HeaderSize -
sizeof(InternalFragmentedPacketData));
}

this->g_data.erase(itData);
return std::make_unique<ProtocolPacket>(std::move(unfragmentedPacket), client);
}
}
return nullptr;
}

//NetCommands

NetCommandResults
Expand Down Expand Up @@ -741,6 +671,31 @@ void ServerSideNetUdp::threadTransmission()

auto transmissionPacket = itClient->second._client->popPacket();

//MTU check
auto const headerId = transmissionPacket->packet().retrieveHeaderId().value();
if (headerId != NET_INTERNAL_FRAGMENTED_PACKET)
{
//Packet is not fragmented, we have to check is size
/*if (this->g_mtu == 0) TODO
{ //We don't know the MTU yet
goto mtu_check_skip;
}*/

auto fragments = transmissionPacket->fragment(64); //TODO
for (std::size_t iFragment = 0; iFragment < fragments.size(); ++iFragment)
{
if (iFragment == 0)
{
transmissionPacket = std::move(fragments[iFragment]);
}
else
{
itClient->second._client->pushForcedFrontPacket(std::move(fragments[iFragment]));
}
}
}
//mtu_check_skip:

if (!transmissionPacket->packet() || !transmissionPacket->packet().haveCorrectHeaderSize())
{ //Last verification of the packet
continue;
Expand Down Expand Up @@ -1102,39 +1057,16 @@ void ClientSideNetUdp::threadTransmission()
goto mtu_check_skip;
}

if (transmissionPacket->packet().getDataSize() > this->g_mtu)
auto fragments = transmissionPacket->fragment(this->g_mtu);
for (std::size_t i = 0; i < fragments.size(); ++i)
{
//We have to fragment the packet
auto currentPacket = std::move(transmissionPacket);
auto const packetSize = currentPacket->packet().getDataSize();
auto const maxFragmentSize =
this->g_mtu - ProtocolPacket::HeaderSize - sizeof(InternalFragmentedPacketData);
auto const fragmentCount =
packetSize / maxFragmentSize + (packetSize % maxFragmentSize > 0 ? 1 : 0);

auto const fragmentRealm = currentPacket->packet().retrieveCounter().value();

InternalFragmentedPacketData fragmentData{};
fragmentData._fragmentTotal = fragmentCount;

for (std::size_t i = 0; i < fragmentCount; ++i)
if (i == 0)
{
auto fragmentedPacket = TransmissionPacket::create(NET_INTERNAL_FRAGMENTED_PACKET);
fragmentedPacket->packet().setCounter(i);
fragmentedPacket->packet().setRealm(fragmentRealm);

fragmentedPacket->packet().pack(&fragmentData, sizeof(fragmentData));
fragmentedPacket->packet().append(currentPacket->packet().getData() + i * maxFragmentSize,
std::min(maxFragmentSize, packetSize - i * maxFragmentSize));

if (i == 0)
{
transmissionPacket = std::move(fragmentedPacket);
}
else
{
this->_client.pushForcedFrontPacket(std::move(fragmentedPacket));
}
transmissionPacket = std::move(fragments[i]);
}
else
{
this->_client.pushForcedFrontPacket(std::move(fragments[i]));
}
}
}
Expand Down

0 comments on commit 562388e

Please sign in to comment.