BCNP 3.2.1
Batched Command Network Protocol
Loading...
Searching...
No Matches
packet.h
Go to the documentation of this file.
1#pragma once
2
13#include <bcnp/message_types.h>
14#include "bcnp/static_vector.h"
15#include "bcnp/packet_storage.h"
16
17#include <cstddef>
18#include <cstdint>
19#include <optional>
20#include <vector>
21
22namespace bcnp {
23
31constexpr std::size_t kChecksumSize = 4;
32
34constexpr std::size_t kMaxMessagesPerPacket = 65535;
35
37constexpr uint8_t kFlagClearQueue = 0x01;
38
40constexpr uint8_t kProtocolMajor = kProtocolMajorV3;
41
43constexpr uint8_t kProtocolMinor = kProtocolMinorV3;
44
46constexpr std::size_t kHeaderSize = kHeaderSizeV3;
47
48 // end of ProtocolConstants
49
57constexpr std::size_t kHeaderMajorIndex = 0;
58
60constexpr std::size_t kHeaderMinorIndex = 1;
61
63constexpr std::size_t kHeaderFlagsIndex = 2;
64
65// kHeaderMsgTypeIndex = 3, kHeaderMsgCountIndex = 5 (from generated header)
66 // end of HeaderOffsets
67
82
99template<typename MsgType>
101public:
102 using iterator_category = std::forward_iterator_tag;
103 using value_type = MsgType;
104 using difference_type = std::ptrdiff_t;
105 using pointer = const MsgType*;
106 using reference = MsgType;
107
113 MessageIterator(const uint8_t* ptr, std::size_t count)
114 : m_ptr(ptr), m_count(count) {}
115
120 MsgType operator*() const {
121 auto result = MsgType::Decode(m_ptr, MsgType::kWireSize);
122 return result.value_or(MsgType{});
123 }
124
127 if (m_count > 0) {
128 m_ptr += MsgType::kWireSize;
129 m_count--;
130 }
131 if (m_count == 0) {
132 m_ptr = nullptr;
133 }
134 return *this;
135 }
136
139 MessageIterator tmp = *this;
140 ++(*this);
141 return tmp;
142 }
143
145 bool operator==(const MessageIterator& other) const {
146 if (m_count == 0 && other.m_count == 0) return true;
147 return m_ptr == other.m_ptr && m_count == other.m_count;
148 }
149
151 bool operator!=(const MessageIterator& other) const {
152 return !(*this == other);
153 }
154
155private:
156 const uint8_t* m_ptr;
157 std::size_t m_count;
158};
159
172 const uint8_t* payloadStart{nullptr};
173
179
189 template<typename MsgType>
191 if (MsgType::kTypeId != header.messageType) {
192 return MessageIterator<MsgType>(nullptr, 0);
193 }
195 }
196
202 template<typename MsgType>
204 return MessageIterator<MsgType>(nullptr, 0);
205 }
206
211 const uint8_t* GetPayload() const { return payloadStart; }
212
217 std::size_t GetPayloadSize() const;
218};
219
241template<typename MsgType, typename Storage = std::vector<MsgType>>
243 static_assert(IsValidPacketStorage_v<Storage>,
244 "Storage must be a valid packet storage container (vector-like interface)");
245
247 Storage messages{};
248
250 header.messageType = MsgType::kTypeId;
251 }
252};
253
255template<typename MsgType, std::size_t Capacity = 64>
257
259template<typename MsgType>
261
281
290 std::optional<PacketView> view;
292 std::size_t bytesConsumed{0};
293};
294
305uint32_t ComputeCrc32(const uint8_t* data, std::size_t length);
306
321template<typename MsgType, typename Storage>
322bool EncodeTypedPacket(const TypedPacket<MsgType, Storage>& packet, uint8_t* output,
323 std::size_t capacity, std::size_t& bytesWritten) {
324 bytesWritten = 0;
325 if (packet.messages.size() > kMaxMessagesPerPacket || !output) {
326 return false;
327 }
328
329 const std::size_t payloadSize = kHeaderSizeV3 + packet.messages.size() * MsgType::kWireSize;
330 const std::size_t required = payloadSize + kChecksumSize;
331 if (capacity < required) {
332 return false;
333 }
334
335 // V3 Header
336 output[kHeaderMajorIndex] = packet.header.major;
337 output[kHeaderMinorIndex] = packet.header.minor;
338 output[kHeaderFlagsIndex] = packet.header.flags;
339 detail::StoreU16(static_cast<uint16_t>(MsgType::kTypeId), &output[kHeaderMsgTypeIndex]);
340 detail::StoreU16(static_cast<uint16_t>(packet.messages.size()), &output[kHeaderMsgCountIndex]);
341
342 // Encode messages
343 std::size_t offset = kHeaderSizeV3;
344 for (const auto& msg : packet.messages) {
345 if (!msg.Encode(&output[offset], MsgType::kWireSize)) {
346 return false;
347 }
348 offset += MsgType::kWireSize;
349 }
350
351 // CRC32
352 const uint32_t crc = ComputeCrc32(output, payloadSize);
353 detail::StoreU32(crc, &output[payloadSize]);
354
355 bytesWritten = required;
356 return true;
357}
358
371template<typename MsgType, typename Storage>
372bool EncodeTypedPacket(const TypedPacket<MsgType, Storage>& packet, std::vector<uint8_t>& output) {
373 if (packet.messages.size() > kMaxMessagesPerPacket) {
374 return false;
375 }
376 const std::size_t required = kHeaderSizeV3 + packet.messages.size() * MsgType::kWireSize + kChecksumSize;
377 output.resize(required);
378 std::size_t bytesWritten = 0;
379 if (!EncodeTypedPacket(packet, output.data(), output.size(), bytesWritten)) {
380 return false;
381 }
382 output.resize(bytesWritten);
383 return true;
384}
385
396template<typename MsgType>
397std::optional<TypedPacket<MsgType>> DecodeTypedPacket(const PacketView& view) {
398 if (view.header.messageType != MsgType::kTypeId) {
399 return std::nullopt;
400 }
401
403 packet.header = view.header;
404 packet.messages.reserve(view.header.messageCount);
405
406 const uint8_t* ptr = view.payloadStart;
407 for (std::size_t i = 0; i < view.header.messageCount; ++i) {
408 auto msg = MsgType::Decode(ptr, MsgType::kWireSize);
409 if (!msg) {
410 return std::nullopt;
411 }
412 packet.messages.push_back(*msg);
413 ptr += MsgType::kWireSize;
414 }
415
416 return packet;
417}
418
430template<typename MsgType, typename Storage>
431std::optional<TypedPacket<MsgType, Storage>> DecodeTypedPacketAs(const PacketView& view) {
432 if (view.header.messageType != MsgType::kTypeId) {
433 return std::nullopt;
434 }
435
437 packet.header = view.header;
439
440 const uint8_t* ptr = view.payloadStart;
441 for (std::size_t i = 0; i < view.header.messageCount; ++i) {
442 auto msg = MsgType::Decode(ptr, MsgType::kWireSize);
443 if (!msg) {
444 return std::nullopt;
445 }
446 packet.messages.push_back(*msg);
447 ptr += MsgType::kWireSize;
448 }
449
450 return packet;
451}
452
464DecodeViewResult DecodePacketViewWithSize(const uint8_t* data, std::size_t length, std::size_t wireSize);
465
476DecodeViewResult DecodePacketView(const uint8_t* data, std::size_t length);
477
489template<typename MsgType>
490DecodeViewResult DecodePacketViewAs(const uint8_t* data, std::size_t length) {
491 return DecodePacketViewWithSize(data, length, MsgType::kWireSize);
492}
493
494} // namespace bcnp
Forward iterator for zero-copy message access from packet payload.
Definition packet.h:100
std::ptrdiff_t difference_type
Definition packet.h:104
bool operator==(const MessageIterator &other) const
Equality comparison (end iterators compare equal).
Definition packet.h:145
MessageIterator & operator++()
Advance to the next message (pre-increment).
Definition packet.h:126
MessageIterator(const uint8_t *ptr, std::size_t count)
Construct iterator at a position in the payload.
Definition packet.h:113
std::forward_iterator_tag iterator_category
Definition packet.h:102
bool operator!=(const MessageIterator &other) const
Inequality comparison.
Definition packet.h:151
MsgType operator*() const
Decode and return the current message.
Definition packet.h:120
MessageIterator operator++(int)
Advance to the next message (post-increment).
Definition packet.h:138
const MsgType * pointer
Definition packet.h:105
constexpr std::size_t kHeaderMajorIndex
Byte offset of major version in header.
Definition packet.h:57
constexpr std::size_t kHeaderMinorIndex
Byte offset of minor version in header.
Definition packet.h:60
constexpr std::size_t kHeaderFlagsIndex
Byte offset of flags byte in header.
Definition packet.h:63
constexpr uint8_t kProtocolMinor
Current protocol minor version.
Definition packet.h:43
constexpr std::size_t kMaxMessagesPerPacket
Maximum number of messages allowed in a single packet.
Definition packet.h:34
constexpr uint8_t kFlagClearQueue
Packet flag: Clear command queue before processing this packet.
Definition packet.h:37
constexpr uint8_t kProtocolMajor
Current protocol major version.
Definition packet.h:40
constexpr std::size_t kChecksumSize
Size of CRC32 checksum in bytes.
Definition packet.h:31
constexpr std::size_t kHeaderSize
Size of packet header in bytes.
Definition packet.h:46
void StoreU16(uint16_t v, uint8_t *p)
void StoreU32(uint32_t v, uint8_t *p)
std::optional< TypedPacket< MsgType, Storage > > DecodeTypedPacketAs(const PacketView &view)
Decode messages from a PacketView with custom storage type.
Definition packet.h:431
constexpr std::size_t kHeaderMsgCountIndex
std::optional< TypedPacket< MsgType > > DecodeTypedPacket(const PacketView &view)
Decode messages from a PacketView into a typed packet.
Definition packet.h:397
bool EncodeTypedPacket(const TypedPacket< MsgType, Storage > &packet, uint8_t *output, std::size_t capacity, std::size_t &bytesWritten)
Encode a typed packet to a pre-allocated buffer.
Definition packet.h:322
DecodeViewResult DecodePacketViewAs(const uint8_t *data, std::size_t length)
Type-safe packet view decode using compile-time message type.
Definition packet.h:490
constexpr bool IsValidPacketStorage_v
DecodeViewResult DecodePacketView(const uint8_t *data, std::size_t length)
Decode a packet using the global message type registry.
Definition packet.cpp:143
constexpr std::size_t kHeaderMsgTypeIndex
void ReserveIfPossible(Container &container, std::size_t capacity)
Helper to reserve capacity (no-op for static storage).
uint32_t ComputeCrc32(const uint8_t *data, std::size_t length)
Compute CRC32 checksum for data integrity verification.
Definition packet.cpp:49
constexpr uint8_t kProtocolMinorV3
PacketError
Error codes returned by packet decoding operations.
Definition packet.h:268
@ UnsupportedVersion
Protocol version mismatch.
@ HandshakeRequired
Connection requires handshake first.
@ ChecksumMismatch
CRC32 validation failed.
@ TooManyMessages
Message count exceeds kMaxMessagesPerPacket.
@ Truncated
Buffer ends before expected packet length.
@ SchemaMismatch
Client/server schema hash mismatch.
@ InvalidFloat
NaN or Inf detected in float field.
@ UnknownMessageType
Message type ID not in registry.
@ None
No error - packet decoded successfully.
@ TooSmall
Buffer too small to contain header.
DecodeViewResult DecodePacketViewWithSize(const uint8_t *data, std::size_t length, std::size_t wireSize)
Decode a packet with explicitly provided message wire size.
Definition packet.cpp:76
constexpr std::size_t kHeaderSizeV3
constexpr uint8_t kProtocolMajorV3
Fixed-capacity vector with stack allocation (no heap).
Result of decoding a packet from raw bytes.
Definition packet.h:289
std::optional< PacketView > view
Decoded view (valid if error == None)
Definition packet.h:290
std::size_t bytesConsumed
Bytes consumed from input buffer.
Definition packet.h:292
PacketError error
Error code if decode failed.
Definition packet.h:291
Parsed packet header structure.
Definition packet.h:75
uint8_t minor
Protocol minor version.
Definition packet.h:77
uint8_t major
Protocol major version.
Definition packet.h:76
uint8_t flags
Packet flags (e.g., kFlagClearQueue)
Definition packet.h:78
uint16_t messageCount
Number of messages in payload.
Definition packet.h:80
MessageTypeId messageType
Type ID of messages in payload.
Definition packet.h:79
Zero-copy view into a decoded packet buffer.
Definition packet.h:170
MessageIterator< MsgType > end_as() const
Get end iterator for type-safe message iteration.
Definition packet.h:203
const uint8_t * GetPayload() const
Get raw pointer to payload for manual parsing.
Definition packet.h:211
PacketHeader header
Parsed header information.
Definition packet.h:171
std::size_t GetPayloadSize() const
Calculate total payload size in bytes.
Definition packet.cpp:58
const uint8_t * payloadStart
Pointer to first message in buffer.
Definition packet.h:172
MessageTypeId GetMessageType() const
Get the message type ID for this packet.
Definition packet.h:178
MessageIterator< MsgType > begin_as() const
Get type-safe iterator to the first message.
Definition packet.h:190
Generic packet containing messages of a specific type.
Definition packet.h:242
Storage messages
Definition packet.h:247
PacketHeader header
Definition packet.h:246