/* ZNetPrivate.cpp Author: Patrick Baggett Created: 7/19/2013 Purpose: ZNet private functions and definitions License: Copyright 2013, 762 Studios */ #include "ZNetPrivate.hpp" #include #include /*************************************************************************/ bool ZNetPrivate::ParseWirePacketHeader(ZBinaryBufferReader* reader) { //Packet is absolutely too small to have any useful data (i.e. size < minimum overhead) if(reader->GetLength() < ZNET_WIRESIZE_PACKET_MINIMUM) return false; if(reader->ReadU8() != ZNET_MAGIC) return false; return true; } /*************************************************************************/ void ZNetPrivate::WriteWirePacketHeader(ZBinaryBufferWriter* writer) { writer->WriteU8(ZNET_MAGIC); } /*************************************************************************/ void ZNetPrivate::WriteWireMessageHeader(ZBinaryBufferWriter* writer, uint32_t channel, uint32_t flags, uint32_t command, uint16_t sequenceNumber) { uint8_t merged = (uint8_t)(((flags & 0x0F) << 4) | (command & 0x0F)); writer->WriteU8((uint8_t)channel); writer->WriteU8(merged); writer->WriteU16(sequenceNumber); } /*************************************************************************/ bool ZNetPrivate::SendAll(SST_Socket s, const SST_NetAddress* addr, uint8_t* data, uint32_t length) { size_t totalSent; if(SST_Net_SendTo(s, data, length, 0, addr, &totalSent) == SSTNETRESULT_SUCCESS) { //Return true if and only if all data was sent return ((uint32_t)totalSent == length); } //Failed to send at all... :( return false; } /*************************************************************************/ int ZNetPrivate::ReadNextMessage(ZBinaryBufferReader* reader, ZNetPrivate::ZNetMessageContainer* msgReturn) { if(reader->GetLength() - reader->GetOffset() == 0) return 0; if(!reader->CanRead(ZNET_WIRESIZE_MESSAGE_HEADER)) return -1; //error in stream //Read channel msgReturn->channel = reader->ReadU8(); //Read command+flags (merged 8-bit value) uint8_t cmdAndFlags = reader->ReadU8(); msgReturn->command = (cmdAndFlags & 0x0F) >> 0; msgReturn->flags = (cmdAndFlags & 0xF0) >> 4; msgReturn->sequence = reader->ReadU16(); //Validate the command is OK if(!ZNetPrivate::IsValidCommand(msgReturn->command)) return -1; //TODO: validate flags for each command. //Ensure we can read at least the minimum number of bytes required for the command if(!reader->CanRead(ZNetPrivate::MinimumSizeForCommand(msgReturn->command))) return -1; switch(msgReturn->command) { case ZNETCMD_CONNECT: case ZNETCMD_DISCONNECT: case ZNETCMD_CONNRESP: { msgReturn->parsed.connect.userdata = reader->ReadU32(); break; } case ZNETCMD_DATA: { if(msgReturn->flags & ZNETCMDFLAGS_LEN8) { msgReturn->parsed.data.offset = reader->ReadU8(); msgReturn->parsed.data.maxSize = reader->ReadU8(); msgReturn->parsed.data.length = reader->ReadU8(); } else if(msgReturn->flags & ZNETCMDFLAGS_LEN16) { msgReturn->parsed.data.offset = reader->ReadU16(); msgReturn->parsed.data.maxSize = reader->ReadU16(); msgReturn->parsed.data.length = reader->ReadU16(); } else if(msgReturn->flags & ZNETCMDFLAGS_LEN32) { msgReturn->parsed.data.offset = reader->ReadU32(); msgReturn->parsed.data.maxSize = reader->ReadU32(); msgReturn->parsed.data.length = reader->ReadU32(); } msgReturn->parsed.data.data = (uint8_t*)reader->GetBufferReadAddress(); //Verify access if(!reader->CanRead(msgReturn->parsed.data.length)) return -1; break; } case ZNETCMD_ACK: { msgReturn->parsed.ack.highestReceived = reader->ReadU16(); msgReturn->parsed.ack.highestSent = reader->ReadU16(); //Read 8-bit, 16-bit, or 32-bit subsequence if(msgReturn->flags & ZNETCMDFLAGS_LEN8) msgReturn->parsed.ack.subsequence = reader->ReadU8(); else if(msgReturn->flags & ZNETCMDFLAGS_LEN16) msgReturn->parsed.ack.subsequence = reader->ReadU16(); else if(msgReturn->flags & ZNETCMDFLAGS_LEN32) msgReturn->parsed.ack.subsequence = reader->ReadU32(); break; } } //Read a full message return 1; } /*************************************************************************/ uint32_t ZNetPrivate::MinimumSizeForCommand(uint32_t command) { uint32_t size; switch(command) { case ZNETCMD_CONNECT: size = sizeof(uint32_t); break; case ZNETCMD_DATA: size = sizeof(uint8_t)*3; break; case ZNETCMD_DISCONNECT: size = sizeof(uint32_t); break; case ZNETCMD_ACK: size = 2*sizeof(uint16_t); break; case ZNETCMD_CONNRESP: size = sizeof(uint32_t); break; default: SST_OS_DebugError("Should not reach here"); size = UINT32_MAX; break; } return size; }