Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:19

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MQTT5_CONTROL_PACKET_HPP
0009 #define BOOST_MQTT5_CONTROL_PACKET_HPP
0010 
0011 #include <boost/mqtt5/types.hpp>
0012 
0013 #include <boost/assert.hpp>
0014 #include <boost/smart_ptr/allocate_unique.hpp>
0015 
0016 #include <algorithm>
0017 #include <cstdint>
0018 #include <memory>
0019 #include <string>
0020 #include <string_view>
0021 #include <vector>
0022 
0023 namespace boost::mqtt5::detail {
0024 
0025 /* max varint number (268'435'455) + fixed header size (1 + 4) */
0026 static constexpr int32_t default_max_send_size = 268'435'460;
0027 
0028 enum class control_code_e : std::uint8_t {
0029     no_packet = 0b00000000, // 0
0030 
0031     connect = 0b00010000, // 1
0032     connack = 0b00100000, // 2
0033     publish = 0b00110000, // 3
0034     puback = 0b01000000, // 4
0035     pubrec = 0b01010000, // 5
0036     pubrel = 0b01100000, // 6
0037     pubcomp = 0b01110000, // 7
0038     subscribe = 0b10000000, // 8
0039     suback = 0b10010000, // 9
0040     unsubscribe = 0b10100000, // 10
0041     unsuback = 0b10110000, // 11
0042     pingreq = 0b11000000, // 12
0043     pingresp = 0b11010000, // 13
0044     disconnect = 0b11100000, // 14
0045     auth = 0b11110000, // 15
0046 };
0047 
0048 constexpr struct with_pid_ {} with_pid {};
0049 constexpr struct no_pid_ {} no_pid {};
0050 
0051 template <typename Allocator>
0052 class control_packet {
0053     uint16_t _packet_id;
0054 
0055     using alloc_type = Allocator;
0056     using deleter = boost::alloc_deleter<std::string, alloc_type>;
0057     std::unique_ptr<std::string, deleter> _packet;
0058 
0059     control_packet(
0060         const Allocator& a,
0061         uint16_t packet_id, std::string packet
0062     ) :
0063         _packet_id(packet_id),
0064         _packet(boost::allocate_unique<std::string>(a, std::move(packet)))
0065     {}
0066 
0067 public:
0068     control_packet(control_packet&&) noexcept = default;
0069     control_packet(const control_packet&) = delete;
0070 
0071     control_packet& operator=(control_packet&&) noexcept = default;
0072     control_packet& operator=(const control_packet&) = delete;
0073 
0074     template <
0075         typename EncodeFun,
0076         typename ...Args
0077     >
0078     static control_packet of(
0079         with_pid_, const Allocator& alloc,
0080         EncodeFun&& encode, uint16_t packet_id, Args&&... args
0081     ) {
0082         return control_packet {
0083             alloc, packet_id, encode(packet_id, std::forward<Args>(args)...)
0084         };
0085     }
0086 
0087     template <
0088         typename EncodeFun,
0089         typename ...Args
0090     >
0091     static control_packet of(
0092         no_pid_, const Allocator& alloc,
0093         EncodeFun&& encode, Args&&... args
0094     ) {
0095         return control_packet {
0096             alloc, uint16_t(0), encode(std::forward<Args>(args)...)
0097         };
0098     }
0099 
0100     size_t size() const {
0101         return _packet->size();
0102     }
0103 
0104     control_code_e control_code() const {
0105         return control_code_e(uint8_t(*(_packet->data())) & 0b11110000);
0106     }
0107 
0108     uint16_t packet_id() const {
0109         return _packet_id;
0110     }
0111 
0112     qos_e qos() const {
0113         BOOST_ASSERT(control_code() == control_code_e::publish);
0114         auto byte = (uint8_t(*(_packet->data())) & 0b00000110) >> 1;
0115         return qos_e(byte);
0116     }
0117 
0118     control_packet& set_dup() {
0119         BOOST_ASSERT(control_code() == control_code_e::publish);
0120         auto& byte = *(_packet->data());
0121         byte |= 0b00001000;
0122         return *this;
0123     }
0124 
0125     std::string_view wire_data() const {
0126         return *_packet;
0127     }
0128 };
0129 
0130 class packet_id_allocator {
0131     struct interval {
0132         uint16_t start, end;
0133 
0134         interval(uint16_t start, uint16_t end) :
0135             start(start), end(end)
0136         {}
0137     };
0138 
0139     std::vector<interval> _free_ids;
0140     static constexpr uint16_t MAX_PACKET_ID = 65535;
0141 
0142 public:
0143     packet_id_allocator() {
0144         _free_ids.emplace_back(MAX_PACKET_ID, uint16_t(0));
0145     }
0146 
0147     packet_id_allocator(packet_id_allocator&&) noexcept = default;
0148     packet_id_allocator(const packet_id_allocator&) = delete;
0149 
0150     packet_id_allocator& operator=(packet_id_allocator&&) noexcept = default;
0151     packet_id_allocator& operator=(const packet_id_allocator&) = delete;
0152 
0153     uint16_t allocate() {
0154         if (_free_ids.empty()) return 0;
0155         auto& last = _free_ids.back();
0156         if (last.start == ++last.end) {
0157             auto ret = last.end;
0158             _free_ids.pop_back();
0159             return ret;
0160         }
0161         return last.end;
0162     }
0163 
0164     void free(uint16_t pid) {
0165         auto it = std::upper_bound(
0166             _free_ids.begin(), _free_ids.end(), pid,
0167             [](const uint16_t x, const interval& i) { return x > i.start; }
0168         );
0169         uint16_t* end_p = nullptr;
0170         if (it != _free_ids.begin()) {
0171             auto pit = std::prev(it);
0172             if (pit->end == pid)
0173                 end_p = &pit->end;
0174         }
0175         if (it != _free_ids.end() && pid - 1 == it->start) {
0176             if (!end_p)
0177                 it->start = pid;
0178             else {
0179                 *end_p = it->end;
0180                 _free_ids.erase(it);
0181             }
0182         }
0183         else {
0184             if (!end_p)
0185                 _free_ids.insert(it, interval(pid, pid - 1));
0186             else
0187                 *end_p = pid - 1;
0188         }
0189     }
0190 };
0191 
0192 } // end namespace boost::mqtt5::detail
0193 
0194 #endif // !BOOST_MQTT5_CONTROL_PACKET_HPP