Skip to content

Commit

Permalink
- isolate the lower level transmission protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
dpjudas committed Jul 16, 2019
1 parent 6587bd8 commit 8491828
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 116 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -960,6 +960,7 @@ set (PCH_SOURCES
network/netsync.cpp
network/netclient.cpp
network/netcommand.cpp
network/netnode.cpp
network/i_net.cpp
d_netinfo.cpp
d_protocol.cpp
Expand Down
123 changes: 7 additions & 116 deletions src/network/netcommand.h
Expand Up @@ -42,12 +42,15 @@ class ByteInputStream
bool IsAtEnd() const;
int BytesLeft() const;

const void* GetData() const { return mData; }
int GetSize() const { return (int)(ptrdiff_t)(pbStream - mData); }

private:
void EnsureBitSpace(int bits, bool writing);

uint8_t *mData = nullptr; // Pointer to our stream of data
uint8_t *pbStream; // Cursor position for next read.
uint8_t *pbStreamEnd; // Pointer to the end of the stream. When pbStream >= pbStreamEnd, the entire stream has been read.
uint8_t *pbStream = nullptr; // Cursor position for next read.
uint8_t *pbStreamEnd = nullptr; // Pointer to the end of the stream. When pbStream >= pbStreamEnd, the entire stream has been read.

uint8_t *bitBuffer = nullptr;
int bitShift = -1;
Expand Down Expand Up @@ -82,8 +85,8 @@ class ByteOutputStream
void EnsureBitSpace(int bits, bool writing);

uint8_t *mData = nullptr; // Pointer to our stream of data
uint8_t *pbStream; // Cursor position for next write
uint8_t *pbStreamEnd; // Pointer to the end of the data buffer
uint8_t *pbStream = nullptr; // Cursor position for next write
uint8_t *pbStreamEnd = nullptr; // Pointer to the end of the data buffer

uint8_t *bitBuffer = nullptr;
int bitShift = -1;
Expand Down Expand Up @@ -126,115 +129,3 @@ class NetCommand
void setUnreliable(bool a) { mUnreliable = a; }
int getSize() const;
};

#if 0
class NetNodeOutputStream
{
public:
void WriteCommand(std::unique_ptr<NetCommand> command, bool unreliable)
{
mMessages.push_back({ std::move(command), mSerial, unreliable });
}

void Send(doomcom_t *comm)
{
NetOutputPacket packet(mNodeIndex);
packet.stream.WriteByte(0);
packet.stream.WriteByte(mHeaderFlags);
packet.stream.WriteShort(mAck);
packet.stream.WriteShort(mSerial);

auto it = mMessages.begin();
while (it != mMessages.end())
{
const auto &msg = *it;

packet.stream.WriteShort(msg.serial);
msg.command.writeCommandToStream(packet.stream);

if (msg.unreliable)
{
it = mMessages.erase(it);
}
else
{
++it;
}
}

comm->PacketSend(packet);
mSerial++;
}

void AckPacket(uint8_t headerFlags, uint16_t serial, uint16_t ack)
{
mAck = ack;
mHeaderFlags |= 1;

if (headerFlags & 1)
{
while (!mMessages.empty() && IsLessEqual(serial, mMessages.front().serial))
{
mMessages.erase(mMessages.begin());
}
}
}

private:
bool IsLessEqual(uint16_t serialA, uint16_t serialB)
{
if (serialA <= serialB)
return serialB - serialA < 0x7fff;
else
return serialA - serialB > 0x7fff;
}

struct Entry
{
Entry(std::unique_ptr<NetCommand> command, uint16_t serial, bool unreliable) : command(std::move(command)), serial(serial), unreliable(unreliable) { }

std::unique_ptr<NetCommand> command;
uint16_t serial = 0;
bool unreliable = false;
};

int mNodeIndex = 0;
std::list<Entry> mMessages;
uint16_t mSerial = 0;
uint16_t mAck = 0;
uint8_t mHeaderFlags = 0;
};

class NetNodeInputStream
{
public:
std::unique_ptr<NetCommand> ReadCommand()
{
return nullptr;
}

void ReceivedPacket(NetInputPacket &packet, NetNodeOutputStream &outputStream)
{
packet.stream.ReadByte();
uint8_t headerFlags = packet.stream.ReadByte();
uint16_t serial = packet.stream.ReadShort();
uint16_t ack = packet.stream.ReadShort();

mPackets.push_back({ packet.stream.GetBuffer(), packet.stream.GetSize(), serial });

outputStream.AckPacket(headerFlags, ack, serial);
}

private:
struct Entry
{
Entry(const void *data, size_t size, uint16_t serial) : buffer((const uint8_t*)data, size), serial(serial) { }

std::vector<uint8_t> buffer;
uint16_t serial;
};

std::list<Entry> mPackets;
uint16_t mLastSerial = 0;
};
#endif
179 changes: 179 additions & 0 deletions src/network/netnode.cpp
@@ -0,0 +1,179 @@

#include "netnode.h"
#include "i_net.h"

void NetNodeOutput::WriteMessage(const void* data, size_t size, bool unreliable)
{
mMessages.push_back(std::make_unique<Message>(data, (int)size, mSerial, unreliable));
}

void NetNodeOutput::Send(doomcom_t* comm, int nodeIndex)
{
NetOutputPacket packet(nodeIndex);
packet.stream.WriteByte(0);
packet.stream.WriteByte(mHeaderFlags);
packet.stream.WriteShort(mAck);
packet.stream.WriteShort(mSerial);

auto it = mMessages.begin();
while (it != mMessages.end())
{
const auto& msg = *it;

packet.stream.WriteShort(msg->serial);
packet.stream.WriteShort(msg->size);
packet.stream.WriteBuffer(msg->data, msg->size);

if (msg->unreliable)
{
it = mMessages.erase(it);
}
else
{
++it;
}
}

comm->PacketSend(packet);
mSerial++;
}

void NetNodeOutput::AckPacket(uint8_t headerFlags, uint16_t serial, uint16_t ack)
{
mAck = ack;
mHeaderFlags |= 1;

if (headerFlags & 1)
{
while (!mMessages.empty() && IsLessEqual(serial, mMessages.front()->serial))
{
mMessages.erase(mMessages.begin());
}
}
}

bool NetNodeOutput::IsLessEqual(uint16_t serialA, uint16_t serialB)
{
if (serialA <= serialB)
return serialB - serialA < 0x7fff;
else
return serialA - serialB > 0x7fff;
}

/////////////////////////////////////////////////////////////////////////////

ByteInputStream NetNodeInput::ReadMessage()
{
if (!mCurrentPacket || mCurrentOffset == mCurrentPacket->size)
AdvanceToNextPacket();

if (!mCurrentPacket || mCurrentOffset == mCurrentPacket->size)
return {};

ByteInputStream header(mCurrentPacket->data + mCurrentOffset, mCurrentPacket->size - mCurrentOffset);
uint16_t serial = header.ReadShort();
uint16_t size = header.ReadShort();
if (mCurrentPacket->size - mCurrentOffset - size < 0)
return {};

ByteInputStream body(mCurrentPacket->data + mCurrentOffset + 4, size);
mCurrentOffset += 4 + size;
return body;
}

void NetNodeInput::AdvanceToNextPacket()
{
if (!mCurrentPacket)
{
mCurrentPacket = FindFirstPacket();
mCurrentOffset = 0;
}
else
{
Packet* nextPacket = FindNextPacket(mCurrentPacket);
if (nextPacket)
{
RemovePacket(mCurrentPacket);
mCurrentPacket = nextPacket;
mCurrentOffset = 0;
}
}
}

NetNodeInput::Packet* NetNodeInput::FindFirstPacket()
{
if (mPackets.empty()) return nullptr;

Packet* first = mPackets.front().get();
for (const auto& packet : mPackets)
{
int delta = SerialDiff(first->serial, packet->serial);
if (delta < 0)
first = packet.get();
}
return first;
}

NetNodeInput::Packet* NetNodeInput::FindNextPacket(Packet* current)
{
Packet* nextPacket = nullptr;
int nextDelta = 0xffff;
for (const auto& packet : mPackets)
{
int delta = SerialDiff(current->serial, packet->serial);
if (delta > 0 && delta < nextDelta)
{
nextDelta = delta;
nextPacket = packet.get();
}
}
return nextPacket;
}

void NetNodeInput::RemovePacket(Packet* packet)
{
for (auto it = mPackets.begin(); it != mPackets.end(); ++it)
{
if ((*it).get() == mCurrentPacket)
{
mPackets.erase(it);
break;
}
}
}

void NetNodeInput::ReceivedPacket(NetInputPacket& packet, NetNodeOutput& outputStream)
{
const int packetHeaderSize = 6;
uint8_t headerFlags = packet.stream.ReadByte();
uint16_t serial = packet.stream.ReadShort();
uint16_t ack = packet.stream.ReadShort();

outputStream.AckPacket(headerFlags, ack, serial);

if (mCurrentPacket)
{
// Is this a packet from the past? If so, it arrived too late.
if (SerialDiff(mCurrentPacket->serial, serial) <= 0)
return;

// Check for duplicates
for (const auto& packet : mPackets)
{
if (packet->serial == serial)
return;
}
}

mPackets.push_back(std::make_unique<Packet>(static_cast<const uint8_t*>(packet.stream.GetData()) + packetHeaderSize, packet.stream.GetSize() - packetHeaderSize, serial));
}

int NetNodeInput::SerialDiff(uint16_t serialA, uint16_t serialB)
{
int delta = static_cast<int>(serialB) - static_cast<int>(serialA);
if (delta < -0x7fff)
delta += 0xffff;
else if (delta > 0x7fff)
delta -= 0xffff;
return delta;
}
66 changes: 66 additions & 0 deletions src/network/netnode.h
@@ -0,0 +1,66 @@

#pragma once

#include <memory>
#include <list>
#include "vectors.h"
#include "netcommand.h"

struct doomcom_t;
class NetInputPacket;

class NetNodeOutput
{
public:
void WriteMessage(const void *data, size_t size, bool unreliable);
void Send(doomcom_t* comm, int nodeIndex);
void AckPacket(uint8_t headerFlags, uint16_t serial, uint16_t ack);

private:
static bool IsLessEqual(uint16_t serialA, uint16_t serialB);

struct Message
{
Message(const void* initdata, int size, uint16_t serial, bool unreliable) : data(new uint8_t[size]), size(size), serial(serial), unreliable(unreliable) { memcpy(data, initdata, size); }
~Message() { delete[] data; }

uint8_t* data;
int size;
uint16_t serial;
bool unreliable;
};

std::list<std::unique_ptr<Message>> mMessages;
uint16_t mSerial = 0;
uint16_t mAck = 0;
uint8_t mHeaderFlags = 0;
};

class NetNodeInput
{
public:
ByteInputStream ReadMessage();
void ReceivedPacket(NetInputPacket& packet, NetNodeOutput& outputStream);

private:
void AdvanceToNextPacket();
static int SerialDiff(uint16_t serialA, uint16_t serialB);

struct Packet
{
Packet(const void* initdata, int size, uint16_t serial) : data(new uint8_t[size]), size(size), serial(serial) { memcpy(data, initdata, size); }
~Packet() { delete[] data; }

uint8_t* data;
int size;
uint16_t serial;
};

Packet* FindFirstPacket();
Packet* FindNextPacket(Packet *current);
void RemovePacket(Packet* packet);

std::list<std::unique_ptr<Packet>> mPackets;
Packet* mCurrentPacket = nullptr;
int mCurrentOffset = 0;
};

0 comments on commit 8491828

Please sign in to comment.