Files
libsst/ZNet/ZNetPrivate.hpp
2026-04-03 00:22:39 -05:00

244 lines
5.7 KiB
C++

/*
ZNetPrivate.hpp
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 7/19/2013
Purpose:
ZNet private functions and definitions
License:
Copyright 2013, 762 Studios
*/
#pragma once
#ifndef _ZNETPRIVATE_HPP
#define _ZNETPRIVATE_HPP
#include <ZUtil/ZBinaryBufferReader.hpp>
#include <ZUtil/ZBinaryBufferWriter.hpp>
#include <SST/SST_Net.h>
//========================================
// Wire format constants
//========================================
#define ZNET_BYTEORDER SST_BIG_ENDIAN //< Global byte order for all of ZNet
#define ZNET_MAGIC 0x5A //'Z' in ASCII (i.e. uppercase zed)
#define ZNET_SYSCHANNEL 0x00u //System channel
#define ZNETCMD_CONNECT 0x00u //Connect request, sent from client to server
#define ZNETCMD_DATA 0x01u //Data packet (or fragment of one)
#define ZNETCMD_DISCONNECT 0x02u //Disconnect request
#define ZNETCMD_ACK 0x03u //Acknowledge a range of packets, possibly including a subsequence value
#define ZNETCMD_CONNRESP 0x04u //Connection response, send from server to client
#define ZNETCMD_MAX 0x05u //First invalid value
//For ZNETCMD_ACK/DATA, the "flag" field will be set to one of these values.
#define ZNETCMDFLAGS_LEN8 0x00u
#define ZNETCMDFLAGS_LEN16 0x01u
#define ZNETCMDFLAGS_LEN32 0x02u
#define ZNETCMDFLAGS_FULL 0x01u
/*
Wire Format
RAW PACKET {
u8 ZNET_MAGIC
[ messages ]
}
MESSAGE {
u8 channel
u4 flags
u4 cmd
u16 seq
[ message data ]
}
CONNECT MESSAGE {
u32 userdata
}
DATA MESSAGE {
[if flags == ZNETCMDFLAGS_LEN8]
u8 offset
u8 max
u8 length
[if flags == ZNETCMDFLAGS_LEN16]
u16 offset
u16 max
u16 length
[if flags == ZNETCMDFLAGS_LEN32]
u32 offset
u32 max
u32 length
u8 data[ length ]
}
DISCONNECT MESSAGE {
u32 userdata
}
ACK MESSAGE {
u16 highestAcked : I have received up to this point
u16 localSequence : I have sent up to this point
[if flags == ZNETCMDFLAGS_LEN8]
u8 subsequence8
[if flags == ZNETCMDFLAGS_LEN16]
u16 subsequence16
[if flags == ZNETCMDFLAGS_LEN32]
u32 subsequence32
}
*/
#define ZNET_WIRESIZE_PACKET_HEADER (sizeof(uint8_t)) //< Size of a packet header (overhead)
#define ZNET_WIRESIZE_MESSAGE_HEADER (2*sizeof(uint8_t) + sizeof(uint16_t)) //< Size of a message header (overhead)
#define ZNET_WIRESIZE_PACKET_MINIMUM ZNET_WIRESIZE_PACKET_HEADER + ZNET_WIRESIZE_MESSAGE_HEADER
class ZNetPeer;
namespace ZNetPrivate
{
//Used for CONNECT, DISCONNECT, CONNRESP
struct ZNetMessageConnect
{
uint32_t userdata;
};
//Used for ACK, ACKSUBSEQ
struct ZNetMessageAck
{
uint32_t subsequence;
uint16_t highestReceived; //Highest contiguous sequence remote host has received
uint16_t highestSent; //Highest local sequence remote host has sent
};
struct ZNetMessagePing
{
uint32_t token;
};
//Used for DATA8, DATA16, DATA32
struct ZNetMessageData
{
uint8_t* data; //Pointer within the packet
uint32_t offset; //Offset into reassembly buffer
uint32_t maxSize; //Maximum size of reassembled packet
uint32_t length; //Length of this packet
};
union ZNetMessage
{
ZNetMessageConnect connect;
ZNetMessageAck ack;
ZNetMessageData data;
ZNetMessagePing ping;
};
struct ZNetMessageContainer
{
uint32_t channel;
uint32_t command;
uint32_t flags;
uint16_t sequence;
ZNetMessage parsed;
};
/*
ZNetPrivate::ParseWirePacketHeader()
Parses the wire format packet header and returns true/false if successful.
@param reader - The reader set to the first byte of the packet in the proper byte order
@return (bool) - True if the header is valid, false if not.
*/
bool ParseWirePacketHeader(ZBinaryBufferReader* reader);
void WriteWirePacketHeader(ZBinaryBufferWriter* writer);
void WriteWireMessageHeader(ZBinaryBufferWriter* writer, uint32_t channel, uint32_t flags, uint32_t command, uint16_t sequenceNumber);
bool SendAll(SST_Socket s, const SST_NetAddress* addr, uint8_t* data, uint32_t length);
/*
ZNetPrivate::ReadNextMessage()
Attempt to parse the next message from a stream.
@param reader - The binary reader
@param msgReturn - The parsed message (only when returning > 0)
@return (int) - < 0: error in stream. 0: end of stream. > 0 successfully parsed message
*/
int ReadNextMessage(ZBinaryBufferReader* reader, ZNetPrivate::ZNetMessageContainer* msgReturn);
/*
ZNetPrivate::MinimumSizeForCommand()
Gets the minimum size (in bytes) of a command's payload.
@return (uint32_t) - The number of bytes
*/
uint32_t MinimumSizeForCommand(uint32_t command);
/*
ZNetPrivate::WireSizeForCommand()
Gets the approximate size for a simple command. This means packet header + message header + payload
@return (uint32_t) - The number of bytes
*/
inline uint32_t WireSizeForSimpleCommand(uint32_t command) { return MinimumSizeForCommand(command) + ZNET_WIRESIZE_PACKET_MINIMUM; }
/*
ZNetPrivate::SequenceAfter()
Checks if seq1 comes after seq2, taking into account sequence number wraps.
@param seq1 - The sequence number to check
@param seq2 - The existing sequence number
@return (bool) - True if seq1 comes after seq2, false if seq2 comes first or equals seq1
*/
inline bool SequenceAfter(uint16_t seq1, uint16_t seq2)
{
return ((seq2 > seq1) && (seq2 - seq1 > UINT16_MAX/2)) || ((seq1 > seq2) && (seq1 - seq2 <= UINT16_MAX/2));
}
inline uint32_t PackedIntegerSize(uint32_t value)
{
if(value <= UINT8_MAX) return sizeof(uint8_t);
if(value <= UINT16_MAX) return sizeof(uint16_t);
return sizeof(uint32_t);
}
void SendPingCommand(bool isReply, uint32_t givenToken, ZNetPeer* peer);
inline bool IsValidCommand(uint32_t command) { return (command < ZNETCMD_MAX); }
inline uint32_t ZNetByteOrder32(uint32_t v)
{
#if (SST_BYTEORDER_HOST != ZNET_BYTEORDER)
v = SST_OS_ByteSwap32(v);
#endif
return v;
}
}
#endif