async_mqtt 5.0.0
Loading...
Searching...
No Matches
v3_1_1_suback.hpp
1// Copyright Takatoshi Kondo 2022
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#if !defined(ASYNC_MQTT_PACKET_V3_1_1_SUBACK_HPP)
8#define ASYNC_MQTT_PACKET_V3_1_1_SUBACK_HPP
9
10#include <utility>
11#include <numeric>
12
13#include <boost/numeric/conversion/cast.hpp>
14
15#include <async_mqtt/exception.hpp>
16#include <async_mqtt/buffer.hpp>
17
18#include <async_mqtt/util/move.hpp>
19#include <async_mqtt/util/static_vector.hpp>
20#include <async_mqtt/util/endian_convert.hpp>
21
22#include <async_mqtt/packet/fixed_header.hpp>
23#include <async_mqtt/packet/topic_subopts.hpp>
25#include <async_mqtt/packet/packet_id_type.hpp>
26#include <async_mqtt/packet/copy_to_static_vector.hpp>
27
28namespace async_mqtt::v3_1_1 {
29
30namespace as = boost::asio;
31
39template <std::size_t PacketIdBytes>
41public:
42 using packet_id_t = typename packet_id_type<PacketIdBytes>::type;
43
50 packet_id_t packet_id,
51 std::vector<suback_return_code> params
52 )
53 : fixed_header_{make_fixed_header(control_packet_type::suback, 0b0000)},
54 entries_{force_move(params)},
55 remaining_length_{PacketIdBytes + entries_.size()}
56 {
57 endian_store(packet_id, packet_id_.data());
58
59 remaining_length_buf_ = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
60 }
61
63 // fixed_header
64 if (buf.empty()) {
65 throw make_error(
66 errc::bad_message,
67 "v3_1_1::suback_packet fixed_header doesn't exist"
68 );
69 }
70 fixed_header_ = static_cast<std::uint8_t>(buf.front());
71 buf.remove_prefix(1);
72 auto cpt_opt = get_control_packet_type_with_check(static_cast<std::uint8_t>(fixed_header_));
73 if (!cpt_opt || *cpt_opt != control_packet_type::suback) {
74 throw make_error(
75 errc::bad_message,
76 "v3_1_1::suback_packet fixed_header is invalid"
77 );
78 }
79
80 // remaining_length
81 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
82 remaining_length_ = *vl_opt;
83 }
84 else {
85 throw make_error(errc::bad_message, "v3_1_1::suback_packet remaining length is invalid");
86 }
87 if (remaining_length_ != buf.size()) {
88 throw make_error(errc::bad_message, "v3_1_1::suback_packet remaining length doesn't match buf.size()");
89 }
90
91 // packet_id
92 if (!copy_advance(buf, packet_id_)) {
93 throw make_error(
94 errc::bad_message,
95 "v3_1_1::suback_packet packet_id doesn't exist"
96 );
97 }
98
99 if (remaining_length_ == 0) {
100 throw make_error(errc::bad_message, "v3_1_1::suback_packet doesn't have entries");
101 }
102
103 while (!buf.empty()) {
104 // suback_return_code
105 if (buf.empty()) {
106 throw make_error(
107 errc::bad_message,
108 "v3_1_1::suback_packet suback_return_code doesn't exist"
109 );
110 }
111 auto rc = static_cast<suback_return_code>(buf.front());
112 entries_.emplace_back(rc);
113 buf.remove_prefix(1);
114 }
115 }
116
117 constexpr control_packet_type type() const {
118 return control_packet_type::suback;
119 }
120
126 std::vector<as::const_buffer> const_buffer_sequence() const {
127 std::vector<as::const_buffer> ret;
129
130 ret.emplace_back(as::buffer(&fixed_header_, 1));
131
132 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
133
134 ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
135
136 ret.emplace_back(as::buffer(entries_.data(), entries_.size()));
137
138 return ret;
139 }
140
145 std::size_t size() const {
146 return
147 1 + // fixed header
148 remaining_length_buf_.size() +
149 remaining_length_;
150 }
151
156 std::size_t num_of_const_buffer_sequence() const {
157 return
158 1 + // fixed header
159 1 + // remaining length
160 1 + // packet id
161 1; // suback_return_code vector
162 }
163
168 packet_id_t packet_id() const {
169 return endian_load<packet_id_t>(packet_id_.data());
170 }
171
176 std::vector<suback_return_code> const& entries() const {
177 return entries_;
178 }
179
180private:
181 std::uint8_t fixed_header_;
182 std::vector<suback_return_code> entries_;
184 std::size_t remaining_length_;
185 static_vector<char, 4> remaining_length_buf_;
186};
187
188template <std::size_t PacketIdBytes>
189inline std::ostream& operator<<(std::ostream& o, basic_suback_packet<PacketIdBytes> const& v) {
190 o <<
191 "v3_1_1::suback{" <<
192 "pid:" << v.packet_id() << ",[";
193 auto b = v.entries().cbegin();
194 auto e = v.entries().cend();
195 if (b != e) {
196 o << *b++;
197 }
198 for (; b != e; ++b) {
199 o << "," << *b;
200 }
201 o << "]}";
202 return o;
203}
204
210
211} // namespace async_mqtt::v3_1_1
212
213#endif // ASYNC_MQTT_PACKET_V3_1_1_SUBACK_HPP
Definition packet_variant.hpp:49
buffer that has string_view interface This class provides string_view interface. This class hold stri...
Definition buffer.hpp:30
MQTT SUBACK packet (v3.1.1)
Definition v3_1_1_suback.hpp:40
packet_id_t packet_id() const
Get packet_id.
Definition v3_1_1_suback.hpp:168
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v3_1_1_suback.hpp:126
std::vector< suback_return_code > const & entries() const
Get entries.
Definition v3_1_1_suback.hpp:176
basic_suback_packet(packet_id_t packet_id, std::vector< suback_return_code > params)
constructor
Definition v3_1_1_suback.hpp:49
std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v3_1_1_suback.hpp:156
std::size_t size() const
Get packet size.
Definition v3_1_1_suback.hpp:145
suback_return_code
MQTT suback_return_code.
Definition suback_return_code.hpp:24