async_mqtt 4.1.0
Loading...
Searching...
No Matches
v5_connack.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_CONNACK_HPP)
8#define ASYNC_MQTT_PACKET_V5_CONNACK_HPP
9
10#include <utility>
11#include <numeric>
12
13#include <async_mqtt/exception.hpp>
14#include <async_mqtt/buffer.hpp>
15
16#include <async_mqtt/util/move.hpp>
17#include <async_mqtt/util/static_vector.hpp>
18
19#include <async_mqtt/packet/fixed_header.hpp>
20#include <async_mqtt/packet/session_present.hpp>
21#include <async_mqtt/packet/reason_code.hpp>
22#include <async_mqtt/packet/property_variant.hpp>
23#include <async_mqtt/packet/copy_to_static_vector.hpp>
24
25namespace async_mqtt::v5 {
26
27namespace as = boost::asio;
28
36public:
37
49 bool session_present,
50 connect_reason_code reason_code,
51 properties props = {}
52 )
53 : fixed_header_{
54 make_fixed_header(control_packet_type::connack, 0b0000)
55 },
56 remaining_length_(
57 1 + // connect acknowledge flags
58 1 // reason code
59 ),
60 connect_acknowledge_flags_(
61 session_present ? 1 : 0
62 ),
63 reason_code_{reason_code},
64 property_length_{async_mqtt::size(props)},
65 props_(force_move(props))
66 {
67 using namespace std::literals;
68 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
69 for (auto e : pb) {
70 property_length_buf_.push_back(e);
71 }
72
73 for (auto const& prop : props_) {
74 auto id = prop.id();
75 if (!validate_property(property_location::connack, id)) {
76 throw make_error(
77 errc::bad_message,
78 "v5::connack_packet property "s + id_to_str(id) + " is not allowed"
79 );
80 }
81 }
82
83 remaining_length_ += property_length_buf_.size() + property_length_;
84 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
85 for (auto e : rb) {
86 remaining_length_buf_.push_back(e);
87 }
88 }
89
90 connack_packet(buffer buf) {
91 // fixed_header
92 if (buf.empty()) {
93 throw make_error(
94 errc::bad_message,
95 "v5::connack_packet fixed_header doesn't exist"
96 );
97 }
98 fixed_header_ = static_cast<std::uint8_t>(buf.front());
99 buf.remove_prefix(1);
100 auto cpt_opt = get_control_packet_type_with_check(fixed_header_);
101 if (!cpt_opt || *cpt_opt != control_packet_type::connack) {
102 throw make_error(
103 errc::bad_message,
104 "v5::connack_packet fixed_header is invalid"
105 );
106 }
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::connack_packet remaining length is invalid");
114 }
115 if (remaining_length_ != buf.size()) {
116 throw make_error(errc::bad_message, "v5::connack_packet remaining length doesn't match buf.size()");
117 }
118
119 // connect_acknowledge_flags
120 if (buf.size() < 1) {
121 throw make_error(
122 errc::bad_message,
123 "v5::connack_packet connect acknowledge flags don't exist"
124 );
125 }
126 connect_acknowledge_flags_ = static_cast<std::uint8_t>(buf.front());
127 buf.remove_prefix(1);
128 if ((connect_acknowledge_flags_ & 0b11111110)!= 0) {
129 throw make_error(
130 errc::bad_message,
131 "v5::connack_packet connect acknowledge flags is invalid"
132 );
133 }
134 // reason_code
135 reason_code_ = static_cast<connect_reason_code>(buf.front());
136 buf.remove_prefix(1);
137 switch (reason_code_) {
138 case connect_reason_code::success:
139 case connect_reason_code::unspecified_error:
140 case connect_reason_code::malformed_packet:
141 case connect_reason_code::protocol_error:
142 case connect_reason_code::implementation_specific_error:
143 case connect_reason_code::unsupported_protocol_version:
144 case connect_reason_code::client_identifier_not_valid:
145 case connect_reason_code::bad_user_name_or_password:
146 case connect_reason_code::not_authorized:
147 case connect_reason_code::server_unavailable:
148 case connect_reason_code::server_busy:
149 case connect_reason_code::banned:
150 case connect_reason_code::server_shutting_down:
151 case connect_reason_code::bad_authentication_method:
152 case connect_reason_code::topic_name_invalid:
153 case connect_reason_code::packet_too_large:
154 case connect_reason_code::quota_exceeded:
155 case connect_reason_code::payload_format_invalid:
156 case connect_reason_code::retain_not_supported:
157 case connect_reason_code::qos_not_supported:
158 case connect_reason_code::use_another_server:
159 case connect_reason_code::server_moved:
160 case connect_reason_code::connection_rate_exceeded:
161 break;
162 default:
163 throw make_error(
164 errc::bad_message,
165 "v5::connack_packet connect reason_code is invalid"
166 );
167 break;
168 }
169
170 // property
171 auto it = buf.begin();
172 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
173 property_length_ = *pl_opt;
174 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
175 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
176 if (buf.size() < property_length_) {
177 throw make_error(
178 errc::bad_message,
179 "v5::connack_packet properties_don't match its length"
180 );
181 }
182 auto prop_buf = buf.substr(0, property_length_);
183 props_ = make_properties(prop_buf, property_location::connack);
184 buf.remove_prefix(property_length_);
185 }
186 else {
187 throw make_error(
188 errc::bad_message,
189 "v5::connack_packet property_length is invalid"
190 );
191 }
192
193 if (!buf.empty()) {
194 throw make_error(
195 errc::bad_message,
196 "v5::connack_packet properties don't match its length"
197 );
198 }
199 }
200
201 constexpr control_packet_type type() const {
202 return control_packet_type::connack;
203 }
204
210 std::vector<as::const_buffer> const_buffer_sequence() const {
211 std::vector<as::const_buffer> ret;
213
214 ret.emplace_back(as::buffer(&fixed_header_, 1));
215 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
216 ret.emplace_back(as::buffer(&connect_acknowledge_flags_, 1));
217 ret.emplace_back(as::buffer(&reason_code_, 1));
218
219 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
220 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
221 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
222
223 return ret;
224 }
225
230 std::size_t size() const {
231 return
232 1 + // fixed header
233 remaining_length_buf_.size() +
234 remaining_length_;
235 }
236
241 std::size_t num_of_const_buffer_sequence() const {
242 return
243 1 + // fixed header
244 1 + // remaining length
245 1 + // connect_acknowledge_flags
246 1 + // reason_code
247 1 + // property length
248 async_mqtt::num_of_const_buffer_sequence(props_);
249 }
250
251 bool session_present() const {
252 return is_session_present(static_cast<char>(connect_acknowledge_flags_));
253 }
254
259 connect_reason_code code() const {
260 return reason_code_;
261 }
262
267 properties const& props() const {
268 return props_;
269 }
270
271private:
272 std::uint8_t fixed_header_;
273
274 std::size_t remaining_length_;
275 boost::container::static_vector<char, 4> remaining_length_buf_;
276
277 std::uint8_t connect_acknowledge_flags_;
278
279 connect_reason_code reason_code_;
280
281 std::size_t property_length_;
282 boost::container::static_vector<char, 4> property_length_buf_;
283 properties props_;
284};
285
286inline std::ostream& operator<<(std::ostream& o, connack_packet const& v) {
287 o <<
288 "v5::connack{" <<
289 "rc:" << v.code() << "," <<
290 "sp:" << v.session_present();
291 if (!v.props().empty()) {
292 o << ",ps:" << v.props();
293 };
294 o << "}";
295 return o;
296}
297
298} // namespace async_mqtt::v5
299
300#endif // ASYNC_MQTT_PACKET_V5_CONNACK_HPP
Definition packet_variant.hpp:49
Definition v5_connack.hpp:35
std::size_t size() const
Get packet size.
Definition v5_connack.hpp:230
properties const & props() const
Definition v5_connack.hpp:267
std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_connack.hpp:241
connack_packet(bool session_present, connect_reason_code reason_code, properties props={})
Definition v5_connack.hpp:48
connect_reason_code code() const
Definition v5_connack.hpp:259
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_connack.hpp:210