async_mqtt 4.1.0
Loading...
Searching...
No Matches
v5_auth.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_AUTH_HPP)
8#define ASYNC_MQTT_PACKET_V5_AUTH_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
40public:
41
50 auth_reason_code reason_code,
51 properties props
52 ) : auth_packet{
53 optional<auth_reason_code>(reason_code),
54 force_move(props)
55 }
56 {}
57
62 ) : auth_packet{
63 nullopt,
64 properties{}
65 }
66 {}
67
74 auth_reason_code reason_code
75 ) : auth_packet{
76 optional<auth_reason_code>(reason_code),
77 properties{}
78 }
79 {}
80
81 auth_packet(buffer buf) {
82 // fixed_header
83 if (buf.empty()) {
84 throw make_error(
85 errc::bad_message,
86 "v5::auth_packet fixed_header doesn't exist"
87 );
88 }
89 fixed_header_ = static_cast<std::uint8_t>(buf.front());
90 buf.remove_prefix(1);
91
92 // remaining_length
93 if (auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
94 remaining_length_ = *vl_opt;
95 }
96 else {
97 throw make_error(errc::bad_message, "v5::auth_packet remaining length is invalid");
98 }
99
100 if (remaining_length_ == 0) {
101 if (!buf.empty()) {
102 throw make_error(errc::bad_message, "v5::auth_packet remaining length is invalid");
103 }
104 return;
105 }
106
107 // connect_reason_code
108 reason_code_.emplace(static_cast<auth_reason_code>(buf.front()));
109 buf.remove_prefix(1);
110 switch (*reason_code_) {
111 case auth_reason_code::success:
112 case auth_reason_code::continue_authentication:
113 case auth_reason_code::re_authenticate:
114 break;
115 default:
116 throw make_error(
117 errc::bad_message,
118 "v5::auth_packet connect reason_code is invalid"
119 );
120 break;
121 }
122
123 if (remaining_length_ == 1) {
124 if (!buf.empty()) {
125 throw make_error(errc::bad_message, "v5::auth_packet remaining length is invalid");
126 }
127 return;
128 }
129
130 // property
131 auto it = buf.begin();
132 if (auto pl_opt = variable_bytes_to_val(it, buf.end())) {
133 property_length_ = *pl_opt;
134 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
135 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
136 if (buf.size() < property_length_) {
137 throw make_error(
138 errc::bad_message,
139 "v5::auth_packet properties_don't match its length"
140 );
141 }
142 auto prop_buf = buf.substr(0, property_length_);
143 props_ = make_properties(prop_buf, property_location::auth);
144 buf.remove_prefix(property_length_);
145 }
146 else {
147 throw make_error(
148 errc::bad_message,
149 "v5::auth_packet property_length is invalid"
150 );
151 }
152
153 if (!buf.empty()) {
154 throw make_error(
155 errc::bad_message,
156 "v5::auth_packet properties don't match its length"
157 );
158 }
159 }
160
161 constexpr control_packet_type type() const {
162 return control_packet_type::auth;
163 }
164
170 std::vector<as::const_buffer> const_buffer_sequence() const {
171 std::vector<as::const_buffer> ret;
173 ret.emplace_back(as::buffer(&fixed_header_, 1));
174 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
175
176 if (reason_code_) {
177 ret.emplace_back(as::buffer(&*reason_code_, 1));
178
179 if (property_length_buf_.size() != 0) {
180 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
181 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
182 std::move(props_cbs.begin(), props_cbs.end(), std::back_inserter(ret));
183 }
184 }
185
186 return ret;
187 }
188
193 std::size_t size() const {
194 return
195 1 + // fixed header
196 remaining_length_buf_.size() +
197 remaining_length_;
198 }
199
204 std::size_t num_of_const_buffer_sequence() const {
205 return
206 1 + // fixed header
207 1 + // remaining length
208 [&] () -> std::size_t {
209 if (reason_code_) {
210 return
211 1 + // reason_code
212 [&] () -> std::size_t {
213 if (property_length_buf_.size() == 0) return 0;
214 return
215 1 + // property length
216 async_mqtt::num_of_const_buffer_sequence(props_);
217 }();
218 }
219 return 0;
220 }();
221 }
222
227 auth_reason_code code() const {
228 if (reason_code_) return *reason_code_;
229 return auth_reason_code::success;
230 }
231
236 properties const& props() const {
237 return props_;
238 }
239
240 friend
241 inline std::ostream& operator<<(std::ostream& o, auth_packet const& v) {
242 o <<
243 "v5::auth{";
244 if (v.reason_code_) {
245 o << "rc:" << *v.reason_code_;
246 }
247 if (!v.props().empty()) {
248 o << ",ps:" << v.props();
249 };
250 o << "}";
251 return o;
252 }
253
254private:
256 optional<auth_reason_code> reason_code,
257 properties props
258 )
259 : fixed_header_{
260 make_fixed_header(control_packet_type::auth, 0b0000)
261 },
262 remaining_length_{
263 0
264 },
265 reason_code_{reason_code},
266 property_length_(async_mqtt::size(props)),
267 props_(force_move(props))
268 {
269 using namespace std::literals;
270
271 auto guard = unique_scope_guard(
272 [&] {
273 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
274 for (auto e : rb) {
275 remaining_length_buf_.push_back(e);
276 }
277 }
278 );
279
280 if (!reason_code_) return;
281 remaining_length_ += 1;
282
283 if (property_length_ == 0) return;
284
285 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
286 for (auto e : pb) {
287 property_length_buf_.push_back(e);
288 }
289
290 for (auto const& prop : props_) {
291 auto id = prop.id();
292 if (!validate_property(property_location::auth, id)) {
293 throw make_error(
294 errc::bad_message,
295 "v5::auth_packet property "s + id_to_str(id) + " is not allowed"
296 );
297 }
298 }
299
300 remaining_length_ += property_length_buf_.size() + property_length_;
301 }
302
303private:
304 std::uint8_t fixed_header_;
305 std::size_t remaining_length_;
306 static_vector<char, 4> remaining_length_buf_;
307
308 optional<auth_reason_code> reason_code_;
309
310 std::size_t property_length_ = 0;
311 static_vector<char, 4> property_length_buf_;
312 properties props_;
313};
314
315} // namespace async_mqtt::v5
316
317#endif // ASYNC_MQTT_PACKET_V5_AUTH_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 AUTH packet (v35)
Definition v5_auth.hpp:39
std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition v5_auth.hpp:204
std::size_t size() const
Get packet size.
Definition v5_auth.hpp:193
properties const & props() const
Definition v5_auth.hpp:236
auth_packet(auth_reason_code reason_code, properties props)
constructor
Definition v5_auth.hpp:49
auth_reason_code code() const
Definition v5_auth.hpp:227
auth_packet(auth_reason_code reason_code)
constructor
Definition v5_auth.hpp:73
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition v5_auth.hpp:170
auth_packet()
constructor
Definition v5_auth.hpp:61