Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

268
ZNet/ZNetClient.cpp Normal file
View File

@@ -0,0 +1,268 @@
/*
ZNetClient.cpp
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 7/18/2013
Purpose:
ZNetClient -- extends ZNetHost to provide a client
License:
Copyright 2013, 762 Studios
*/
#include <ZNet/ZNetClient.hpp>
#include <ZNet/ZNetPacket.hpp>
#include <SST/SST_Assert.h>
#include <SST/SST_Endian.h>
#include <SST/SST_Time.h>
#include "ZNetPrivate.hpp"
#include <stdio.h> //HACKHACK printf
ZNetClient::ZNetClient()
{
connectedFlag = false;
}
ZNetClient::~ZNetClient()
{
}
/*************************************************************************/
int ZNetClient::Update()
{
bool hitError = false;
uint8_t data[9000];
//Only update if we've got a server
if(server.GetState() != STATE_UNCONNECTED)
{
SST_Socket s = server.GetSocket();
SST_NetResult res;
do
{
SST_NetAddress sender;
size_t nrReceived;
res = SST_Net_RecvFrom(s, data, sizeof(data), 0, &sender, &nrReceived);
if(res == SSTNETRESULT_SUCCESS)
{
//OK, so is the packet from the server? If not, ignore it
if(SST_Net_AddressCompare(&sender, server.GetNetAddress()) != 0)
continue;
HandlePacket(data, (uint32_t)nrReceived);
}
else if(res == SSTNETRESULT_WOULDBLOCK)
break;
else
hitError = true;
} while(res == SSTNETRESULT_SUCCESS);
}
static const char* str[] = {"UNCONNECTED", "HANDSHAKE", "CONNECTED", "SERVING"};
printf("MY STATE: %s / %u ack\n", str[server.GetState()], server.GetPacketChannel(0)->GetLocalAck());
//Send all channel data to server
if(!this->SendToPeer(&server))
hitError = true;
//Send acks
server.SendAcksForAllChannels();
server.ProcessLocalAcks();
if(hitError)
return -1;
return HasEvent() ? 1 : 0;
}
/*************************************************************************/
bool ZNetClient::Connect(SST_Socket s, SST_NetAddress* addr, uint32_t nrChannels, uint32_t userData)
{
SST_OS_DebugAssert(s != 0, "Invalid socket");
SST_OS_DebugAssert(addr != NULL, "Invalid address");
SST_OS_DebugAssert(server.GetState() == STATE_UNCONNECTED, "Must be unconnected, use Reset() first");
if(nrChannels == 0 || nrChannels > UINT8_MAX)
return false;
if(!server.Initialize(this, addr, s, nrChannels))
return false;
if(SST_Net_SetNonblock(s, 1) != SSTNETRESULT_SUCCESS)
return false;
//CONNECT always occurs on ZNET_SYSCHANNEL
ZNetPacketChannel* channel = server.GetPacketChannel(ZNET_SYSCHANNEL);
userData = ZNetPrivate::ZNetByteOrder32(userData);
//Create a packet, copying the userdata
ZNetPacket* packet = this->CreatePacket((void*)&userData, sizeof(userData), 0);
if(packet == NULL)
return false;
if(!channel->QueueForSending(packet, ZNETCMD_CONNECT))
{
packet->ReleaseReference();
return false;
}
//We're done with this
packet->ReleaseReference();
//Note that we're trying!
server.SetState(STATE_HANDSHAKE);
return true;
}
/*************************************************************************/
void ZNetClient::HandlePacket(const uint8_t* data, uint32_t dataSize)
{
ZBinaryBufferReader reader(data, dataSize, ZNET_BYTEORDER);
static int COUNT = 0;
printf("(%u) Handling packet of %u length", ++COUNT, dataSize);
//Valid packet header?
if(!ZNetPrivate::ParseWirePacketHeader(&reader))
{
printf("...but it is invalid\n");
return;
}
ZNetPrivate::ZNetMessageContainer container;
int retval;
uint64_t now = SST_OS_GetMilliTime();
bool wasValid = true;
do
{
retval = ZNetPrivate::ReadNextMessage(&reader, &container);
printf("ReadNextMessage(): %d\n", retval);
if(retval > 0)
{
switch(container.command)
{
//Server sent how far it is. We can safely act on this now because it does not generate any events.
//ACKs themselves do not utilize sequence numbers (they always have 0)
case ZNETCMD_ACK:
{
printf("ZNETCMD_ACK: CH %u: highestRecv = %u, highestSent = %u\n", container.channel, container.parsed.ack.highestReceived, container.parsed.ack.highestSent);
//Ensure it is a valid ack
if(container.channel < server.GetNumberChannels())
{
ZNetPacketChannel* channel = server.GetPacketChannel(container.channel);
int32_t currentPing = server.GetPing();
//Update ACKs, calculating an adjusted ping
channel->UpdateRemoteAck(container.parsed.ack.highestReceived, &currentPing);
//server.SetPing(currentPing);
server.SetPing(75);
}
else
wasValid = false;
break;
}
//Server sent data.
case ZNETCMD_DATA:
{
printf("ZNETCMD_DATA found, ch = %u, length = %u, offset = %u, maxSize = %u\n",
container.channel, container.parsed.data.length, container.parsed.data.offset,
container.parsed.data.maxSize);
if(container.channel < server.GetNumberChannels())
{
ZNetPacketChannel* ch = server.GetPacketChannel(container.channel);
ch->QueueData(&container);
}
else
wasValid = false;
break;
}
//Server sent a connection response
case ZNETCMD_CONNRESP:
{
printf("ZNETCMD_CONNRESP: code = %u\n", container.parsed.connect.userdata);
if(container.channel == ZNET_SYSCHANNEL)
{
const uint32_t reasonCode = container.parsed.connect.userdata; //slightly less typing
//TODO: flags? can have server full!!!
//Accepted?
if(reasonCode == 0)
{
if(server.GetState() == STATE_HANDSHAKE)
{
//OK, we're good
server.SetState(STATE_CONNECTED);
ZNetEvent ev;
ev.packet = NULL;
ev.userdata = reasonCode;
ev.remote = &server;
ev.type = ZNETEVENT_CONNECT;
this->AddEvent(&ev);
}
//We got it, mark that we did.
server.GetPacketChannel(ZNET_SYSCHANNEL)->UpdateLocalAck(container.sequence);
}
else //Not accepted. In this case, the server doesn't consider us a client, so no acks required.
{
ZNetEvent ev;
ev.packet = NULL;
ev.userdata = reasonCode;
ev.remote = &server;
ev.type = ZNETEVENT_DISCONNECT;
this->AddEvent(&ev);
//TODO: clear out CONNECT command
}
} // if on system channel
else //else not accepted.
wasValid = false;
break;
}
case ZNETCMD_DISCONNECT:
SST_OS_DebugError("Not yet implemented!");
break;
//Ignore this command, it doesn't make any sense as a client
case ZNETCMD_CONNECT:
default:
wasValid = false;
break;
}
}
} while(retval > 0);
//If all was valid, update last received time
if(wasValid)
server.SetLastReceived(now);
}