async_mqtt 4.1.0
Loading...
Searching...
No Matches
v5_unsuback.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_UNSUBACK_HPP)
8#define ASYNC_MQTT_PACKET_V5_UNSUBACK_HPP
9
10#include <async_mqtt/exception.hpp>
11#include <async_mqtt/buffer.hpp>
12
13#include <async_mqtt/util/move.hpp>
14#include <async_mqtt/util/static_vector.hpp>
15#include <async_mqtt/util/endian_convert.hpp>
16
17#include <async_mqtt/packet/packet_id_type.hpp>
18#include <async_mqtt/packet/fixed_header.hpp>
19#include <async_mqtt/packet/reason_code.hpp>
20#include <async_mqtt/packet/property_variant.hpp>
21#include <async_mqtt/packet/copy_to_static_vector.hpp>
22
23namespace async_mqtt::v5 {
24
25namespace as = boost::asio;
26
34template <std::size_t PacketIdBytes>
36public:
37 using packet_id_t = typename packet_id_type<PacketIdBytes>::type;
38
47 packet_id_t packet_id,
48 std::vector<unsuback_reason_code> params,
49 properties props = {}
50 )
51 : fixed_header_{make_fixed_header(control_packet_type::unsuback, 0b0000)},
52 entries_{force_move(params)},
53 remaining_length_{PacketIdBytes + entries_.size()},
54 property_length_(async_mqtt::size(props)),
55 props_(force_move(props))
56 {
57 using namespace std::literals;
58 endian_store(packet_id, packet_id_.data());
59
60 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
61 for (auto e : pb) {
62 property_length_buf_.push_back(e);
63 }
64
65 for (auto const& prop : props_) {
66 auto id = prop.id();
67 if (!validate_property(property_location::unsuback, id)) {
68 throw make_error(
69 errc::bad_message,
70 "v5::unsuback_packet property "s + id_to_str(id) + " is not allowed"
71 );
72 }
73 }
74
75 remaining_length_ += property_length_buf_.size() + property_length_;
76 remaining_length_buf_ = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
77 }
78
79 basic_unsuback_packet(buffer buf) {
80 // fixed_header
81 if (buf.empty()) {
82 throw make_error(
83 errc::bad_message,
84 "v5::unsuback_packet fixed_header doesn't exist"
85 );
86 }
87 fixed_header_ = static_cast<std::uint8_t>(buf.front());
88 buf.remove_prefix(1);
89 auto cpt_opt = get_control_packet_type_with_check(static_cast<std::uint8_t>(fixed_header_));
90 if (!cpt_opt || *cpt_opt != control_packet_type::unsuback) {
91 throw make_error(
92 errc::bad_message,
93 "v5::unsuback_packet fixed_header is invalid"
94 );
95 }
96
97 // remaining_length
98 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
99 remaining_length_ = *vl_opt;
100 }
101 else {
102 throw make_error(errc::bad_message, "v5::unsuback_packet remaining length is invalid");
103 }
104 if (remaining_length_ != buf.size()) {
105 throw make_error(errc::bad_message, "v5::unsuback_packet remaining length doesn't match buf.size()");
106 }
107
108 // packet_id
109 if (!copy_advance(buf, packet_id_)) {
110 throw make_error(
111 errc::bad_message,
112 "v5::unsuback_packet packet_id doesn't exist"
113 );
114 }
115
116 // property
117 auto it = buf.begin();
118 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
119 property_length_ = *pl_opt;
120 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
121 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
122 if (buf.size() < property_length_) {
123 throw make_error(
124 errc::bad_message,
125 "v5::unsuback_packet properties_don't match its length"
126 );
127 }
128 auto prop_buf = buf.substr(0, property_length_);
129 props_ = make_properties(prop_buf, property_location::unsuback);
130 buf.remove_prefix(property_length_);
131 }
132 else {
133 throw make_error(
134 errc::bad_message,
135 "v5::unsuback_packet property_length is invalid"
136 );
137 }
138
139 if (remaining_length_ == 0) {
140 throw make_error(errc::bad_message, "v5::unsuback_packet doesn't have entries");
141 }
142
143 while (!buf.empty()) {
144 // reason_code
145 if (buf.empty()) {
146 throw make_error(
147 errc::bad_message,
148 "v5::unsuback_packet unsuback_reason_code doesn't exist"
149 );
150 }
151 auto rc = static_cast<unsuback_reason_code>(buf.front());
152 entries_.emplace_back(rc);
153 buf.remove_prefix(1);
154 }
155 }
156
157 constexpr control_packet_type type() const {
158 return control_packet_type::unsuback;
159 }
160
166 std::vector<as::const_buffer> const_buffer_sequence() const {
167 std::vector<as::const_buffer> ret;
169
170 ret.emplace_back(as::buffer(&fixed_header_, 1));
171
172 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
173
174 ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
175
176 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
177 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
178 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
179
180 ret.emplace_back(as::buffer(entries_.data(), entries_.size()));
181
182 return ret;
183 }
184
189 std::size_t size() const {
190 return
191 1 + // fixed header
192 remaining_length_buf_.size() +
193 remaining_length_;
194 }
195
200 std::size_t num_of_const_buffer_sequence() const {
201 return
202 1 + // fixed header
203 1 + // remaining length
204 1 + // packet id
205 [&] () -> std::size_t {
206 if (property_length_buf_.size() == 0) return 0;
207 return
208 1 + // property length
209 async_mqtt::num_of_const_buffer_sequence(props_);
210 }() +
211 1; // unsuback_reason_code vector
212 }
213
218 packet_id_t packet_id() const {
219 return endian_load<packet_id_t>(packet_id_.data());
220 }
221
226 std::vector<unsuback_reason_code> const& entries() const {
227 return entries_;
228 }
229
234 properties const& props() const {
235 return props_;
236 }
237
238private:
239 std::uint8_t fixed_header_;
240 std::vector<unsuback_reason_code> entries_;
242 std::size_t remaining_length_;
243 static_vector<char, 4> remaining_length_buf_;
244
245 std::size_t property_length_ = 0;
246 static_vector<char, 4> property_length_buf_;
247 properties props_;
248};
249
250template <std::size_t PacketIdBytes>
251inline std::ostream& operator<<(std::ostream& o, basic_unsuback_packet<PacketIdBytes> const& v) {
252 o <<
253 "v5::unsuback{" <<
254 "pid:" << v.packet_id() << ",[";
255 auto b = v.entries().cbegin();
256 auto e = v.entries().cend();
257 if (b != e) {
258 o << *b++;
259 }
260 for (; b != e; ++b) {
261 o << "," << *b;
262 }
263 o << "]";
264 if (!v.props().empty()) {
265 o << ",ps:" << v.props();
266 };
267 o << "}";
268 return o;
269}
270
271using unsuback_packet = basic_unsuback_packet<2>;
272
273} // namespace async_mqtt::v5
274
275#endif // ASYNC_MQTT_PACKET_V5_UNSUBACK_HPP
Definition packet_variant.hpp:49
MQTT UNSUBACK packet (v5)
Definition v5_unsuback.hpp:35
packet_id_t packet_id() const
Get packet_id.
Definition v5_unsuback.hpp:218
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_unsuback.hpp:166
std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_unsuback.hpp:200
std::size_t size() const
Get packet size.
Definition v5_unsuback.hpp:189
basic_unsuback_packet(packet_id_t packet_id, std::vector< unsuback_reason_code > params, properties props={})
constructor
Definition v5_unsuback.hpp:46
properties const & props() const
Definition v5_unsuback.hpp:234
std::vector< unsuback_reason_code > const & entries() const
Get entries.
Definition v5_unsuback.hpp:226