386 lines
9.8 KiB
C++
386 lines
9.8 KiB
C++
#include "ehs/io/socket/ehc/NetClientCh.h"
|
|
#include "ehs/io/socket/EHC.h"
|
|
|
|
namespace ehs
|
|
{
|
|
NetClientCh::~NetClientCh()
|
|
{
|
|
}
|
|
|
|
NetClientCh::NetClientCh()
|
|
: token{}, status(NetStatus::DISCONNECTED), queueSlot(0), deltaDuration(0.0f), deltaRate(0.0f), lastPing(0.0f),
|
|
latency(0.0f), timeout(5.0f), nextSendId(0), nextRecvId(0)
|
|
{
|
|
}
|
|
|
|
NetClientCh::NetClientCh(Str_8 name, const Version &version, Endpoint remoteEndpoint)
|
|
: NetChannel((Str_8 &&)name, version), remoteEndpoint((Endpoint &&)remoteEndpoint), token{},
|
|
status(NetStatus::DISCONNECTED), queueSlot(0), deltaDuration(0.0f), deltaRate(0.0f), lastPing(0.0f),
|
|
latency(0.0f), timeout(0.0f), nextSendId(0), nextRecvId(0)
|
|
{
|
|
}
|
|
|
|
NetClientCh::NetClientCh(NetClientCh &&client) noexcept
|
|
: NetChannel((NetChannel &&)client), remoteEndpoint((Endpoint &&)client.remoteEndpoint), token{},
|
|
status(client.status), queueSlot(client.queueSlot), deltaDuration(0.0f), deltaRate(0.0f), lastPing(0.0f),
|
|
latency(0.0f), timeout(0.0f), nextSendId(0), sent((Vector<Insurance> &&)client.sent), nextRecvId(0),
|
|
received((Vector<NetFrag> &&)client.received)
|
|
{
|
|
Util::Copy(token, client.token, 64);
|
|
|
|
Util::Zero(client.token, 64);
|
|
client.status = NetStatus::DISCONNECTED;
|
|
client.queueSlot = 0;
|
|
client.deltaDuration = 0.0f;
|
|
client.deltaRate = 0.0f;
|
|
client.lastPing = 0.0f;
|
|
client.latency = 0.0f;
|
|
client.timeout = 0.0f;
|
|
client.nextSendId = 0;
|
|
client.nextRecvId = 0;
|
|
}
|
|
|
|
NetClientCh::NetClientCh(const NetClientCh &client)
|
|
: NetChannel(client), remoteEndpoint(client.remoteEndpoint), token{}, status(NetStatus::DISCONNECTED),
|
|
queueSlot(0), deltaDuration(0.0f), deltaRate(0.0f), lastPing(0.0f), latency(0.0f), timeout(0.0f), nextSendId(0),
|
|
nextRecvId(0)
|
|
{
|
|
}
|
|
|
|
NetClientCh & NetClientCh::operator=(NetClientCh &&client) noexcept
|
|
{
|
|
if (this == &client)
|
|
return *this;
|
|
|
|
NetChannel::operator=((NetChannel &&)client);
|
|
|
|
remoteEndpoint = (Endpoint &&)client.remoteEndpoint;
|
|
Util::Copy(token, client.token, 64);
|
|
status = client.status;
|
|
queueSlot = client.queueSlot;
|
|
deltaDuration = client.deltaDuration;
|
|
deltaRate = client.deltaRate;
|
|
lastPing = client.lastPing;
|
|
latency = client.latency;
|
|
timeout = client.timeout;
|
|
nextSendId = client.nextSendId;
|
|
sent = (Vector<Insurance> &&)client.sent;
|
|
nextRecvId = client.nextRecvId;
|
|
received = (Vector<NetFrag> &&)client.received;
|
|
|
|
Util::Zero(client.token, 64);
|
|
client.status = NetStatus::DISCONNECTED;
|
|
client.queueSlot = 0;
|
|
client.deltaDuration = 0.0f;
|
|
client.deltaRate = 0.0f;
|
|
client.lastPing = 0.0f;
|
|
client.latency = 0.0f;
|
|
client.timeout = 0.0f;
|
|
client.nextSendId = 0;
|
|
client.nextRecvId = 0;
|
|
|
|
return *this;
|
|
}
|
|
|
|
NetClientCh & NetClientCh::operator=(const NetClientCh &client)
|
|
{
|
|
if (this == &client)
|
|
return *this;
|
|
|
|
remoteEndpoint = client.remoteEndpoint;
|
|
Util::Zero(token, 64);
|
|
status = NetStatus::DISCONNECTED;
|
|
queueSlot = 0;
|
|
deltaDuration = 0.0f;
|
|
deltaRate = 0.0f;
|
|
lastPing = 0.0f;
|
|
latency = 0.0f;
|
|
timeout = 0.0f;
|
|
nextSendId = 0;
|
|
sent = {};
|
|
nextRecvId = 0;
|
|
received = {};
|
|
|
|
return *this;
|
|
}
|
|
|
|
void NetClientCh::OnConnected(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::OnActive(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::OnQueueUpdate(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::OnDisconnected(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::OnRejected(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::OnTimeout(Serializer<UInt_64> data)
|
|
{
|
|
}
|
|
|
|
void NetClientCh::Connect(const Endpoint &endpoint, const Serializer<UInt_64> &payload)
|
|
{
|
|
if (!GetOwner()->udp.IsValid())
|
|
return;
|
|
|
|
Send(false, true, false, internalSys, connectOp, payload);
|
|
|
|
status = NetStatus::PENDING;
|
|
}
|
|
|
|
bool NetClientCh::Disconnect(const Serializer<UInt_64> &payload)
|
|
{
|
|
if (!GetOwner()->udp.IsValid())
|
|
return false;
|
|
|
|
Send(false, true, false, internalSys, disconnectOp, payload);
|
|
|
|
return true;
|
|
}
|
|
|
|
void NetClientCh::Send(const bool deltaLocked, UInt_64 encId, const bool ensure, UInt_64 sysId, UInt_64 opId,
|
|
const Serializer<UInt_64> &payload)
|
|
{
|
|
if (!IsValid() || (deltaLocked && deltaDuration < deltaRate))
|
|
return;
|
|
|
|
const EHC *owner = GetOwner();
|
|
|
|
NetEnc *enc = owner->GetEncryption(encId);
|
|
if (!enc)
|
|
{
|
|
EHS_LOG_INT(LogType::WARN, 0, "Encryption with the Id, \"" + Str_8::FromNum(encId) + "\", does not exist.");
|
|
|
|
return;
|
|
}
|
|
|
|
Header header = {
|
|
EHC::GetVersion(),
|
|
encId,
|
|
enc->GetVersion(),
|
|
GetId(),
|
|
NetChannelType::SERVER,
|
|
GetVersion(),
|
|
nextSendId++,
|
|
1,
|
|
0,
|
|
ensure,
|
|
"",
|
|
sysId,
|
|
opId
|
|
};
|
|
|
|
Util::Copy(header.token, token, 64);
|
|
|
|
const Endpoint localEndpoint = owner->GetLocalEndpoint();
|
|
|
|
if ((localEndpoint.version == IP::V6 && payload.Size() > EHC_IPV6_PAYLOAD) || (localEndpoint.version == IP::V4 && payload.Size() > EHC_IPV4_PAYLOAD))
|
|
{
|
|
NetFrag frags = FragmentData(localEndpoint.version, header, payload);
|
|
for (UInt_64 i = 0; i < frags.Size(); ++i)
|
|
{
|
|
Header newHeader = frags.GetHeader();
|
|
newHeader.fragment = i;
|
|
|
|
Send(enc, newHeader, frags[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Send(enc, header, payload);
|
|
}
|
|
}
|
|
|
|
void NetClientCh::Send(const bool deltaLocked, const Str_8 &encName, const bool ensure, const Str_8 &sysName,
|
|
const Str_8 &opName, const Serializer<UInt_64> &payload)
|
|
{
|
|
Send(deltaLocked, encName.Hash_64(), ensure, sysName.Hash_64(), opName.Hash_64(), payload);
|
|
}
|
|
|
|
NetStatus NetClientCh::GetStatus() const
|
|
{
|
|
return status;
|
|
}
|
|
|
|
void NetClientCh::Process(const float &delta, const Endpoint &endpoint, const Header &header, Serializer<UInt_64> &payload)
|
|
{
|
|
if (!Util::Compare(token, header.token, 64))
|
|
return;
|
|
|
|
if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == connectedOp)
|
|
{
|
|
if (status != NetStatus::PENDING)
|
|
return;
|
|
|
|
Util::Copy(token, header.token, 64);
|
|
|
|
status = payload.Read<NetStatus>();
|
|
queueSlot = payload.Read<UInt_64>();
|
|
|
|
OnConnected({Endianness::LE, &payload[payload.GetOffset()], payload.Size() - payload.GetOffset()});
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == disconnectedOp)
|
|
{
|
|
OnDisconnected({Endianness::LE, &payload[payload.GetOffset()], payload.Size() - payload.GetOffset()});
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == rejectedOp)
|
|
{
|
|
OnRejected({Endianness::LE, &payload[payload.GetOffset()], payload.Size() - payload.GetOffset()});
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == statusUpdateOp)
|
|
{
|
|
const NetStatus newStatus = payload.Read<NetStatus>();
|
|
queueSlot = payload.Read<UInt_64>();
|
|
|
|
if (status == NetStatus::ACTIVE)
|
|
OnActive({Endianness::LE, &payload[payload.GetOffset()], payload.Size() - payload.GetOffset()});
|
|
else if (status == NetStatus::QUEUED && newStatus == NetStatus::QUEUED)
|
|
OnQueueUpdate({Endianness::LE, &payload[payload.GetOffset()], payload.Size() - payload.GetOffset()});
|
|
|
|
status = newStatus;
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == receivedOp)
|
|
{
|
|
const UInt_64 msgId = payload.Read<UInt_64>();
|
|
const UInt_64 fragment = payload.Read<UInt_64>();
|
|
|
|
RemoveInsurance(msgId, fragment);
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == pingOp)
|
|
{
|
|
deltaRate = payload.Read<float>();
|
|
|
|
Pong(delta);
|
|
}
|
|
else if (!header.ensure && header.token[0] && header.systemId == internalSys && header.opId == latencyOp)
|
|
{
|
|
latency = payload.Read<float>();
|
|
}
|
|
}
|
|
|
|
void NetClientCh::Poll(const float &delta)
|
|
{
|
|
}
|
|
|
|
NetFrag NetClientCh::FragmentData(const IP version, const Header& header, const Serializer<>& data)
|
|
{
|
|
NetFrag result;
|
|
|
|
if (version == IP::V6)
|
|
{
|
|
UInt_64 frags = data.Size() / EHC_IPV6_PAYLOAD;
|
|
if (data.Size() % EHC_IPV6_PAYLOAD)
|
|
++frags;
|
|
|
|
result = NetFrag(header, frags);
|
|
|
|
UInt_64 size = EHC_IPV6_PAYLOAD;
|
|
|
|
for (UInt_64 i = 0; i < result.Size(); ++i)
|
|
{
|
|
size = EHC_IPV6_PAYLOAD;
|
|
if (i == result.Size() - 1)
|
|
size = data.Size() % EHC_IPV6_PAYLOAD;
|
|
|
|
result[i] = {data.GetEndianness(), &data[i * EHC_IPV6_PAYLOAD], size};
|
|
}
|
|
}
|
|
else if (version == IP::V4)
|
|
{
|
|
UInt_64 frags = data.Size() / EHC_IPV4_PAYLOAD;
|
|
if (data.Size() % EHC_IPV4_PAYLOAD)
|
|
++frags;
|
|
|
|
result = NetFrag(header, frags);
|
|
|
|
UInt_64 size = EHC_IPV4_PAYLOAD;
|
|
|
|
for (UInt_64 i = 0; i < result.Size(); ++i)
|
|
{
|
|
size = EHC_IPV4_PAYLOAD;
|
|
if (i == result.Size() - 1)
|
|
size = data.Size() % EHC_IPV4_PAYLOAD;
|
|
|
|
result[i] = {data.GetEndianness(), &data[i * EHC_IPV4_PAYLOAD], size};
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void NetClientCh::Send(NetEnc *enc, const Header& header, const Serializer<UInt_64>& payload)
|
|
{
|
|
Serializer result(Endianness::LE);
|
|
result.Write(header);
|
|
result.WriteSer(payload);
|
|
|
|
enc->Encrypt(&result[sizeof(bool)], result.Size() - sizeof(bool));
|
|
|
|
if (header.ensure)
|
|
sent.Push({header, payload});
|
|
|
|
GetOwner()->udp.Send(remoteEndpoint, result, result.Size());
|
|
}
|
|
|
|
void NetClientCh::Pong(const float delta)
|
|
{
|
|
Serializer payload(Endianness::LE);
|
|
payload.Write(delta);
|
|
|
|
Send(false, true, false, internalSys, pongOp, payload);
|
|
|
|
timeout = 0.0f;
|
|
}
|
|
|
|
void NetClientCh::RemoveInsurance(const UInt_64 msgId, const UInt_64 fragment)
|
|
{
|
|
for (UInt_64 i = 0; i < sent.Size(); ++i)
|
|
{
|
|
if (sent[i].header.id == msgId && sent[i].header.fragment == fragment)
|
|
{
|
|
sent.Remove(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
timeout = 0.0f;
|
|
}
|
|
|
|
void NetClientCh::AddReceived(const Header& header, const Serializer<>& payload)
|
|
{
|
|
NetFrag* frags = nullptr;
|
|
|
|
for (UInt_64 i = 0; i < received.Size(); ++i)
|
|
{
|
|
if (received[i].GetHeader().id == header.id)
|
|
{
|
|
if (received[i][header.fragment].Size())
|
|
return;
|
|
|
|
frags = &received[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (header.id > nextRecvId)
|
|
nextRecvId = header.id + 1;
|
|
|
|
if (frags)
|
|
(*frags)[header.fragment] = payload;
|
|
else
|
|
received.Push({header, payload});
|
|
|
|
timeout = 0.0f;
|
|
}
|
|
}
|