async_mqtt 5.0.0
Loading...
Searching...
No Matches
v5_puback.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_PUBACK_HPP)
8#define ASYNC_MQTT_PACKET_V5_PUBACK_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
43template <std::size_t PacketIdBytes>
45public:
46 using packet_id_t = typename packet_id_type<PacketIdBytes>::type;
47
58 packet_id_t packet_id,
59 puback_reason_code reason_code,
60 properties props
63 optional<puback_reason_code>(reason_code),
64 force_move(props)
65 }
66 {}
67
74 packet_id_t packet_id
77 nullopt,
78 properties{}
79 }
80 {}
81
90 packet_id_t packet_id,
91 puback_reason_code reason_code
94 optional<puback_reason_code>(reason_code),
95 properties{}
96 }
97 {}
98
100 // fixed_header
101 if (buf.empty()) {
102 throw make_error(
103 errc::bad_message,
104 "v5::puback_packet fixed_header doesn't exist"
105 );
106 }
107 fixed_header_ = static_cast<std::uint8_t>(buf.front());
108 buf.remove_prefix(1);
109
110 // remaining_length
111 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
112 remaining_length_ = *vl_opt;
113 }
114 else {
115 throw make_error(errc::bad_message, "v5::puback_packet remaining length is invalid");
116 }
117
118 // packet_id
119 if (!insert_advance(buf, packet_id_)) {
120 throw make_error(
121 errc::bad_message,
122 "v5::puback_packet packet_id doesn't exist"
123 );
124 }
125
126 if (remaining_length_ == PacketIdBytes) {
127 if (!buf.empty()) {
128 throw make_error(errc::bad_message, "v5::puback_packet remaining length is invalid");
129 }
130 return;
131 }
132
133 // reason_code
134 reason_code_.emplace(static_cast<puback_reason_code>(buf.front()));
135 buf.remove_prefix(1);
136 switch (*reason_code_) {
137 case puback_reason_code::success:
138 case puback_reason_code::no_matching_subscribers:
139 case puback_reason_code::unspecified_error:
140 case puback_reason_code::implementation_specific_error:
141 case puback_reason_code::not_authorized:
142 case puback_reason_code::topic_name_invalid:
143 case puback_reason_code::packet_identifier_in_use:
144 case puback_reason_code::quota_exceeded:
145 case puback_reason_code::payload_format_invalid:
146 break;
147 default:
148 throw make_error(
149 errc::bad_message,
150 "v5::puback_packet connect reason_code is invalid"
151 );
152 break;
153 }
154
155 if (remaining_length_ == 3) {
156 if (!buf.empty()) {
157 throw make_error(errc::bad_message, "v5::puback_packet remaining length is invalid");
158 }
159 return;
160 }
161
162 // property
163 auto it = buf.begin();
164 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
165 property_length_ = *pl_opt;
166 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
167 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
168 if (buf.size() < property_length_) {
169 throw make_error(
170 errc::bad_message,
171 "v5::puback_packet properties_don't match its length"
172 );
173 }
174 auto prop_buf = buf.substr(0, property_length_);
175 props_ = make_properties(prop_buf, property_location::puback);
176 buf.remove_prefix(property_length_);
177 }
178 else {
179 throw make_error(
180 errc::bad_message,
181 "v5::puback_packet property_length is invalid"
182 );
183 }
184
185 if (!buf.empty()) {
186 throw make_error(
187 errc::bad_message,
188 "v5::puback_packet properties don't match its length"
189 );
190 }
191 }
192
193 constexpr control_packet_type type() const {
194 return control_packet_type::puback;
195 }
196
202 std::vector<as::const_buffer> const_buffer_sequence() const {
203 std::vector<as::const_buffer> ret;
205 ret.emplace_back(as::buffer(&fixed_header_, 1));
206 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
207
208 ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
209
210 if (reason_code_) {
211 ret.emplace_back(as::buffer(&*reason_code_, 1));
212 if (property_length_buf_.size() != 0) {
213 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
214 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
215 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
216 }
217 }
218
219 return ret;
220 }
221
226 std::size_t size() const {
227 return
228 1 + // fixed header
229 remaining_length_buf_.size() +
230 remaining_length_;
231 }
232
237 constexpr std::size_t num_of_const_buffer_sequence() const {
238 return
239 1 + // fixed header
240 1 + // remaining length
241 1 + // packet_id
242 [&] () -> std::size_t {
243 if (reason_code_) {
244 return
245 1 + // reason_code
246 [&] () -> std::size_t {
247 if (property_length_buf_.size() == 0) return 0;
248 return
249 1 + // property length
250 async_mqtt::num_of_const_buffer_sequence(props_);
251 }();
252 }
253 return 0;
254 }();
255 }
256
261 packet_id_t packet_id() const {
262 return endian_load<packet_id_t>(packet_id_.data());
263 }
264
269 puback_reason_code code() const {
270 if (reason_code_) return *reason_code_;
271 return puback_reason_code::success;
272 }
273
278 properties const& props() const {
279 return props_;
280 }
281
282 friend
283 inline std::ostream& operator<<(std::ostream& o, basic_puback_packet<PacketIdBytes> const& v) {
284 o <<
285 "v5::puback{" <<
286 "pid:" << v.packet_id();
287 if (v.reason_code_) {
288 o << ",rc:" << *v.reason_code_;
289 }
290 if (!v.props().empty()) {
291 o << ",ps:" << v.props();
292 };
293 o << "}";
294 return o;
295 }
296
297private:
299 packet_id_t packet_id,
300 optional<puback_reason_code> reason_code,
301 properties props
302 )
303 : fixed_header_{
304 make_fixed_header(control_packet_type::puback, 0b0000)
305 },
306 remaining_length_{
307 PacketIdBytes
308 },
309 packet_id_(packet_id_.capacity()),
310 reason_code_{reason_code},
311 property_length_(async_mqtt::size(props)),
312 props_(force_move(props))
313 {
314 using namespace std::literals;
315 endian_store(packet_id, packet_id_.data());
316
317 auto guard = unique_scope_guard(
318 [&] {
319 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
320 for (auto e : rb) {
321 remaining_length_buf_.push_back(e);
322 }
323 }
324 );
325
326 if (!reason_code_) return;
327 remaining_length_ += 1;
328
329 if (property_length_ == 0) return;
330
331 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
332 for (auto e : pb) {
333 property_length_buf_.push_back(e);
334 }
335
336 for (auto const& prop : props_) {
337 auto id = prop.id();
338 if (!validate_property(property_location::puback, id)) {
339 throw make_error(
340 errc::bad_message,
341 "v5::puback_packet property "s + id_to_str(id) + " is not allowed"
342 );
343 }
344 }
345
346 remaining_length_ += property_length_buf_.size() + property_length_;
347 }
348
349private:
350 std::uint8_t fixed_header_;
351 std::size_t remaining_length_;
352 static_vector<char, 4> remaining_length_buf_;
353 static_vector<char, PacketIdBytes> packet_id_;
354
355 optional<puback_reason_code> reason_code_;
356
357 std::size_t property_length_ = 0;
358 static_vector<char, 4> property_length_buf_;
359 properties props_;
360};
361
362using puback_packet = basic_puback_packet<2>;
363
364} // namespace async_mqtt::v5
365
366#endif // ASYNC_MQTT_PACKET_V5_PUBACK_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 PUBACK packet (v5)
Definition v5_puback.hpp:44
properties const & props() const
Definition v5_puback.hpp:278
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_puback.hpp:202
basic_puback_packet(packet_id_t packet_id, puback_reason_code reason_code)
constructor
Definition v5_puback.hpp:89
basic_puback_packet(packet_id_t packet_id, puback_reason_code reason_code, properties props)
constructor
Definition v5_puback.hpp:57
std::size_t size() const
Get packet size.
Definition v5_puback.hpp:226
puback_reason_code code() const
Definition v5_puback.hpp:269
basic_puback_packet(packet_id_t packet_id)
constructor
Definition v5_puback.hpp:73
packet_id_t packet_id() const
Get packet_id.
Definition v5_puback.hpp:261
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_puback.hpp:237