async_mqtt 5.0.0
Loading...
Searching...
No Matches
v5_pubrel.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_V5_PUBREL_HPP)
8#define ASYNC_MQTT_PACKET_V5_PUBREL_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#include <async_mqtt/util/scope_guard.hpp>
22
23#include <async_mqtt/packet/fixed_header.hpp>
24#include <async_mqtt/packet/packet_id_type.hpp>
25#include <async_mqtt/packet/reason_code.hpp>
26#include <async_mqtt/packet/property_variant.hpp>
27#include <async_mqtt/packet/copy_to_static_vector.hpp>
28
29namespace async_mqtt::v5 {
30
31namespace as = boost::asio;
32
44template <std::size_t PacketIdBytes>
46public:
47 using packet_id_t = typename packet_id_type<PacketIdBytes>::type;
48
58 packet_id_t packet_id,
59 pubrel_reason_code reason_code,
60 properties props
63 optional<pubrel_reason_code>(reason_code),
64 force_move(props)
65 }
66 {}
67
73 packet_id_t packet_id
76 nullopt,
77 properties{}
78 }
79 {}
80
88 packet_id_t packet_id,
89 pubrel_reason_code reason_code
92 optional<pubrel_reason_code>(reason_code),
93 properties{}
94 }
95 {}
96
98 // fixed_header
99 if (buf.empty()) {
100 throw make_error(
101 errc::bad_message,
102 "v5::pubrel_packet fixed_header doesn't exist"
103 );
104 }
105 fixed_header_ = static_cast<std::uint8_t>(buf.front());
106 buf.remove_prefix(1);
107
108 // remaining_length
109 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
110 remaining_length_ = *vl_opt;
111 }
112 else {
113 throw make_error(errc::bad_message, "v5::pubrel_packet remaining length is invalid");
114 }
115
116 // packet_id
117 if (!insert_advance(buf, packet_id_)) {
118 throw make_error(
119 errc::bad_message,
120 "v5::pubrel_packet packet_id doesn't exist"
121 );
122 }
123
124 if (remaining_length_ == PacketIdBytes) {
125 if (!buf.empty()) {
126 throw make_error(errc::bad_message, "v5::pubrel_packet remaining length is invalid");
127 }
128 return;
129 }
130
131 // reason_code
132 reason_code_.emplace(static_cast<pubrel_reason_code>(buf.front()));
133 buf.remove_prefix(1);
134 switch (*reason_code_) {
135 case pubrel_reason_code::success:
136 case pubrel_reason_code::packet_identifier_not_found:
137 break;
138 default:
139 throw make_error(
140 errc::bad_message,
141 "v5::pubrel_packet connect reason_code is invalid"
142 );
143 break;
144 }
145
146 if (remaining_length_ == 3) {
147 if (!buf.empty()) {
148 throw make_error(errc::bad_message, "v5::pubrel_packet remaining length is invalid");
149 }
150 return;
151 }
152
153 // property
154 auto it = buf.begin();
155 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
156 property_length_ = *pl_opt;
157 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
158 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
159 if (buf.size() < property_length_) {
160 throw make_error(
161 errc::bad_message,
162 "v5::pubrel_packet properties don't match its length"
163 );
164 }
165 auto prop_buf = buf.substr(0, property_length_);
166 props_ = make_properties(prop_buf, property_location::pubrel);
167 buf.remove_prefix(property_length_);
168 }
169 else {
170 throw make_error(
171 errc::bad_message,
172 "v5::pubrel_packet property_length is invalid"
173 );
174 }
175
176 if (!buf.empty()) {
177 throw make_error(
178 errc::bad_message,
179 "v5::pubrel_packet properties don't match its length"
180 );
181 }
182 }
183
184 constexpr control_packet_type type() const {
185 return control_packet_type::pubrel;
186 }
187
193 std::vector<as::const_buffer> const_buffer_sequence() const {
194 std::vector<as::const_buffer> ret;
196 ret.emplace_back(as::buffer(&fixed_header_, 1));
197 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
198
199 ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
200
201 if (reason_code_) {
202 ret.emplace_back(as::buffer(&*reason_code_, 1));
203
204 if (property_length_buf_.size() != 0) {
205 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
206 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
207 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
208 }
209 }
210
211 return ret;
212 }
213
218 std::size_t size() const {
219 return
220 1 + // fixed header
221 remaining_length_buf_.size() +
222 remaining_length_;
223 }
224
229 constexpr std::size_t num_of_const_buffer_sequence() const {
230 return
231 1 + // fixed header
232 1 + // remaining length
233 1 + // packet_id
234 [&] () -> std::size_t {
235 if (reason_code_) {
236 return
237 1 + // reason_code
238 [&] () -> std::size_t {
239 if (property_length_buf_.size() == 0) return 0;
240 return
241 1 + // property length
242 async_mqtt::num_of_const_buffer_sequence(props_);
243 }();
244 }
245 return 0;
246 }();
247 }
248
253 packet_id_t packet_id() const {
254 return endian_load<packet_id_t>(packet_id_.data());
255 }
256
261 pubrel_reason_code code() const {
262 if (reason_code_) return *reason_code_;
263 return pubrel_reason_code::success;
264 }
265
270 properties const& props() const {
271 return props_;
272 }
273
274 friend
275 inline std::ostream& operator<<(std::ostream& o, basic_pubrel_packet<PacketIdBytes> const& v) {
276 o <<
277 "v5::pubrel{" <<
278 "pid:" << v.packet_id();
279 if (v.reason_code_) {
280 o << ",rc:" << *v.reason_code_;
281 }
282 if (!v.props().empty()) {
283 o << ",ps:" << v.props();
284 };
285 o << "}";
286 return o;
287 }
288
289private:
291 packet_id_t packet_id,
292 optional<pubrel_reason_code> reason_code,
293 properties props
294 )
295 : fixed_header_{
296 make_fixed_header(control_packet_type::pubrel, 0b0010)
297 },
298 remaining_length_{
299 PacketIdBytes
300 },
301 packet_id_(packet_id_.capacity()),
302 reason_code_{reason_code},
303 property_length_(async_mqtt::size(props)),
304 props_(force_move(props))
305 {
306 using namespace std::literals;
307 endian_store(packet_id, packet_id_.data());
308
309 auto guard = unique_scope_guard(
310 [&] {
311 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
312 for (auto e : rb) {
313 remaining_length_buf_.push_back(e);
314 }
315 }
316 );
317
318 if (!reason_code_) return;
319 remaining_length_ += 1;
320
321 if (property_length_ == 0) return;
322
323 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
324 for (auto e : pb) {
325 property_length_buf_.push_back(e);
326 }
327
328 for (auto const& prop : props_) {
329 auto id = prop.id();
330 if (!validate_property(property_location::pubrel, id)) {
331 throw make_error(
332 errc::bad_message,
333 "v5::pubrel_packet property "s + id_to_str(id) + " is not allowed"
334 );
335 }
336 }
337
338 remaining_length_ += property_length_buf_.size() + property_length_;
339 }
340
341private:
342 std::uint8_t fixed_header_;
343 std::size_t remaining_length_;
344 static_vector<char, 4> remaining_length_buf_;
345 static_vector<char, PacketIdBytes> packet_id_;
346
347 optional<pubrel_reason_code> reason_code_;
348
349 std::size_t property_length_ = 0;
350 static_vector<char, 4> property_length_buf_;
351 properties props_;
352};
353
354using pubrel_packet = basic_pubrel_packet<2>;
355
356} // namespace async_mqtt::v5
357
358#endif // ASYNC_MQTT_PACKET_V5_PUBREL_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
buffer substr(size_type pos=0, size_type count=npos) const &
get substring The returned buffer ragnge is the same as string_view::substr(). In addition the lifeti...
Definition buffer.hpp:201
MQTT PUBREL packet (v5)
Definition v5_pubrel.hpp:45
basic_pubrel_packet(packet_id_t packet_id, pubrel_reason_code reason_code)
constructor
Definition v5_pubrel.hpp:87
std::size_t size() const
Get packet size.
Definition v5_pubrel.hpp:218
basic_pubrel_packet(packet_id_t packet_id)
constructor
Definition v5_pubrel.hpp:72
basic_pubrel_packet(packet_id_t packet_id, pubrel_reason_code reason_code, properties props)
constructor
Definition v5_pubrel.hpp:57
properties const & props() const
Definition v5_pubrel.hpp:270
pubrel_reason_code code() const
Definition v5_pubrel.hpp:261
packet_id_t packet_id() const
Get packet_id.
Definition v5_pubrel.hpp:253
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_pubrel.hpp:193
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_pubrel.hpp:229