#include "tracking/protocol.hpp" #include "coding/endianness.hpp" #include "coding/writer.hpp" #include "base/assert.hpp" #include "std/cstdint.hpp" #include "std/sstream.hpp" #include "std/utility.hpp" namespace { template vector CreateDataPacketImpl(Container const & points, tracking::Protocol::PacketType const type) { vector buffer; MemWriter writer(buffer); uint32_t version = tracking::Protocol::Encoder::kLatestVersion; switch (type) { case tracking::Protocol::PacketType::DataV0: version = 0; break; case tracking::Protocol::PacketType::DataV1: version = 1; break; case tracking::Protocol::PacketType::AuthV0: ASSERT(false, ("Not a DATA packet.")); break; } tracking::Protocol::Encoder::SerializeDataPoints(version, writer, points); auto packet = tracking::Protocol::CreateHeader(type, static_cast(buffer.size())); packet.insert(packet.end(), begin(buffer), end(buffer)); return packet; } } // namespace namespace tracking { uint8_t const Protocol::kOk[4] = {'O', 'K', '\n', '\n'}; uint8_t const Protocol::kFail[4] = {'F', 'A', 'I', 'L'}; static_assert(sizeof(Protocol::kFail) >= sizeof(Protocol::kOk), ""); // static vector Protocol::CreateHeader(PacketType type, uint32_t payloadSize) { vector header; InitHeader(header, type, payloadSize); return header; } // static vector Protocol::CreateAuthPacket(string const & clientId) { vector packet; InitHeader(packet, PacketType::CurrentAuth, static_cast(clientId.size())); packet.insert(packet.end(), begin(clientId), end(clientId)); return packet; } // static vector Protocol::CreateDataPacket(DataElementsCirc const & points, PacketType type) { return CreateDataPacketImpl(points, type); } // static vector Protocol::CreateDataPacket(DataElementsVec const & points, PacketType type) { return CreateDataPacketImpl(points, type); } // static pair Protocol::DecodeHeader(vector const & data) { ASSERT_GREATER_OR_EQUAL(data.size(), sizeof(uint32_t /* header */), ()); uint32_t size = (*reinterpret_cast(data.data())) & 0xFFFFFF00; if (!IsBigEndian()) size = ReverseByteOrder(size); return make_pair(PacketType(static_cast(data[0])), size); } // static string Protocol::DecodeAuthPacket(Protocol::PacketType type, vector const & data) { switch (type) { case Protocol::PacketType::AuthV0: return string(begin(data), end(data)); case Protocol::PacketType::DataV0: case Protocol::PacketType::DataV1: ASSERT(false, ("Not an AUTH packet.")); break; } return string(); } // static Protocol::DataElementsVec Protocol::DecodeDataPacket(PacketType type, vector const & data) { DataElementsVec points; MemReader memReader(data.data(), data.size()); ReaderSource src(memReader); switch (type) { case Protocol::PacketType::DataV0: Encoder::DeserializeDataPoints(0 /* version */, src, points); break; case Protocol::PacketType::DataV1: Encoder::DeserializeDataPoints(1 /* version */, src, points); break; case Protocol::PacketType::AuthV0: ASSERT(false, ("Not a DATA packet.")); break; } return points; } // static void Protocol::InitHeader(vector & packet, PacketType type, uint32_t payloadSize) { packet.resize(sizeof(uint32_t)); uint32_t & size = *reinterpret_cast(packet.data()); size = payloadSize; ASSERT_LESS(size, 0x00FFFFFF, ()); if (!IsBigEndian()) size = ReverseByteOrder(size); packet[0] = static_cast(type); } string DebugPrint(Protocol::PacketType type) { switch (type) { case Protocol::PacketType::AuthV0: return "AuthV0"; case Protocol::PacketType::DataV0: return "DataV0"; case Protocol::PacketType::DataV1: return "DataV1"; } stringstream ss; ss << "Unknown(" << static_cast(type) << ")"; return ss.str(); } } // namespace tracking