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