157 lines
3.9 KiB
C++
157 lines
3.9 KiB
C++
/*
|
|
ZNetPeer.cpp
|
|
Author: Patrick Baggett <ptbaggett@762studios.com>
|
|
Created: 7/18/2013
|
|
|
|
Purpose:
|
|
|
|
ZNet peer class, representing a remote host
|
|
|
|
License:
|
|
|
|
Copyright 2013, 762 Studios
|
|
*/
|
|
|
|
/*************************************************************************/
|
|
|
|
#include <ZNet/ZNetPeer.hpp>
|
|
#include <ZNet/ZNetPacketChannel.hpp>
|
|
#include <ZNet/ZNetHost.hpp>
|
|
#include "ZNetPrivate.hpp"
|
|
#include <SST/SST_OS.h>
|
|
#include <new>
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
ZNetPeer::ZNetPeer()
|
|
{
|
|
lastValidIncoming = 0;
|
|
lastOutgoingAck = 0;
|
|
socketCopy = 0;
|
|
channels = NULL;
|
|
userdata = NULL;
|
|
nrChannels = 0;
|
|
ping = -1;
|
|
state = STATE_UNCONNECTED;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
bool ZNetPeer::Initialize(ZNetHost* _host, const SST_NetAddress* newAddr, SST_Socket s, uint32_t _nrChannels)
|
|
{
|
|
SST_OS_DebugAssert(_host != NULL, "Host may not be NULL");
|
|
SST_OS_DebugAssert(channels == NULL, "This should have been NULL; memory leak!");
|
|
|
|
channels = new(std::nothrow) ZNetPacketChannel[_nrChannels];
|
|
if(channels == NULL)
|
|
return false;
|
|
|
|
//Initialize channel ID (new[] doesn't allow non-default constructors)
|
|
for(uint32_t i=0; i<_nrChannels; i++)
|
|
{
|
|
channels[i].SetChannelId(i);
|
|
channels[i].SetHost(_host);
|
|
}
|
|
|
|
//Store other properties
|
|
memcpy(&addr, newAddr, sizeof(SST_NetAddress));
|
|
nrChannels = _nrChannels;
|
|
socketCopy = s;
|
|
userdata = NULL;
|
|
lastValidIncoming = SST_OS_GetMilliTime();
|
|
state = STATE_HANDSHAKE;
|
|
|
|
//OK
|
|
return true;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void ZNetPeer::Deinitialize()
|
|
{
|
|
for(uint32_t i=0; i<nrChannels; i++)
|
|
channels[i].Deinitialize();
|
|
|
|
delete[] channels;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
ZNetPacketChannel* ZNetPeer::GetPacketChannel(uint32_t chId)
|
|
{
|
|
//Really, this is trivial, but I don't want asserts to be conditional on whether
|
|
//the user of the API has enabled them vs how the library was built.
|
|
SST_OS_DebugAssert(chId < nrChannels, "Invalid channel number");
|
|
|
|
return &channels[chId];
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void ZNetPeer::ProcessLocalAcks()
|
|
{
|
|
for(uint32_t i=0; i<nrChannels; i++)
|
|
channels[i].ProcessLocalAcks();
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void ZNetPeer::SendAcksForAllChannels()
|
|
{
|
|
uint8_t data[9000];
|
|
uint32_t mtu = this->GetPacketChannel(ZNET_SYSCHANNEL)->GetHost()->GetMTU();
|
|
bool unsent = true;
|
|
|
|
uint64_t now = SST_OS_GetMilliTime();
|
|
|
|
//TODO: maybe not the best idea...? it will start out by sending an ACK 0...kinda silly I guess
|
|
if(lastOutgoingAck == 0 ||
|
|
((ping > 0) && (now > lastOutgoingAck + (uint64_t)ping) && (now - lastOutgoingAck > 50)) ) //TODO: does a minimum ack latency of 50 make any sense? in the cases where ping is realllly low (e.g. <= 1msec) don't need to spam?
|
|
{
|
|
lastOutgoingAck = now;
|
|
}
|
|
else
|
|
return;
|
|
|
|
|
|
ZBinaryBufferWriter writer(data, mtu, ZNET_BYTEORDER);
|
|
|
|
//Write the write header
|
|
ZNetPrivate::WriteWirePacketHeader(&writer);
|
|
|
|
//Write an ACK point for each channel
|
|
for(uint32_t i=0; i<nrChannels; i++)
|
|
{
|
|
ZNetPacketChannel* channel = GetPacketChannel(i);
|
|
uint32_t remain = mtu - (uint32_t)writer.GetOffset();
|
|
|
|
//Can we fit another ack?
|
|
if(remain > ZNetPrivate::WireSizeForSimpleCommand(ZNETCMD_ACK))
|
|
{
|
|
//TODO: flags??
|
|
ZNetPrivate::WriteWireMessageHeader(&writer, i, 0, ZNETCMD_ACK, 0);
|
|
|
|
writer.WriteU16(channel->GetLocalAck());
|
|
writer.WriteU16(channel->GetHighestSent());
|
|
|
|
unsent = true;
|
|
}
|
|
else
|
|
{
|
|
ZNetPrivate::SendAll(socketCopy, &addr, data, (uint32_t)writer.GetOffset());
|
|
unsent = false;
|
|
|
|
//Restart
|
|
writer.Rewind();
|
|
ZNetPrivate::WriteWirePacketHeader(&writer);
|
|
}
|
|
|
|
}
|
|
|
|
if(unsent)
|
|
ZNetPrivate::SendAll(socketCopy, &addr, data, (uint32_t)writer.GetOffset());
|
|
}
|
|
|
|
/*************************************************************************/
|