From 92d21c5ddd4cb86af3a6345a08f8f403da3f239d Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Fri, 14 Aug 2020 12:20:58 +0200 Subject: [PATCH] the ReceivedFrame class has been split into a InBuffer base class to make it easier to store messages without having to construct a full frame, this commit adds the newly introduced classes --- include/amqpcpp/inbuffer.h | 143 +++++++++++++++++++++++++++++ src/buffercheck.h | 61 +++++++++++++ src/inbuffer.cpp | 182 +++++++++++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+) create mode 100644 include/amqpcpp/inbuffer.h create mode 100644 src/buffercheck.h create mode 100644 src/inbuffer.cpp diff --git a/include/amqpcpp/inbuffer.h b/include/amqpcpp/inbuffer.h new file mode 100644 index 0000000..c6bde4d --- /dev/null +++ b/include/amqpcpp/inbuffer.h @@ -0,0 +1,143 @@ +/** + * InBuffer.h + * + * The InBuffer class is a wrapper around a data buffer and that adds + * some safety checks so that the rest of the library can safely read + * from it. + * + * This is a class that is used internally by the AMQP library. As a user + * of this library, you normally do not have to instantiate it. However, + * if you do want to store or safe messages yourself, it sometimes can + * be useful to implement it. + * + * @copyright 2014 - 2020 Copernica BV + */ + +/** + * Include guard + */ +#pragma once + +/** + * Dependencies + */ +#include + +/** + * Set up namespace + */ +namespace AMQP { + +/** + * Forward declarations + */ +class Buffer; + +/** + * Class definition + */ +class InBuffer +{ +protected: + /** + * The buffer we are reading from + * @var Buffer + */ + const Buffer &_buffer; + + /** + * Number of bytes already processed + * @var uint32_t + */ + uint32_t _skip = 0; + +public: + /** + * Constructor + * @param buffer Binary buffer + */ + InBuffer(const Buffer &buffer) : _buffer(buffer) {} + + /** + * Destructor + */ + virtual ~InBuffer() {} + + /** + * Read the next uint8_t from the buffer + * @return uint8_t value read + */ + uint8_t nextUint8(); + + /** + * Read the next int8_t from the buffer + * @return int8_t value read + */ + int8_t nextInt8(); + + /** + * Read the next uint16_t from the buffer + * @return uint16_t value read + */ + uint16_t nextUint16(); + + /** + * Read the next int16_t from the buffer + * @return int16_t value read + */ + int16_t nextInt16(); + + /** + * Read the next uint32_t from the buffer + * @return uint32_t value read + */ + uint32_t nextUint32(); + + /** + * Read the next int32_t from the buffer + * @return int32_t value read + */ + int32_t nextInt32(); + + /** + * Read the next uint64_t from the buffer + * @return uint64_t value read + */ + uint64_t nextUint64(); + + /** + * Read the next int64_t from the buffer + * @return int64_t value read + */ + int64_t nextInt64(); + + /** + * Read a float from the buffer + * @return float float read from buffer. + */ + float nextFloat(); + + /** + * Read a double from the buffer + * @return double double read from buffer + */ + double nextDouble(); + + /** + * Get a pointer to the next binary buffer of a certain size + * @param size + * @return char* + */ + const char *nextData(uint32_t size); + + /** + * The checker may access private data + */ + friend class BufferCheck; + +}; + +/** + * End of namespace + */ +} diff --git a/src/buffercheck.h b/src/buffercheck.h new file mode 100644 index 0000000..b9ad69f --- /dev/null +++ b/src/buffercheck.h @@ -0,0 +1,61 @@ +/** + * BufferCheck.h + * + * Class that checks incoming frames for their size + * + * @copyright 2014 - 2020 Copernica BV + */ + +/** + * Set up namespace + */ +namespace AMQP { + +/** + * Internal helper class that checks if there is enough room left in the buffer + */ +class BufferCheck +{ +private: + /** + * The frame + * @var InBuffer + */ + InBuffer *_frame; + + /** + * The size that is checked + * @var size_t + */ + size_t _size; + +public: + /** + * Constructor + * @param frame + * @param size + */ + BufferCheck(InBuffer *frame, size_t size) : _frame(frame), _size(size) + { + // no problem is there are still enough bytes left + if (frame->_buffer.size() - frame->_skip >= size) return; + + // frame buffer is too small + throw ProtocolException("frame out of range"); + } + + /** + * Destructor + */ + virtual ~BufferCheck() + { + // update the number of bytes to skip + _frame->_skip += (uint32_t)_size; + } +}; + +/** + * End namespace + */ +} + diff --git a/src/inbuffer.cpp b/src/inbuffer.cpp new file mode 100644 index 0000000..2f3208f --- /dev/null +++ b/src/inbuffer.cpp @@ -0,0 +1,182 @@ +/** + * InBuffer.cpp + * + * Implementation of the InBuffer class + * + * @copyright 2014 - 2020 Copernica BV + */ +#include "includes.h" +#include "buffercheck.h" + +/** + * Set up namespace + */ +namespace AMQP { + +/** + * Read the next uint8 from the buffer + * @param char* buffer buffer to read from + * @return uint8_t value read + */ +uint8_t InBuffer::nextUint8() +{ + // check if there is enough size + BufferCheck check(this, 1); + + // get a byte + return _buffer.byte(_skip); +} + +/** + * Read the next int8 from the buffer + * @param char* buffer buffer to read from + * @return int8_t value read + */ +int8_t InBuffer::nextInt8() +{ + // check if there is enough size + BufferCheck check(this, 1); + + // get a byte + return (int8_t)_buffer.byte(_skip); +} + +/** + * Read the next uint16_t from the buffer + * @return uint16_t value read + */ +uint16_t InBuffer::nextUint16() +{ + // check if there is enough size + BufferCheck check(this, sizeof(uint16_t)); + + // get two bytes, and convert to host-byte-order + uint16_t value; + _buffer.copy(_skip, sizeof(uint16_t), &value); + return be16toh(value); +} + +/** + * Read the next int16_t from the buffer + * @return int16_t value read + */ +int16_t InBuffer::nextInt16() +{ + // check if there is enough size + BufferCheck check(this, sizeof(int16_t)); + + // get two bytes, and convert to host-byte-order + int16_t value; + _buffer.copy(_skip, sizeof(int16_t), &value); + return be16toh(value); +} + +/** + * Read the next uint32_t from the buffer + * @return uint32_t value read + */ +uint32_t InBuffer::nextUint32() +{ + // check if there is enough size + BufferCheck check(this, sizeof(uint32_t)); + + // get four bytes, and convert to host-byte-order + uint32_t value; + _buffer.copy(_skip, sizeof(uint32_t), &value); + return be32toh(value); +} + +/** + * Read the next int32_t from the buffer + * @return uint32_t value read + */ +int32_t InBuffer::nextInt32() +{ + // check if there is enough size + BufferCheck check(this, sizeof(int32_t)); + + // get four bytes, and convert to host-byte-order + int32_t value; + _buffer.copy(_skip, sizeof(int32_t), &value); + return be32toh(value); +} + +/** + * Read the next uint64_t from the buffer + * @return uint64_t value read + */ +uint64_t InBuffer::nextUint64() +{ + // check if there is enough size + BufferCheck check(this, sizeof(uint64_t)); + + // get eight bytes, and convert to host-byte-order + uint64_t value; + _buffer.copy(_skip, sizeof(uint64_t), &value); + return be64toh(value); +} + +/** + * Read the next uint64_t from the buffer + * @return uint64_t value read + */ +int64_t InBuffer::nextInt64() +{ + // check if there is enough size + BufferCheck check(this, sizeof(int64_t)); + + // get eight bytes, and convert to host-byte-order + int64_t value; + _buffer.copy(_skip, sizeof(int64_t), &value); + return be64toh(value); +} + +/** + * Read a float from the buffer + * @return float float read from buffer. + */ +float InBuffer::nextFloat() +{ + // check if there is enough size + BufferCheck check(this, sizeof(float)); + + // get four bytes + float value; + _buffer.copy(_skip, sizeof(float), &value); + return value; +} + +/** + * Read a double from the buffer + * @return double double read from buffer + */ +double InBuffer::nextDouble() +{ + // check if there is enough size + BufferCheck check(this, sizeof(double)); + + // get eight bytes, and convert to host-byte-order + double value; + _buffer.copy(_skip, sizeof(double), &value); + return value; +} + +/** + * Get a pointer to the next binary buffer of a certain size + * @param size + * @return char* + */ +const char *InBuffer::nextData(uint32_t size) +{ + // check if there is enough size + BufferCheck check(this, size); + + // get the data + return _buffer.data(_skip, size); +} + +/** + * End of namespace + */ +} +