/* ZNetPrivate.hpp Author: Patrick Baggett Created: 7/19/2013 Purpose: ZNet private functions and definitions License: Copyright 2013, 762 Studios */ #pragma once #ifndef _ZNETPRIVATE_HPP #define _ZNETPRIVATE_HPP #include #include #include //======================================== // 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