121 properties
props = {}
124 make_fixed_header(control_packet_type::connect, 0b0000)
137 protocol_name_and_level_{0x00, 0x04,
'M',
'Q',
'T',
'T', 0x05},
139 client_id_length_buf_(2),
142 props_(force_move(
props))
144 using namespace std::literals;
146 endian_store(boost::numeric_cast<std::uint16_t>(client_id_.size()), client_id_length_buf_.data());
148 if (!utf8string_check(client_id_)) {
151 "v5::connect_packet client_id invalid utf8"
155 if (
clean_start) connect_flags_ |= connect_flags::mask_clean_start;
160 "v5::connect_packet user name invalid utf8"
163 connect_flags_ |= connect_flags::mask_user_name_flag;
165 user_name_length_buf_ = endian_static_vector(boost::numeric_cast<std::uint16_t>(user_name_.size()));
166 remaining_length_ += 2 + user_name_.size();
169 connect_flags_ |= connect_flags::mask_password_flag;
171 password_length_buf_ = endian_static_vector(boost::numeric_cast<std::uint16_t>(password_.size()));
172 remaining_length_ += 2 + password_.size();
175 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(property_length_));
177 property_length_buf_.push_back(e);
180 for (
auto const& prop : props_) {
182 if (!validate_property(property_location::connect,
id)) {
185 "v5::connect_packet property "s + id_to_str(
id) +
" is not allowed"
190 remaining_length_ += property_length_buf_.size() + property_length_;
193 connect_flags_ |= connect_flags::mask_will_flag;
194 if (w->get_retain() == pub::retain::yes) connect_flags_ |= connect_flags::mask_will_retain;
195 connect_flags::set_will_qos(connect_flags_, w->get_qos());
196 if (!utf8string_check(w->topic())) {
199 "v5::connect_packet will topic invalid utf8"
202 will_topic_ = force_move(w->topic());
203 will_topic_length_buf_ = endian_static_vector(boost::numeric_cast<std::uint16_t>(will_topic_.size()));
204 if (w->message().size() > 0xffffL) {
207 "v5::connect_packet will message too long"
210 will_message_ = force_move(w->message());
211 will_message_length_buf_ = endian_static_vector(boost::numeric_cast<std::uint16_t>(will_message_.size()));
212 will_props_ = force_move(w->props());
213 will_property_length_ = boost::numeric_cast<std::uint32_t>(async_mqtt::size(will_props_));
214 auto pb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(will_property_length_));
216 will_property_length_buf_.push_back(e);
219 for (
auto const& prop : will_props_) {
221 if (!validate_property(property_location::will,
id)) {
224 "v5::connect_packet will_property "s + id_to_str(
id) +
" is not allowed"
230 will_property_length_buf_.size() + will_property_length_ +
231 2 + will_topic_.size() +
232 2 + will_message_.size();
235 auto rb = val_to_variable_bytes(boost::numeric_cast<std::uint32_t>(remaining_length_));
237 remaining_length_buf_.push_back(e);
246 "v5::connect_packet fixed_header doesn't exist"
249 fixed_header_ =
static_cast<std::uint8_t
>(buf.front());
250 buf.remove_prefix(1);
251 auto cpt_opt = get_control_packet_type_with_check(fixed_header_);
252 if (!cpt_opt || *cpt_opt != control_packet_type::connect) {
255 "v5::connect_packet fixed_header is invalid"
260 if (
auto vl_opt = insert_advance_variable_length(buf, remaining_length_buf_)) {
261 remaining_length_ = *vl_opt;
264 throw make_error(errc::bad_message,
"v5::connect_packet remaining length is invalid");
266 if (remaining_length_ != buf.size()) {
267 throw make_error(errc::bad_message,
"v5::connect_packet remaining length doesn't match buf.size()");
271 if (!insert_advance(buf, protocol_name_and_level_)) {
274 "v5::connect_packet length of protocol_name or level is invalid"
277 static_vector<char, 7> expected_protocol_name_and_level {
278 0, 4,
'M',
'Q',
'T',
'T', 5
280 if (protocol_name_and_level_ != expected_protocol_name_and_level) {
283 "v5::connect_packet contents of protocol_name or level is invalid"
288 if (buf.size() < 1) {
291 "v5::connect_packet connect_flags doesn't exist"
294 connect_flags_ = buf.front();
295 if (connect_flags_ & 0b00000001) {
298 "v5::connect_packet connect_flags reserved bit0 is 1 (must be 0)"
301 buf.remove_prefix(1);
304 if (!insert_advance(buf, keep_alive_buf_)) {
307 "v5::connect_packet keep_alive is invalid"
312 auto it = buf.begin();
313 if (
auto pl_opt = variable_bytes_to_val(it, buf.end())) {
314 property_length_ = *pl_opt;
315 std::copy(buf.begin(), it, std::back_inserter(property_length_buf_));
316 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
317 if (buf.size() < property_length_) {
320 "v5::connect_packet properties_don't match its length"
323 auto prop_buf = buf.substr(0, property_length_);
324 props_ = make_properties(prop_buf, property_location::connect);
325 buf.remove_prefix(property_length_);
330 "v5::connect_packet property_length is invalid"
335 if (!insert_advance(buf, client_id_length_buf_)) {
338 "v5::connect_packet length of client_id is invalid"
341 auto client_id_length = endian_load<std::uint16_t>(client_id_length_buf_.data());
344 if (buf.size() < client_id_length) {
347 "v5::connect_packet client_id doesn't match its length"
350 client_id_ = buf.
substr(0, client_id_length);
351 if (!utf8string_check(client_id_)) {
354 "v5::connect_packet client_id invalid utf8"
357 buf.remove_prefix(client_id_length);
360 if (connect_flags::has_will_flag(connect_flags_)) {
362 auto will_qos = connect_flags::will_qos(connect_flags_);
363 if (will_qos != qos::at_most_once &&
364 will_qos != qos::at_least_once &&
365 will_qos != qos::exactly_once) {
368 "v5::connect_packet will_qos is invalid"
373 auto it = buf.begin();
374 if (
auto pl_opt = variable_bytes_to_val(it, buf.end())) {
375 will_property_length_ = *pl_opt;
376 std::copy(buf.begin(), it, std::back_inserter(will_property_length_buf_));
377 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
378 if (buf.size() < will_property_length_) {
381 "v5::connect_packet properties_don't match its length"
384 auto prop_buf = buf.substr(0, will_property_length_);
385 will_props_ = make_properties(prop_buf, property_location::will);
386 buf.remove_prefix(will_property_length_);
391 "v5::connect_packet property_length is invalid"
396 if (!insert_advance(buf, will_topic_length_buf_)) {
399 "v5::connect_packet length of will_topic is invalid"
402 auto will_topic_length = endian_load<std::uint16_t>(will_topic_length_buf_.data());
405 if (buf.size() < will_topic_length) {
408 "v5::connect_packet will_topic doesn't match its length"
411 will_topic_ = buf.
substr(0, will_topic_length);
412 if (!utf8string_check(will_topic_)) {
415 "v5::connect_packet will topic invalid utf8"
418 buf.remove_prefix(will_topic_length);
421 if (!insert_advance(buf, will_message_length_buf_)) {
424 "v5::connect_packet length of will_message is invalid"
427 auto will_message_length = endian_load<std::uint16_t>(will_message_length_buf_.data());
430 if (buf.size() < will_message_length) {
433 "v5::connect_packet will_message doesn't match its length"
436 will_message_ = buf.
substr(0, will_message_length);
437 buf.remove_prefix(will_message_length);
440 auto will_retain = connect_flags::will_retain(connect_flags_);
441 auto will_qos = connect_flags::will_qos(connect_flags_);
442 if (will_retain == pub::retain::yes) {
445 "v5::connect_packet combination of will_flag and will_retain is invalid"
448 if (will_qos != qos::at_most_once) {
451 "v5::connect_packet combination of will_flag and will_qos is invalid"
456 if (connect_flags::has_user_name_flag(connect_flags_)) {
458 if (!insert_advance(buf, user_name_length_buf_)) {
461 "v5::connect_packet length of user_name is invalid"
464 auto user_name_length = endian_load<std::uint16_t>(user_name_length_buf_.data());
467 if (buf.size() < user_name_length) {
470 "v5::connect_packet user_name doesn't match its length"
473 user_name_ = buf.
substr(0, user_name_length);
474 if (!utf8string_check(user_name_)) {
477 "v5::connect_packet user name invalid utf8"
480 buf.remove_prefix(user_name_length);
484 if (connect_flags::has_password_flag(connect_flags_)) {
486 if (!insert_advance(buf, password_length_buf_)) {
489 "v5::connect_packet length of password is invalid"
492 auto password_length = endian_load<std::uint16_t>(password_length_buf_.data());
495 if (buf.size() != password_length) {
498 "v5::connect_packet password doesn't match its length"
501 password_ = buf.
substr(0, password_length);
502 buf.remove_prefix(password_length);
506 constexpr control_packet_type type()
const {
507 return control_packet_type::connect;
516 std::vector<as::const_buffer>
ret;
519 ret.emplace_back(as::buffer(&fixed_header_, 1));
520 ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
521 ret.emplace_back(as::buffer(protocol_name_and_level_.data(), protocol_name_and_level_.size()));
522 ret.emplace_back(as::buffer(&connect_flags_, 1));
523 ret.emplace_back(as::buffer(keep_alive_buf_.data(), keep_alive_buf_.size()));
525 ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
526 auto props_cbs = async_mqtt::const_buffer_sequence(props_);
529 ret.emplace_back(as::buffer(client_id_length_buf_.data(), client_id_length_buf_.size()));
530 ret.emplace_back(as::buffer(client_id_));
532 if (connect_flags::has_will_flag(connect_flags_)) {
533 ret.emplace_back(as::buffer(will_property_length_buf_.data(), will_property_length_buf_.size()));
534 auto will_props_cbs = async_mqtt::const_buffer_sequence(will_props_);
536 ret.emplace_back(as::buffer(will_topic_length_buf_.data(), will_topic_length_buf_.size()));
537 ret.emplace_back(as::buffer(will_topic_));
538 ret.emplace_back(as::buffer(will_message_length_buf_.data(), will_message_length_buf_.size()));
539 ret.emplace_back(as::buffer(will_message_));
542 if (connect_flags::has_user_name_flag(connect_flags_)) {
543 ret.emplace_back(as::buffer(user_name_length_buf_.data(), user_name_length_buf_.size()));
544 ret.emplace_back(as::buffer(user_name_));
547 if (connect_flags::has_password_flag(connect_flags_)) {
548 ret.emplace_back(as::buffer(password_length_buf_.data(), password_length_buf_.size()));
549 ret.emplace_back(as::buffer(password_));
562 remaining_length_buf_.size() +
578 async_mqtt::num_of_const_buffer_sequence(props_) +
582 [&] () -> std::size_t {
583 if (connect_flags::has_will_flag(connect_flags_)) {
586 async_mqtt::num_of_const_buffer_sequence(will_props_) +
592 [&] () -> std::size_t {
593 if (connect_flags::has_user_name_flag(connect_flags_)) {
598 [&] () -> std::size_t {
599 if (connect_flags::has_password_flag(connect_flags_)) {
611 return connect_flags::has_clean_start(connect_flags_);
635 if (connect_flags::has_user_name_flag(connect_flags_)) {
648 if (connect_flags::has_password_flag(connect_flags_)) {
661 if (connect_flags::has_will_flag(connect_flags_)) {
663 connect_flags::will_retain(connect_flags_) |
664 connect_flags::will_qos(connect_flags_);
687 std::uint8_t fixed_header_;
690 std::size_t remaining_length_;
701 std::size_t will_property_length_;
703 properties will_props_;
712 std::size_t property_length_;