mqtt_cpp
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
v5_message.hpp
Go to the documentation of this file.
1 // Copyright Takatoshi Kondo 2018
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(MQTT_V5_MESSAGE_HPP)
8 #define MQTT_V5_MESSAGE_HPP
9 
10 #include <string>
11 #include <vector>
12 #include <memory>
13 #include <algorithm>
14 #include <numeric>
15 
16 #include <boost/asio/buffer.hpp>
17 #include <boost/optional.hpp>
18 #include <boost/container/static_vector.hpp>
19 #include <boost/numeric/conversion/cast.hpp>
20 
21 #include <mqtt/namespace.hpp>
22 #include <mqtt/two_byte_util.hpp>
23 #include <mqtt/fixed_header.hpp>
27 #include <mqtt/will.hpp>
28 #include <mqtt/connect_flags.hpp>
29 #include <mqtt/publish.hpp>
30 #include <mqtt/exception.hpp>
32 #include <mqtt/string_check.hpp>
33 #include <mqtt/property.hpp>
35 #include <mqtt/property_parse.hpp>
36 #include <mqtt/reason_code.hpp>
37 #include <mqtt/packet_id_type.hpp>
38 #include <mqtt/move.hpp>
39 #include <mqtt/variant_visit.hpp>
40 
41 #if !defined(MQTT_ALWAYS_SEND_REASON_CODE)
42 #define MQTT_ALWAYS_SEND_REASON_CODE false
43 #endif // !defined(MQTT_ALWAYS_SEND_REASON_CODE)
44 
45 namespace MQTT_NS {
46 
47 namespace as = boost::asio;
48 
49 namespace v5 {
50 
51 namespace detail {
52 
54 public:
58  header_only_message(control_packet_type type, std::uint8_t flags)
59  : message_ { static_cast<char>(make_fixed_header(type, flags)), 0 }
60  {}
61 
67  std::vector<as::const_buffer> const_buffer_sequence() const {
68  return { as::buffer(message_.data(), message_.size()) };
69  }
70 
75  std::size_t size() const {
76  return message_.size();
77  }
78 
83  static constexpr std::size_t num_of_const_buffer_sequence() {
84  return 1;
85  }
86 
93  std::string continuous_buffer() const {
94  return std::string(message_.data(), message_.size());
95  }
96 private:
97  boost::container::static_vector<char, 2> message_;
98 };
99 
100 } // namespace detail
101 
103 public:
105  std::uint16_t keep_alive_sec,
106  buffer client_id,
107  bool clean_start,
108  optional<will> w,
109  optional<buffer> user_name,
110  optional<buffer> password,
111  properties props
112  )
113  : fixed_header_(make_fixed_header(control_packet_type::connect, 0b0000)),
114  connect_flags_(0),
115  // protocol name length, protocol name, protocol level, connect flag, client id length, client id, keep alive
116  remaining_length_(
117  2 + // protocol name length
118  4 + // protocol name
119  1 + // protocol level
120  1 + // connect flag
121  2 + // keep alive
122  2 + // client id length
123  client_id.size() // client id
124  ),
125  protocol_name_and_level_ { 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x05 },
126  client_id_(force_move(client_id)),
127  client_id_length_buf_{ num_to_2bytes(boost::numeric_cast<std::uint16_t>(client_id_.size())) },
128  will_property_length_(
129  w ?
130  std::accumulate(
131  w.value().props().begin(),
132  w.value().props().end(),
133  std::size_t(0U),
134  [](std::size_t total, property_variant const& pv) {
135  return total + v5::size(pv);
136  }
137  )
138  : 0U
139  ),
140  will_props_(
141  w ?
142  force_move(w.value().props())
143  : properties()
144  ),
145  keep_alive_buf_ ({ num_to_2bytes(keep_alive_sec ) }),
146  property_length_(
147  std::accumulate(
148  props.begin(),
149  props.end(),
150  std::size_t(0U),
151  [](std::size_t total, property_variant const& pv) {
152  return total + v5::size(pv);
153  }
154  )
155  ),
156  props_(force_move(props)),
157  num_of_const_buffer_sequence_(
158  1 + // fixed header
159  1 + // remaining length
160  1 + // protocol name and level
161  1 + // connect flags
162  1 + // keep alive
163  1 + // property length
164  std::accumulate(
165  props_.begin(),
166  props_.end(),
167  std::size_t(0U),
168  [](std::size_t total, property_variant const& pv) {
169  return total + v5::num_of_const_buffer_sequence(pv);
170  }
171  ) +
172  2 // client id length, client id
173  )
174  {
175  auto pb = variable_bytes(property_length_);
176  for (auto e : pb) {
177  property_length_buf_.push_back(e);
178  }
179 
180  remaining_length_ += property_length_buf_.size() + property_length_;
181 
182  utf8string_check(client_id_);
183  if (clean_start) connect_flags_ |= connect_flags::clean_start;
184  if (user_name) {
185  utf8string_check(user_name.value());
186  connect_flags_ |= connect_flags::user_name_flag;
187  user_name_ = force_move(user_name.value());
188  add_uint16_t_to_buf(user_name_length_buf_, boost::numeric_cast<std::uint16_t>(user_name_.size()));
189 
190  remaining_length_ += 2 + user_name_.size();
191  num_of_const_buffer_sequence_ += 2; // user name length, user name
192  }
193  if (password) {
194  connect_flags_ |= connect_flags::password_flag;
195  password_ = force_move(password.value());
196  add_uint16_t_to_buf(password_length_buf_, boost::numeric_cast<std::uint16_t>(password_.size()));
197 
198  remaining_length_ += 2 + password_.size();
199  num_of_const_buffer_sequence_ += 2; // password length, password
200  }
201  if (w) {
202  connect_flags_ |= connect_flags::will_flag;
203  if (w.value().get_retain() == retain::yes) connect_flags_ |= connect_flags::will_retain;
204  connect_flags::set_will_qos(connect_flags_, w.value().get_qos());
205 
206  auto wpb = variable_bytes(will_property_length_);
207  for (auto e : wpb) {
208  will_property_length_buf_.push_back(e);
209  }
210 
211  utf8string_check(w.value().topic());
212  will_topic_name_ = force_move(w.value().topic());
214  will_topic_name_length_buf_,
215  boost::numeric_cast<std::uint16_t>(will_topic_name_.size())
216  );
217  if (w.value().message().size() > 0xffffL) throw will_message_length_error();
218  will_message_ = force_move(w.value().message());
220  will_message_length_buf_,
221  boost::numeric_cast<std::uint16_t>(will_message_.size()));
222 
223  remaining_length_ +=
224  will_property_length_buf_.size() +
225  will_property_length_ +
226  2 + will_topic_name_.size() + 2 + will_message_.size();
227  num_of_const_buffer_sequence_ +=
228  std::accumulate(
229  will_props_.begin(),
230  will_props_.end(),
231  std::size_t(0U),
232  [](std::size_t total, property_variant const& pv) {
233  return total + v5::num_of_const_buffer_sequence(pv);
234  }
235  ) +
236  2 + // will topic name length, will topic name
237  2; // will message length, will message
238 
239  }
240 
241  auto rb = remaining_bytes(remaining_length_);
242  for (auto e : rb) {
243  remaining_length_buf_.push_back(e);
244  }
245  }
246 
252  std::vector<as::const_buffer> const_buffer_sequence() const {
253  std::vector<as::const_buffer> ret;
254  ret.reserve(num_of_const_buffer_sequence());
255 
256  ret.emplace_back(as::buffer(&fixed_header_, 1));
257  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
258  ret.emplace_back(as::buffer(protocol_name_and_level_.data(), protocol_name_and_level_.size()));
259  ret.emplace_back(as::buffer(&connect_flags_, 1));
260  ret.emplace_back(as::buffer(keep_alive_buf_.data(), keep_alive_buf_.size()));
261 
262  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
263  for (auto const& p : props_) {
265  }
266 
267  ret.emplace_back(as::buffer(client_id_length_buf_.data(), client_id_length_buf_.size()));
268  ret.emplace_back(as::buffer(client_id_));
269 
270  if (connect_flags::has_will_flag(connect_flags_)) {
271  ret.emplace_back(as::buffer(will_property_length_buf_.data(), will_property_length_buf_.size()));
272  for (auto const& p : will_props_) {
274  }
275  ret.emplace_back(as::buffer(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size()));
276  ret.emplace_back(as::buffer(will_topic_name_));
277  ret.emplace_back(as::buffer(will_message_length_buf_.data(), will_message_length_buf_.size()));
278  ret.emplace_back(as::buffer(will_message_));
279  }
280 
281  if (connect_flags::has_user_name_flag(connect_flags_)) {
282  ret.emplace_back(as::buffer(user_name_length_buf_.data(), user_name_length_buf_.size()));
283  ret.emplace_back(as::buffer(user_name_));
284  }
285 
286  if (connect_flags::has_password_flag(connect_flags_)) {
287  ret.emplace_back(as::buffer(password_length_buf_.data(), password_length_buf_.size()));
288  ret.emplace_back(as::buffer(password_));
289  }
290 
291  return ret;
292  }
293 
298  std::size_t size() const {
299  return
300  1 + // fixed header
301  remaining_length_buf_.size() +
302  remaining_length_;
303  }
304 
309  constexpr std::size_t num_of_const_buffer_sequence() const {
310  return num_of_const_buffer_sequence_;
311  }
312 
319  std::string continuous_buffer() const {
320  std::string ret;
321 
322  ret.reserve(size());
323 
324  ret.push_back(static_cast<char>(fixed_header_));
325  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
326  ret.append(protocol_name_and_level_.data(), protocol_name_and_level_.size());
327  ret.push_back(connect_flags_);
328  ret.append(keep_alive_buf_.data(), keep_alive_buf_.size());
329 
330  ret.append(property_length_buf_.data(), property_length_buf_.size());
331 
332  auto it = ret.end();
333  ret.resize(ret.size() + property_length_);
334  auto end = ret.end();
335  for (auto const& p : props_) {
336  v5::fill(p, it, end);
337  it += static_cast<std::string::difference_type>(v5::size(p));
338  }
339 
340  ret.append(client_id_length_buf_.data(), client_id_length_buf_.size());
341  ret.append(client_id_.data(), client_id_.size());
342 
343  if (connect_flags::has_will_flag(connect_flags_)) {
344  ret.append(will_property_length_buf_.data(), will_property_length_buf_.size());
345  auto it = ret.end();
346  ret.resize(ret.size() + will_property_length_);
347  auto end = ret.end();
348  for (auto const& p : will_props_) {
349  v5::fill(p, it, end);
350  it += static_cast<std::string::difference_type>(v5::size(p));
351  }
352  ret.append(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size());
353  ret.append(will_topic_name_.data(), will_topic_name_.size());
354  ret.append(will_message_length_buf_.data(), will_message_length_buf_.size());
355  ret.append(will_message_.data(), will_message_.size());
356  }
357 
358  if (connect_flags::has_user_name_flag(connect_flags_)) {
359  ret.append(user_name_length_buf_.data(), user_name_length_buf_.size());
360  ret.append(user_name_.data(), user_name_.size());
361  }
362 
363  if (connect_flags::has_password_flag(connect_flags_)) {
364  ret.append(password_length_buf_.data(), password_length_buf_.size());
365  ret.append(password_.data(), password_.size());
366  }
367 
368  return ret;
369  }
370 
371 private:
372  std::uint8_t fixed_header_;
373  char connect_flags_;
374 
375  std::size_t remaining_length_;
376  boost::container::static_vector<char, 4> remaining_length_buf_;
377 
378  boost::container::static_vector<char, 7> protocol_name_and_level_;
379  buffer client_id_;
380  boost::container::static_vector<char, 2> client_id_length_buf_;
381 
382  std::size_t will_property_length_;
383  boost::container::static_vector<char, 4> will_property_length_buf_;
384  properties will_props_;
385 
386  buffer will_topic_name_;
387  boost::container::static_vector<char, 2> will_topic_name_length_buf_;
388  buffer will_message_;
389  boost::container::static_vector<char, 2> will_message_length_buf_;
390 
391  buffer user_name_;
392  boost::container::static_vector<char, 2> user_name_length_buf_;
393  buffer password_;
394  boost::container::static_vector<char, 2> password_length_buf_;
395 
396  boost::container::static_vector<char, 2> keep_alive_buf_;
397 
398  std::size_t property_length_;
399  boost::container::static_vector<char, 4> property_length_buf_;
400  properties props_;
401 
402  std::size_t num_of_const_buffer_sequence_;
403 };
404 
406 public:
408  bool session_present,
409  connect_reason_code reason_code,
410  properties props
411  )
412  : fixed_header_(make_fixed_header(control_packet_type::connack, 0b0000)),
413  remaining_length_(
414  1 + // connect acknowledge flags
415  1 // reason code
416  ),
417  connect_acknowledge_flags_(session_present ? 1 : 0),
418  reason_code_(reason_code),
419  property_length_(
420  std::accumulate(
421  props.begin(),
422  props.end(),
423  std::size_t(0U),
424  [](std::size_t total, property_variant const& pv) {
425  return total + v5::size(pv);
426  }
427  )
428  ),
429  props_(force_move(props)),
430  num_of_const_buffer_sequence_(
431  1 + // fixed header
432  1 + // remaining length
433  1 + // connect acknowledge flags
434  1 + // reason code
435  1 + // property length
436  std::accumulate(
437  props_.begin(),
438  props_.end(),
439  std::size_t(0U),
440  [](std::size_t total, property_variant const& pv) {
441  return total + v5::num_of_const_buffer_sequence(pv);
442  }
443  )
444  )
445  {
446  auto pb = variable_bytes(property_length_);
447  for (auto e : pb) {
448  property_length_buf_.push_back(e);
449  }
450 
451  remaining_length_ += property_length_buf_.size() + property_length_;
452  auto rb = remaining_bytes(remaining_length_);
453  for (auto e : rb) {
454  remaining_length_buf_.push_back(e);
455  }
456  }
457 
463  std::vector<as::const_buffer> const_buffer_sequence() const {
464  std::vector<as::const_buffer> ret;
465  ret.reserve(num_of_const_buffer_sequence());
466 
467  ret.emplace_back(as::buffer(&fixed_header_, 1));
468  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
469  ret.emplace_back(as::buffer(&connect_acknowledge_flags_, 1));
470  ret.emplace_back(as::buffer(&reason_code_, 1));
471 
472  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
473  for (auto const& p : props_) {
475  }
476 
477  return ret;
478  }
479 
484  std::size_t size() const {
485  return
486  1 + // fixed header
487  remaining_length_buf_.size() +
488  remaining_length_;
489  }
490 
495  constexpr std::size_t num_of_const_buffer_sequence() const {
496  return num_of_const_buffer_sequence_;
497  }
498 
505  std::string continuous_buffer() const {
506  std::string ret;
507 
508  ret.reserve(size());
509 
510  ret.push_back(static_cast<char>(fixed_header_));
511  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
512  ret.push_back(static_cast<char>(connect_acknowledge_flags_));
513  ret.push_back(static_cast<char>(reason_code_));
514 
515  auto it = ret.end();
516  ret.resize(ret.size() + property_length_);
517  auto end = ret.end();
518  for (auto const& p : props_) {
519  v5::fill(p, it, end);
520  it += static_cast<std::string::difference_type>(v5::size(p));
521  }
522 
523  return ret;
524  }
525 
526 private:
527  std::uint8_t fixed_header_;
528 
529  std::size_t remaining_length_;
530  boost::container::static_vector<char, 4> remaining_length_buf_;
531 
532  std::uint8_t connect_acknowledge_flags_;
533 
534  connect_reason_code reason_code_;
535 
536  std::size_t property_length_;
537  boost::container::static_vector<char, 4> property_length_buf_;
538  properties props_;
539 
540  std::size_t num_of_const_buffer_sequence_;
541 };
542 
543 template <std::size_t PacketIdBytes>
545 public:
546  template <
547  typename ConstBufferSequence,
548  typename std::enable_if<
549  as::is_const_buffer_sequence<ConstBufferSequence>::value,
550  std::nullptr_t
551  >::type = nullptr
552  >
555  as::const_buffer topic_name,
556  ConstBufferSequence payloads,
557  publish_options pubopts,
559  )
560  : fixed_header_(make_fixed_header(control_packet_type::publish, 0b0000) | pubopts.operator std::uint8_t()),
561  topic_name_(topic_name),
562  topic_name_length_buf_ { num_to_2bytes(boost::numeric_cast<std::uint16_t>(topic_name_.size())) },
563  property_length_(
564  std::accumulate(
565  props.begin(),
566  props.end(),
567  std::size_t(0U),
568  [](std::size_t total, property_variant const& pv) {
569  return total + v5::size(pv);
570  }
571  )
572  ),
573  props_(force_move(props)),
574  remaining_length_(
575  2 // topic name length
576  + topic_name_.size() // topic name
577  + ( (pubopts.get_qos() == qos::at_least_once || pubopts.get_qos() == qos::exactly_once)
578  ? PacketIdBytes // packet_id
579  : 0)
580  ),
581  num_of_const_buffer_sequence_(
582  1 + // fixed header
583  1 + // remaining length
584  1 + // topic name length
585  1 + // topic name
586  ((pubopts.get_qos() == qos::at_most_once) ? 0U : 1U) + // packet id
587  1 + // property length
588  std::accumulate(
589  props_.begin(),
590  props_.end(),
591  std::size_t(0U),
592  [](std::size_t total, property_variant const& pv) {
593  return total + v5::num_of_const_buffer_sequence(pv);
594  }
595  )
596  )
597  {
598  auto b = as::buffer_sequence_begin(payloads);
599  auto e = as::buffer_sequence_end(payloads);
600  auto num_of_payloads = static_cast<std::size_t>(std::distance(b, e));
601  payloads_.reserve(num_of_payloads);
602  for (; b != e; ++b) {
603  auto const& payload = *b;
604  remaining_length_ += payload.size();
605  payloads_.push_back(payload);
606  }
607  num_of_const_buffer_sequence_ += num_of_payloads;
608 
609  utf8string_check(topic_name_);
610 
611  auto pb = variable_bytes(property_length_);
612  for (auto e : pb) {
613  property_length_buf_.push_back(e);
614  }
615 
616  remaining_length_ += property_length_buf_.size() + property_length_;
617 
618  auto rb = remaining_bytes(remaining_length_);
619  for (auto e : rb) {
620  remaining_length_buf_.push_back(e);
621  }
622  if (pubopts.get_qos() == qos::at_least_once ||
623  pubopts.get_qos() == qos::exactly_once) {
624  packet_id_.reserve(PacketIdBytes);
625  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
626  }
627  }
628 
630  if (buf.empty()) throw remaining_length_error();
631  fixed_header_ = static_cast<std::uint8_t>(buf.front());
632  qos qos_value = get_qos();
633  buf.remove_prefix(1);
634 
635  if (buf.empty()) throw remaining_length_error();
636  auto len_consumed = remaining_length(buf.begin(), buf.end());
637  remaining_length_ = std::get<0>(len_consumed);
638  auto consumed = std::get<1>(len_consumed);
639 
640  std::copy(
641  buf.begin(),
642  std::next(buf.begin(), static_cast<buffer::difference_type>(consumed)),
643  std::back_inserter(remaining_length_buf_));
644  buf.remove_prefix(consumed);
645 
646  if (buf.size() < 2) throw remaining_length_error();
647  std::copy(buf.begin(), std::next(buf.begin(), 2), std::back_inserter(topic_name_length_buf_));
648  auto topic_name_length = make_uint16_t(buf.begin(), std::next(buf.begin(), 2));
649  buf.remove_prefix(2);
650 
651  if (buf.size() < topic_name_length) throw remaining_length_error();
652 
653  topic_name_ = as::buffer(buf.substr(0, topic_name_length));
654  utf8string_check(topic_name_);
655  buf.remove_prefix(topic_name_length);
656 
657  switch (qos_value) {
658  case qos::at_most_once:
659  break;
660  case qos::at_least_once:
661  case qos::exactly_once:
662  if (buf.size() < PacketIdBytes) throw remaining_length_error();
663  std::copy(buf.begin(), std::next(buf.begin(), PacketIdBytes), std::back_inserter(packet_id_));
664  buf.remove_prefix(PacketIdBytes);
665  break;
666  default:
667  throw protocol_error();
668  break;
669  };
670 
671  auto len_consume = variable_length(
672  buf.begin(),
673  buf.end()
674  );
675  property_length_ = std::get<0>(len_consume);
676  auto consume = std::get<1>(len_consume);
677  if (consume == 0) throw property_length_error();
678  std::copy(
679  buf.begin(),
680  std::next(buf.begin(), static_cast<buffer::difference_type>(consume)),
681  std::back_inserter(property_length_buf_)
682  );
683  buf.remove_prefix(consume);
684  if (buf.size() < property_length_) throw property_length_error();
685 
686  props_ = property::parse(buf.substr(0, property_length_));
687  buf.remove_prefix(property_length_);
688  if (!buf.empty()) {
689  payloads_.emplace_back(as::buffer(buf));
690  }
691  num_of_const_buffer_sequence_ =
692  1 + // fixed header
693  1 + // remaining length
694  1 + // topic name length
695  1 + // topic name
696  ((qos_value == qos::at_most_once) ? 0U : 1U) + // packet id
697  1 + // property length
698  std::accumulate(
699  props_.begin(),
700  props_.end(),
701  std::size_t(0U),
702  [](std::size_t total, property_variant const& pv) {
703  return total + v5::num_of_const_buffer_sequence(pv);
704  }
705  ) +
706  payloads_.size(); // payload
707  }
708 
714  std::vector<as::const_buffer> const_buffer_sequence() const {
715  std::vector<as::const_buffer> ret;
716  ret.reserve(num_of_const_buffer_sequence());
717 
718  ret.emplace_back(as::buffer(&fixed_header_, 1));
719  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
720  ret.emplace_back(topic_name_length_buf_.data(), topic_name_length_buf_.size());
721  ret.emplace_back(as::buffer(topic_name_));
722 
723  if (!packet_id_.empty()) {
724  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
725  }
726 
727  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
728  for (auto const& p : props_) {
730  }
731 
732  std::copy(payloads_.begin(), payloads_.end(), std::back_inserter(ret));
733 
734  return ret;
735  }
736 
741  std::size_t size() const {
742  return
743  1 + // fixed header
744  remaining_length_buf_.size() +
745  remaining_length_;
746  }
747 
752  constexpr std::size_t num_of_const_buffer_sequence() const {
753  return num_of_const_buffer_sequence_;
754  }
755 
762  std::string continuous_buffer() const {
763  std::string ret;
764 
765  ret.reserve(size());
766 
767  ret.push_back(static_cast<char>(fixed_header_));
768  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
769 
770  ret.append(topic_name_length_buf_.data(), topic_name_length_buf_.size());
771  ret.append(get_pointer(topic_name_), get_size(topic_name_));
772 
773  ret.append(packet_id_.data(), packet_id_.size());
774 
775  ret.append(property_length_buf_.data(), property_length_buf_.size());
776 
777  auto it = ret.end();
778  ret.resize(ret.size() + property_length_);
779  auto end = ret.end();
780  for (auto const& p : props_) {
781  v5::fill(p, it, end);
782  it += static_cast<std::string::difference_type>(v5::size(p));
783  }
784 
785  for (auto const& payload : payloads_) {
786  ret.append(get_pointer(payload), get_size(payload));
787  }
788 
789  return ret;
790  }
791 
797  return make_packet_id<PacketIdBytes>::apply(packet_id_.begin(), packet_id_.end());
798  }
799 
804  constexpr publish_options get_options() const {
805  return publish_options(fixed_header_);
806  }
807 
812  constexpr qos get_qos() const {
813  return publish::get_qos(fixed_header_);
814  }
815 
820  constexpr bool is_retain() const {
821  return publish::is_retain(fixed_header_);
822  }
823 
828  constexpr bool is_dup() const {
829  return publish::is_dup(fixed_header_);
830  }
831 
836  string_view topic() const {
837  return string_view(get_pointer(topic_name_), get_size(topic_name_));
838  }
839 
844  std::vector<string_view> payload() const {
845  std::vector<string_view> ret;
846  ret.reserve(payloads_.size());
847  for (auto const& payload : payloads_) {
848  ret.emplace_back(get_pointer(payload), get_size(payload));
849  }
850  return ret;
851  }
852 
858  auto size = std::accumulate(
859  payloads_.begin(),
860  payloads_.end(),
861  std::size_t(0),
862  [](std::size_t s, as::const_buffer const& payload) {
863  return s += payload.size();
864  }
865  );
866 
867  if (size == 0) return buffer();
868 
869  auto spa = make_shared_ptr_array(size);
870  auto ptr = spa.get();
871  auto it = ptr;
872  for (auto const& payload : payloads_) {
873  auto b = get_pointer(payload);
874  auto s = get_size(payload);
875  auto e = b + s;
876  std::copy(b, e, it);
877  it += s;
878  }
879  return buffer(string_view(ptr, size), force_move(spa));
880  }
881 
886  properties const& props() const {
887  return props_;
888  }
889 
895  auto add_size = v5::size(p);
896  props_.push_back(force_move(p));
897  property_length_ += add_size;
898  property_length_buf_.clear();
899  auto pb = variable_bytes(property_length_);
900  for (auto e : pb) {
901  property_length_buf_.push_back(e);
902  }
903 
904  remaining_length_buf_.clear();
905  remaining_length_ += add_size;
906  auto rb = remaining_bytes(remaining_length_);
907  for (auto e : rb) {
908  remaining_length_buf_.push_back(e);
909  }
910  }
911 
917  template <typename Property>
918  std::enable_if_t<
919  std::is_base_of<property::detail::n_bytes_property<1>, Property>::value ||
920  std::is_base_of<property::detail::n_bytes_property<2>, Property>::value ||
921  std::is_base_of<property::detail::n_bytes_property<4>, Property>::value
922  >
924  for (auto& p : props_) {
927  [&update_prop](Property& t) { t = std::forward<Property>(update_prop); },
928  [](auto&) { }
929  ),
930  p
931  );
932  }
933  }
934 
940  std::size_t removed_size = 0;
941  auto it = props_.begin();
942  auto end = props_.begin();
943  while (it != end) {
944  if (v5::id(*it) == id) {
945  removed_size += v5::size(*it);
946  it = props_.erase(it);
947  }
948  else {
949  ++it;
950  }
951  }
952 
953  property_length_ -= removed_size;
954  property_length_buf_.clear();
955  auto pb = variable_bytes(property_length_);
956  for (auto e : pb) {
957  property_length_buf_.push_back(e);
958  }
959 
960  remaining_length_buf_.clear();
961  remaining_length_ -= removed_size;
962  auto rb = remaining_bytes(remaining_length_);
963  for (auto e : rb) {
964  remaining_length_buf_.push_back(e);
965  }
966  }
967 
972  constexpr void set_dup(bool dup) {
973  publish::set_dup(fixed_header_, dup);
974  }
975 
980  void set_topic_name(as::const_buffer topic_name) {
981  auto prev_topic_name_size = get_size(topic_name_);
982  topic_name_ = force_move(topic_name);
983  topic_name_length_buf_ = boost::container::static_vector<char, 2>{
984  num_to_2bytes(boost::numeric_cast<std::uint16_t>(get_size(topic_name)))
985  };
986 
987  remaining_length_buf_.clear();
988  remaining_length_ = remaining_length_ - prev_topic_name_size + get_size(topic_name);
989  auto rb = remaining_bytes(remaining_length_);
990  for (auto e : rb) {
991  remaining_length_buf_.push_back(e);
992  }
993  }
994 
995 private:
996  std::uint8_t fixed_header_;
997  as::const_buffer topic_name_;
998  boost::container::static_vector<char, 2> topic_name_length_buf_;
999  boost::container::static_vector<char, PacketIdBytes> packet_id_;
1000  std::size_t property_length_;
1001  boost::container::static_vector<char, 4> property_length_buf_;
1002  properties props_;
1003  std::vector<as::const_buffer> payloads_;
1004  std::size_t remaining_length_;
1005  boost::container::static_vector<char, 4> remaining_length_buf_;
1006  std::size_t num_of_const_buffer_sequence_;
1007 };
1008 
1011 
1012 template <std::size_t PacketIdBytes>
1015  typename packet_id_type<PacketIdBytes>::type packet_id,
1016  v5::puback_reason_code reason_code,
1017  properties props)
1019  reason_code_(reason_code),
1021  std::accumulate(
1022  props.begin(),
1023  props.end(),
1024  std::size_t(0U),
1025  [](std::size_t total, property_variant const& pv) {
1026  return total + v5::size(pv);
1027  }
1028  )
1029  ),
1030  props_(force_move(props)),
1032  1 + // fixed header
1033  1 + // remaining length
1034  1 + // packet id
1035  // TODO: This is wrong. The reason code MUST be provided
1036  // if there are properties. Not the other way around.
1037  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
1038  // 3.4.2.1 PUBACK Reason Code
1039  // The Reason Code and Property Length can be omitted if
1040  // the Reason Code is 0x00 (Success) and there are no Properties.
1041  // In this case the PUBACK has a Remaining Length of 2.
1042  [&] () -> std::size_t {
1044  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
1045  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1046  if (props_.empty()) {
1047  return 1; // reason code
1048  }
1049  else {
1050  return
1051  1 + // reason code
1052  1 + // property length
1053  std::accumulate( // properties
1054  props_.begin(),
1055  props_.end(),
1056  std::size_t(0U),
1057  [](std::size_t total, property_variant const& pv) {
1058  return total + v5::num_of_const_buffer_sequence(pv);
1059  }
1060  );
1061  }
1062  }
1063  else {
1064  return 0;
1065  }
1066  } ()
1067  )
1068  {
1069  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
1070  auto pb = variable_bytes(property_length_);
1071  for (auto e : pb) {
1072  property_length_buf_.push_back(e);
1073  }
1074 
1075  remaining_length_ =
1076  PacketIdBytes + // packet id
1077  // TODO: This is wrong. The reason code MUST be provided
1078  // if there are properties. Not the other way around.
1079  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
1080  // 3.4.2.1 PUBACK Reason Code
1081  // The Reason Code and Property Length can be omitted if
1082  // the Reason Code is 0x00 (Success) and there are no Properties.
1083  // In this case the PUBACK has a Remaining Length of 2.
1084  [&] () -> std::size_t {
1086  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
1087  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1088  if (props_.empty()) {
1089  return 1; // reason code
1090  }
1091  else {
1092  return
1093  1 + // reason code
1094  property_length_buf_.size() +
1095  property_length_;
1096  }
1097  }
1098  else {
1099  return 0;
1100  }
1101  } ();
1102 
1103  auto rb = remaining_bytes(remaining_length_);
1104  for (auto e : rb) {
1105  remaining_length_buf_.push_back(e);
1106  }
1107  }
1108 
1114  std::vector<as::const_buffer> const_buffer_sequence() const {
1115  std::vector<as::const_buffer> ret;
1116  ret.reserve(num_of_const_buffer_sequence());
1117 
1118  ret.emplace_back(as::buffer(&fixed_header_, 1));
1119  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
1120  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
1121 
1122  // TODO: This is wrong. The reason code MUST be provided
1123  // if there are properties. Not the other way around.
1124  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
1125  // 3.4.2.1 PUBACK Reason Code
1126  // The Reason Code and Property Length can be omitted if
1127  // the Reason Code is 0x00 (Success) and there are no Properties.
1128  // In this case the PUBACK has a Remaining Length of 2.
1130  ret.emplace_back(as::buffer(&reason_code_, 1));
1131  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
1132  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1133  if (!props_.empty()) {
1134  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
1135  for (auto const& p : props_) {
1137  }
1138  }
1139  }
1140  return ret;
1141  }
1142 
1147  std::size_t size() const {
1148  return
1149  1 + // fixed header
1150  remaining_length_buf_.size() +
1151  remaining_length_;
1152  }
1153 
1158  constexpr std::size_t num_of_const_buffer_sequence() const {
1159  return num_of_const_buffer_sequence_;
1160  }
1161 
1168  std::string continuous_buffer() const {
1169  std::string ret;
1170  auto sz = size();
1171  ret.reserve(sz);
1172 
1173  ret.push_back(static_cast<char>(fixed_header_));
1174  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
1175 
1176  // TODO: This is wrong. The reason code MUST be provided
1177  // if there are properties. Not the other way around.
1178  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
1179  // 3.4.2.1 PUBACK Reason Code
1180  // The Reason Code and Property Length can be omitted if
1181  // the Reason Code is 0x00 (Success) and there are no Properties.
1182  // In this case the PUBACK has a Remaining Length of 2.
1184  ret.push_back(static_cast<char>(reason_code_));
1185 
1186  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
1187  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1188  if (!props_.empty()) {
1189  ret.append(property_length_buf_.data(), property_length_buf_.size());
1190 
1191  auto it = ret.end();
1192  ret.resize(sz);
1193  auto end = ret.end();
1194  for (auto const& p : props_) {
1195  v5::fill(p, it, end);
1196  it += static_cast<std::string::difference_type>(v5::size(p));
1197  }
1198  }
1199  }
1200  return ret;
1201  }
1202 
1203  std::uint8_t fixed_header_;
1204  std::size_t remaining_length_;
1205  boost::container::static_vector<char, 4> remaining_length_buf_;
1206  boost::container::static_vector<char, PacketIdBytes> packet_id_;
1208  std::size_t property_length_;
1209  boost::container::static_vector<char, 4> property_length_buf_;
1212 };
1213 
1215 
1216 template <std::size_t PacketIdBytes>
1219  typename packet_id_type<PacketIdBytes>::type packet_id,
1220  pubrec_reason_code reason_code,
1221  properties props)
1222  : fixed_header_(make_fixed_header(control_packet_type::pubrec, 0b0000)),
1223  reason_code_(reason_code),
1224  property_length_(
1225  std::accumulate(
1226  props.begin(),
1227  props.end(),
1228  std::size_t(0U),
1229  [](std::size_t total, property_variant const& pv) {
1230  return total + v5::size(pv);
1231  }
1232  )
1233  ),
1234  props_(force_move(props)),
1235  num_of_const_buffer_sequence_(
1236  1 + // fixed header
1237  1 + // remaining length
1238  1 + // packet id
1239  // TODO: This is wrong. The reason code MUST be provided
1240  // if there are properties. Not the other way around.
1241  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
1242  // 3.5.2.1 PUBREC Reason Code
1243  // The Reason Code and Property Length can be omitted if
1244  // the Reason Code is 0x00 (Success) and there are no Properties.
1245  // In this case the PUBREC has a Remaining Length of 2.
1246  [&] () -> std::size_t {
1248  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
1249  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1250  if (props_.empty()) {
1251  return 1; // reason code
1252  }
1253  else {
1254  return
1255  1 + // reason code
1256  1 + // property length
1257  std::accumulate( // properties
1258  props_.begin(),
1259  props_.end(),
1260  std::size_t(0U),
1261  [](std::size_t total, property_variant const& pv) {
1262  return total + v5::num_of_const_buffer_sequence(pv);
1263  }
1264  );
1265  }
1266  }
1267  else {
1268  return 0;
1269  }
1270  } ()
1271  )
1272  {
1273  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
1274  auto pb = variable_bytes(property_length_);
1275  for (auto e : pb) {
1276  property_length_buf_.push_back(e);
1277  }
1278 
1279  remaining_length_ =
1280  PacketIdBytes + // packet id
1281  // TODO: This is wrong. The reason code MUST be provided
1282  // if there are properties. Not the other way around.
1283  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
1284  // 3.5.2.1 PUBREC Reason Code
1285  // The Reason Code and Property Length can be omitted if
1286  // the Reason Code is 0x00 (Success) and there are no Properties.
1287  // In this case the PUBREC has a Remaining Length of 2.
1288  [&] () -> std::size_t {
1290  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
1291  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1292  if (props_.empty()) {
1293  return 1; // reason code
1294  }
1295  else {
1296  return
1297  1 + // reason code
1298  property_length_buf_.size() +
1299  property_length_;
1300  }
1301  }
1302  else {
1303  return 0;
1304  }
1305  } ();
1306 
1307  auto rb = remaining_bytes(remaining_length_);
1308  for (auto e : rb) {
1309  remaining_length_buf_.push_back(e);
1310  }
1311  }
1312 
1318  std::vector<as::const_buffer> const_buffer_sequence() const {
1319  std::vector<as::const_buffer> ret;
1320  ret.reserve(num_of_const_buffer_sequence());
1321 
1322  ret.emplace_back(as::buffer(&fixed_header_, 1));
1323  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
1324  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
1325 
1326  // TODO: This is wrong. The reason code MUST be provided
1327  // if there are properties. Not the other way around.
1328  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
1329  // 3.5.2.1 PUBREC Reason Code
1330  // The Reason Code and Property Length can be omitted if
1331  // the Reason Code is 0x00 (Success) and there are no Properties.
1332  // In this case the PUBREC has a Remaining Length of 2.
1334  ret.emplace_back(as::buffer(&reason_code_, 1));
1335  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
1336  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1337  if (!props_.empty()) {
1338  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
1339  for (auto const& p : props_) {
1341  }
1342  }
1343  }
1344  return ret;
1345  }
1346 
1351  std::size_t size() const {
1352  return
1353  1 + // fixed header
1354  remaining_length_buf_.size() +
1355  remaining_length_;
1356  }
1357 
1362  constexpr std::size_t num_of_const_buffer_sequence() const {
1363  return num_of_const_buffer_sequence_;
1364  }
1365 
1372  std::string continuous_buffer() const {
1373  std::string ret;
1374  auto sz = size();
1375  ret.reserve(sz);
1376 
1377  ret.push_back(static_cast<char>(fixed_header_));
1378  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
1379 
1380  // TODO: This is wrong. The reason code MUST be provided
1381  // if there are properties. Not the other way around.
1382  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
1383  // 3.5.2.1 PUBREC Reason Code
1384  // The Reason Code and Property Length can be omitted if
1385  // the Reason Code is 0x00 (Success) and there are no Properties.
1386  // In this case the PUBREC has a Remaining Length of 2.
1388  ret.push_back(static_cast<char>(reason_code_));
1389 
1390  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
1391  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1392  if (!props_.empty()) {
1393  ret.append(property_length_buf_.data(), property_length_buf_.size());
1394 
1395  auto it = ret.end();
1396  ret.resize(sz);
1397  auto end = ret.end();
1398  for (auto const& p : props_) {
1399  v5::fill(p, it, end);
1400  it += static_cast<std::string::difference_type>(v5::size(p));
1401  }
1402  }
1403  }
1404  return ret;
1405  }
1406 
1407 
1408  std::uint8_t fixed_header_;
1409  std::size_t remaining_length_;
1410  boost::container::static_vector<char, 4> remaining_length_buf_;
1411  boost::container::static_vector<char, PacketIdBytes> packet_id_;
1413  std::size_t property_length_;
1414  boost::container::static_vector<char, 4> property_length_buf_;
1417 };
1418 
1420 
1421 template <std::size_t PacketIdBytes>
1424  typename packet_id_type<PacketIdBytes>::type packet_id,
1425  v5::pubrel_reason_code reason_code,
1426  properties props)
1427  : fixed_header_(make_fixed_header(control_packet_type::pubrel, 0b0010)),
1428  reason_code_(reason_code),
1429  property_length_(
1430  std::accumulate(
1431  props.begin(),
1432  props.end(),
1433  std::size_t(0U),
1434  [](std::size_t total, property_variant const& pv) {
1435  return total + v5::size(pv);
1436  }
1437  )
1438  ),
1439  props_(force_move(props)),
1440  num_of_const_buffer_sequence_(
1441  1 + // fixed header
1442  1 + // remaining length
1443  1 + // packet id
1444  // TODO: This is wrong. The reason code MUST be provided
1445  // if there are properties. Not the other way around.
1446  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
1447  // 3.6.2.1 PUBREL Reason Code
1448  // The Reason Code and Property Length can be omitted if
1449  // the Reason Code is 0x00 (Success) and there are no Properties.
1450  // In this case the PUBREL has a Remaining Length of 2.
1451  [&] () -> std::size_t {
1452  if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) {
1453  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
1454  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1455  if (props_.empty()) {
1456  return 1; // reason code
1457  }
1458  else {
1459  return
1460  1 + // reason code
1461  1 + // property length
1462  std::accumulate( // properties
1463  props_.begin(),
1464  props_.end(),
1465  std::size_t(0U),
1466  [](std::size_t total, property_variant const& pv) {
1467  return total + v5::num_of_const_buffer_sequence(pv);
1468  }
1469  );
1470  }
1471  }
1472  else {
1473  return 0;
1474  }
1475  } ()
1476  )
1477  {
1478  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
1479  auto pb = variable_bytes(property_length_);
1480  for (auto e : pb) {
1481  property_length_buf_.push_back(e);
1482  }
1483 
1484  remaining_length_ =
1485  PacketIdBytes + // packet id
1486  // TODO: This is wrong. The reason code MUST be provided
1487  // if there are properties. Not the other way around.
1488  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
1489  // 3.6.2.1 PUBREL Reason Code
1490  // The Reason Code and Property Length can be omitted if
1491  // the Reason Code is 0x00 (Success) and there are no Properties.
1492  // In this case the PUBREL has a Remaining Length of 2.
1493  [&] () -> std::size_t {
1494  if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) {
1495  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
1496  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1497  if (props_.empty()) {
1498  return 1; // reason code
1499  }
1500  else {
1501  return
1502  1 + // reason code
1503  property_length_buf_.size() +
1504  property_length_;
1505  }
1506  }
1507  else {
1508  return 0;
1509  }
1510  } ();
1511 
1512  auto rb = remaining_bytes(remaining_length_);
1513  for (auto e : rb) {
1514  remaining_length_buf_.push_back(e);
1515  }
1516  }
1517 
1519  if (buf.empty()) throw remaining_length_error();
1520  fixed_header_ = static_cast<std::uint8_t>(buf.front());
1521  buf.remove_prefix(1);
1522 
1523  if (buf.empty()) throw remaining_length_error();
1524  auto len_consumed = remaining_length(buf.begin(), buf.end());
1525  remaining_length_ = std::get<0>(len_consumed);
1526  auto consumed = std::get<1>(len_consumed);
1527 
1528  std::copy(
1529  buf.begin(),
1530  std::next(buf.begin(), static_cast<buffer::difference_type>(consumed)),
1531  std::back_inserter(remaining_length_buf_));
1532  buf.remove_prefix(consumed);
1533 
1534  if (buf.size() < PacketIdBytes) throw remaining_length_error();
1535  std::copy(buf.begin(), std::next(buf.begin(), PacketIdBytes), std::back_inserter(packet_id_));
1536  buf.remove_prefix(PacketIdBytes);
1537 
1538  if (buf.empty()) {
1539  num_of_const_buffer_sequence_ =
1540  1 + // fixed header
1541  1 + // remaining length
1542  1; // packet id
1543  reason_code_ = v5::pubrel_reason_code::success;
1544  return;
1545  }
1546 
1547  reason_code_ = static_cast<v5::pubrel_reason_code>(buf.front());
1548  buf.remove_prefix(1);
1549 
1550  if (buf.empty()) {
1551  property_length_ = 0;
1552  }
1553  else {
1554  auto len_consume = variable_length(
1555  buf.begin(),
1556  buf.end()
1557  );
1558  property_length_ = std::get<0>(len_consume);
1559  auto consume = std::get<1>(len_consume);
1560  if (consume == 0) throw property_length_error();
1561  std::copy(
1562  buf.begin(),
1563  std::next(buf.begin(), static_cast<buffer::difference_type>(consume)),
1564  std::back_inserter(property_length_buf_)
1565  );
1566  buf.remove_prefix(consume);
1567  if (buf.size() != property_length_) throw property_length_error();
1568 
1569  props_ = property::parse(buf);
1570  buf.remove_prefix(property_length_);
1571  }
1572 
1573  num_of_const_buffer_sequence_ =
1574  1 + // fixed header
1575  1 + // remaining length
1576  1 + // packet id
1577  // TODO: This is wrong. The reason code MUST be provided
1578  // if there are properties. Not the other way around.
1579  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
1580  // 3.6.2.1 PUBREL Reason Code
1581  // The Reason Code and Property Length can be omitted if
1582  // the Reason Code is 0x00 (Success) and there are no Properties.
1583  // In this case the PUBREL has a Remaining Length of 2.
1584  [&] () -> std::size_t {
1585  if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) {
1586  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
1587  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1588  if (props_.empty()) {
1589  return 1; // reason code
1590  }
1591  else {
1592  return
1593  1 + // reason code
1594  1 + // property length
1595  std::accumulate( // properties
1596  props_.begin(),
1597  props_.end(),
1598  std::size_t(0U),
1599  [](std::size_t total, property_variant const& pv) {
1600  return total + v5::num_of_const_buffer_sequence(pv);
1601  }
1602  );
1603  }
1604  }
1605  else {
1606  return 0;
1607  }
1608  } ();
1609  }
1610 
1616  std::vector<as::const_buffer> const_buffer_sequence() const {
1617  std::vector<as::const_buffer> ret;
1618  ret.reserve(num_of_const_buffer_sequence());
1619 
1620  ret.emplace_back(as::buffer(&fixed_header_, 1));
1621  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
1622  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
1623 
1624  // TODO: This is wrong. The reason code MUST be provided
1625  // if there are properties. Not the other way around.
1626  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
1627  // 3.6.2.1 PUBREL Reason Code
1628  // The Reason Code and Property Length can be omitted if
1629  // the Reason Code is 0x00 (Success) and there are no Properties.
1630  // In this case the PUBREL has a Remaining Length of 2.
1631  if(reason_code_ != v5::pubrel_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
1632  ret.emplace_back(as::buffer(&reason_code_, 1));
1633  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
1634  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1635  if (!props_.empty()) {
1636  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
1637 
1638  for (auto const& p : props_) {
1640  }
1641  }
1642  }
1643  return ret;
1644  }
1645 
1650  std::size_t size() const {
1651  return
1652  1 + // fixed header
1653  remaining_length_buf_.size() +
1654  remaining_length_;
1655  }
1656 
1661  constexpr std::size_t num_of_const_buffer_sequence() const {
1662  return num_of_const_buffer_sequence_;
1663  }
1664 
1671  std::string continuous_buffer() const {
1672  std::string ret;
1673  auto sz = size();
1674  ret.reserve(sz);
1675 
1676  ret.push_back(static_cast<char>(fixed_header_));
1677  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
1678  ret.append(packet_id_.data(), packet_id_.size());
1679 
1680  // TODO: This is wrong. The reason code MUST be provided
1681  // if there are properties. Not the other way around.
1682  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
1683  // 3.6.2.1 PUBREL Reason Code
1684  // The Reason Code and Property Length can be omitted if
1685  // the Reason Code is 0x00 (Success) and there are no Properties.
1686  // In this case the PUBREL has a Remaining Length of 2.
1687  if (reason_code_ != v5::pubrel_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
1688  ret.push_back(static_cast<char>(reason_code_));
1689 
1690  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
1691  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1692  if (!props_.empty()) {
1693  ret.append(property_length_buf_.data(), property_length_buf_.size());
1694 
1695  auto it = ret.end();
1696  ret.resize(sz);
1697  auto end = ret.end();
1698  for (auto const& p : props_) {
1699  v5::fill(p, it, end);
1700  it += static_cast<std::string::difference_type>(v5::size(p));
1701  }
1702  }
1703  }
1704  return ret;
1705  }
1706 
1711  decltype(auto) packet_id() const {
1712  return make_packet_id<PacketIdBytes>::apply(packet_id_.begin(), packet_id_.end());
1713  }
1714 
1720  return reason_code_;
1721  }
1722 
1727  properties const& props() const {
1728  return props_;
1729  }
1730 
1731  std::uint8_t fixed_header_;
1732  std::size_t remaining_length_;
1733  boost::container::static_vector<char, 4> remaining_length_buf_;
1734  boost::container::static_vector<char, PacketIdBytes> packet_id_;
1736  std::size_t property_length_;
1737  boost::container::static_vector<char, 4> property_length_buf_;
1740 };
1741 
1744 
1745 template <std::size_t PacketIdBytes>
1748  typename packet_id_type<PacketIdBytes>::type packet_id,
1749  pubcomp_reason_code reason_code,
1750  properties props)
1751  : fixed_header_(make_fixed_header(control_packet_type::pubcomp, 0b0000)),
1752  reason_code_(reason_code),
1753  property_length_(
1754  std::accumulate(
1755  props.begin(),
1756  props.end(),
1757  std::size_t(0U),
1758  [](std::size_t total, property_variant const& pv) {
1759  return total + v5::size(pv);
1760  }
1761  )
1762  ),
1763  props_(force_move(props)),
1764  num_of_const_buffer_sequence_(
1765  1 + // fixed header
1766  1 + // remaining length
1767  1 + // packet id
1768  // TODO: This is wrong. The reason code MUST be provided
1769  // if there are properties. Not the other way around.
1770  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
1771  // 3.7.2.1 PUBCOMP Reason Code
1772  // The Reason Code and Property Length can be omitted if
1773  // the Reason Code is 0x00 (Success) and there are no Properties.
1774  // In this case the PUBCOMP has a Remaining Length of 2.
1775  [&] () -> std::size_t {
1776  if ((reason_code_ != v5::pubcomp_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) {
1777  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
1778  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1779  if (props_.empty()) {
1780  return 1; // reason code
1781  }
1782  else {
1783  return
1784  1 + // reason code
1785  1 + // property length
1786  std::accumulate( // properties
1787  props_.begin(),
1788  props_.end(),
1789  std::size_t(0U),
1790  [](std::size_t total, property_variant const& pv) {
1791  return total + v5::num_of_const_buffer_sequence(pv);
1792  }
1793  );
1794  }
1795  }
1796  else {
1797  return 0;
1798  }
1799  } ()
1800  )
1801  {
1802  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
1803  auto pb = variable_bytes(property_length_);
1804  for (auto e : pb) {
1805  property_length_buf_.push_back(e);
1806  }
1807 
1808  remaining_length_ =
1809  PacketIdBytes + // packet id
1810  // TODO: This is wrong. The reason code MUST be provided
1811  // if there are properties. Not the other way around.
1812  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
1813  // 3.7.2.1 PUBCOMP Reason Code
1814  // The Reason Code and Property Length can be omitted if
1815  // the Reason Code is 0x00 (Success) and there are no Properties.
1816  // In this case the PUBCOMP has a Remaining Length of 2.
1817  [&] () -> std::size_t {
1818  if ((reason_code_ != v5::pubcomp_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) {
1819  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
1820  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1821  if (props_.empty()) {
1822  return 1; // reason code
1823  }
1824  else {
1825  return
1826  1 + // reason code
1827  property_length_buf_.size() +
1828  property_length_;
1829  }
1830  }
1831  else {
1832  return 0;
1833  }
1834  } ();
1835 
1836  auto rb = remaining_bytes(remaining_length_);
1837  for (auto e : rb) {
1838  remaining_length_buf_.push_back(e);
1839  }
1840  }
1841 
1847  std::vector<as::const_buffer> const_buffer_sequence() const {
1848  std::vector<as::const_buffer> ret;
1849  ret.reserve(num_of_const_buffer_sequence());
1850 
1851  ret.emplace_back(as::buffer(&fixed_header_, 1));
1852  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
1853  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
1854 
1855  // TODO: This is wrong. The reason code MUST be provided
1856  // if there are properties. Not the other way around.
1857  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
1858  // 3.7.2.1 PUBCOMP Reason Code
1859  // The Reason Code and Property Length can be omitted if
1860  // the Reason Code is 0x00 (Success) and there are no Properties.
1861  // In this case the PUBCOMP has a Remaining Length of 2.
1862  if (reason_code_ != v5::pubcomp_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
1863  ret.emplace_back(as::buffer(&reason_code_, 1));
1864  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
1865  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1866  if (!props_.empty()) {
1867  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
1868 
1869  for (auto const& p : props_) {
1871  }
1872  }
1873  }
1874  return ret;
1875  }
1876 
1881  std::size_t size() const {
1882  return
1883  1 + // fixed header
1884  remaining_length_buf_.size() +
1885  remaining_length_;
1886  }
1887 
1892  constexpr std::size_t num_of_const_buffer_sequence() const {
1893  return num_of_const_buffer_sequence_;
1894  }
1895 
1902  std::string continuous_buffer() const {
1903  std::string ret;
1904  auto sz = size();
1905  ret.reserve(sz);
1906 
1907  ret.push_back(static_cast<char>(fixed_header_));
1908  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
1909 
1910  // TODO: This is wrong. The reason code MUST be provided
1911  // if there are properties. Not the other way around.
1912  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
1913  // 3.7.2.1 PUBCOMP Reason Code
1914  // The Reason Code and Property Length can be omitted if
1915  // the Reason Code is 0x00 (Success) and there are no Properties.
1916  // In this case the PUBCOMP has a Remaining Length of 2.
1917  if (reason_code_ != v5::pubcomp_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
1918  ret.push_back(static_cast<char>(reason_code_));
1919 
1920  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
1921  // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used.
1922  if (!props_.empty()) {
1923  ret.append(property_length_buf_.data(), property_length_buf_.size());
1924 
1925  auto it = ret.end();
1926  ret.resize(sz);
1927  auto end = ret.end();
1928  for (auto const& p : props_) {
1929  v5::fill(p, it, end);
1930  it += static_cast<std::string::difference_type>(v5::size(p));
1931  }
1932  }
1933  }
1934  return ret;
1935  }
1936 
1937 
1938  std::uint8_t fixed_header_;
1939  std::size_t remaining_length_;
1940  boost::container::static_vector<char, 4> remaining_length_buf_;
1941  boost::container::static_vector<char, PacketIdBytes> packet_id_;
1943  std::size_t property_length_;
1944  boost::container::static_vector<char, 4> property_length_buf_;
1947 };
1948 
1950 
1951 template <std::size_t PacketIdBytes>
1953 private:
1954  struct entry {
1955  entry(as::const_buffer topic_filter, subscribe_options options)
1956  : topic_filter_(topic_filter),
1957  topic_filter_length_buf_ { num_to_2bytes(boost::numeric_cast<std::uint16_t>(topic_filter_.size())) },
1958  options_(options)
1959  {}
1960 
1961  as::const_buffer topic_filter_;
1962  boost::container::static_vector<char, 2> topic_filter_length_buf_;
1963  subscribe_options options_;
1964  };
1965 
1966 public:
1968  std::vector<std::tuple<as::const_buffer, subscribe_options>> params,
1969  typename packet_id_type<PacketIdBytes>::type packet_id,
1970  properties props
1971  )
1972  : fixed_header_(make_fixed_header(control_packet_type::subscribe, 0b0010)),
1973  remaining_length_(PacketIdBytes),
1974  property_length_(
1975  std::accumulate(
1976  props.begin(),
1977  props.end(),
1978  std::size_t(0U),
1979  [](std::size_t total, property_variant const& pv) {
1980  return total + v5::size(pv);
1981  }
1982  )
1983  ),
1984  props_(force_move(props)),
1985  num_of_const_buffer_sequence_(
1986  1 + // fixed header
1987  1 + // remaining length
1988  1 + // packet id
1989  1 + // property length
1990  std::accumulate(
1991  props_.begin(),
1992  props_.end(),
1993  std::size_t(0U),
1994  [](std::size_t total, property_variant const& pv) {
1995  return total + v5::num_of_const_buffer_sequence(pv);
1996  }
1997  ) +
1998  params.size() * 3 // topic filter length, topic filter, qos
1999  )
2000  {
2001  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
2002 
2003  auto pb = variable_bytes(property_length_);
2004  for (auto e : pb) {
2005  property_length_buf_.push_back(e);
2006  }
2007 
2008  remaining_length_ +=
2009  property_length_buf_.size() +
2010  property_length_;
2011 
2012  // Check for errors before allocating.
2013  for (auto&& e : params) {
2014  as::const_buffer topic_filter = std::get<0>(e);
2015  utf8string_check(topic_filter);
2016  }
2017 
2018  entries_.reserve(params.size());
2019  for (auto&& e : params) {
2020  as::const_buffer topic_filter = std::get<0>(e);
2021  size_t size = topic_filter.size();
2022 
2023  entries_.emplace_back(topic_filter, std::get<1>(e));
2024  remaining_length_ +=
2025  2 + // topic filter length
2026  size + // topic filter
2027  1; // means QoS
2028  }
2029 
2030  auto rb = remaining_bytes(remaining_length_);
2031  for (auto e : rb) {
2032  remaining_length_buf_.push_back(e);
2033  }
2034  }
2035 
2041  std::vector<as::const_buffer> const_buffer_sequence() const {
2042  std::vector<as::const_buffer> ret;
2043  ret.reserve(num_of_const_buffer_sequence());
2044 
2045  ret.emplace_back(as::buffer(&fixed_header_, 1));
2046 
2047  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2048 
2049  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
2050 
2051  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2052  for (auto const& p : props_) {
2054  }
2055 
2056  for (auto const& e : entries_) {
2057  ret.emplace_back(as::buffer(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size()));
2058  ret.emplace_back(as::buffer(e.topic_filter_));
2059  ret.emplace_back(as::buffer(&e.options_, 1));
2060  }
2061 
2062  return ret;
2063  }
2064 
2069  std::size_t size() const {
2070  return
2071  1 + // fixed header
2072  remaining_length_buf_.size() +
2073  remaining_length_;
2074  }
2075 
2080  constexpr std::size_t num_of_const_buffer_sequence() const {
2081  return num_of_const_buffer_sequence_;
2082  }
2083 
2090  std::string continuous_buffer() const {
2091  std::string ret;
2092 
2093  ret.reserve(size());
2094 
2095  ret.push_back(static_cast<char>(fixed_header_));
2096  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2097 
2098  ret.append(packet_id_.data(), packet_id_.size());
2099 
2100  ret.append(property_length_buf_.data(), property_length_buf_.size());
2101 
2102  auto it = ret.end();
2103  ret.resize(ret.size() + property_length_);
2104  auto end = ret.end();
2105  for (auto const& p : props_) {
2106  v5::fill(p, it, end);
2107  it += static_cast<std::string::difference_type>(v5::size(p));
2108  }
2109 
2110  for (auto const& e : entries_) {
2111  ret.append(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size());
2112  ret.append(get_pointer(e.topic_filter_), get_size(e.topic_filter_));
2113  ret.push_back(static_cast<char>(e.options_.operator std::uint8_t()));
2114  }
2115 
2116  return ret;
2117  }
2118 
2119 private:
2120  std::uint8_t fixed_header_;
2121  std::vector<entry> entries_;
2122  boost::container::static_vector<char, PacketIdBytes> packet_id_;
2123  std::size_t remaining_length_;
2124  boost::container::static_vector<char, 4> remaining_length_buf_;
2125  std::size_t property_length_;
2126  boost::container::static_vector<char, 4> property_length_buf_;
2127  properties props_;
2128  std::size_t num_of_const_buffer_sequence_;
2129 };
2130 
2132 
2133 template <std::size_t PacketIdBytes>
2135 public:
2137  std::vector<suback_reason_code> reason_codes,
2138  typename packet_id_type<PacketIdBytes>::type packet_id,
2139  properties props
2140  )
2141  : fixed_header_(make_fixed_header(control_packet_type::suback, 0b0000)),
2142  remaining_length_(reason_codes.size() + PacketIdBytes),
2143  property_length_(
2144  std::accumulate(
2145  props.begin(),
2146  props.end(),
2147  std::size_t(0U),
2148  [](std::size_t total, property_variant const& pv) {
2149  return total + v5::size(pv);
2150  }
2151  )
2152  ),
2153  props_(force_move(props)),
2154  num_of_const_buffer_sequence_(
2155  1 + // fixed header
2156  1 + // remaining length
2157  1 + // packet id
2158  1 + // property length
2159  std::accumulate(
2160  props_.begin(),
2161  props_.end(),
2162  std::size_t(0U),
2163  [](std::size_t total, property_variant const& pv) {
2164  return total + v5::num_of_const_buffer_sequence(pv);
2165  }
2166  ) +
2167  1 // entries (reason code ...)
2168  )
2169  {
2170  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
2171 
2172  auto pb = variable_bytes(property_length_);
2173  for (auto e : pb) {
2174  property_length_buf_.push_back(e);
2175  }
2176 
2177  remaining_length_ +=
2178  property_length_buf_.size() +
2179  property_length_;
2180 
2181  auto rb = remaining_bytes(remaining_length_);
2182  for (auto e : rb) {
2183  remaining_length_buf_.push_back(e);
2184  }
2185  entries_.reserve(reason_codes.size());
2186  for (auto e : reason_codes) {
2187  entries_.push_back(static_cast<char>(e));
2188  }
2189  }
2190 
2196  std::vector<as::const_buffer> const_buffer_sequence() const {
2197  std::vector<as::const_buffer> ret;
2198  ret.reserve(num_of_const_buffer_sequence());
2199 
2200  ret.emplace_back(as::buffer(&fixed_header_, 1));
2201  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2202  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
2203 
2204  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2205  for (auto const& p : props_) {
2207  }
2208 
2209  ret.emplace_back(as::buffer(entries_));
2210 
2211  return ret;
2212  }
2213 
2218  std::size_t size() const {
2219  return
2220  1 + // fixed header
2221  remaining_length_buf_.size() +
2222  remaining_length_;
2223  }
2224 
2229  constexpr std::size_t num_of_const_buffer_sequence() const {
2230  return num_of_const_buffer_sequence_;
2231  }
2232 
2239  std::string continuous_buffer() const {
2240  std::string ret;
2241 
2242  ret.reserve(size());
2243 
2244  ret.push_back(static_cast<char>(fixed_header_));
2245  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2246 
2247  ret.append(packet_id_.data(), packet_id_.size());
2248 
2249  auto it = ret.end();
2250  ret.resize(ret.size() + property_length_);
2251  auto end = ret.end();
2252  for (auto const& p : props_) {
2253  v5::fill(p, it, end);
2254  it += static_cast<std::string::difference_type>(v5::size(p));
2255  }
2256 
2257  ret.append(entries_);
2258 
2259  return ret;
2260  }
2261 
2262 private:
2263  std::uint8_t fixed_header_;
2264  std::string entries_;
2265  boost::container::static_vector<char, PacketIdBytes> packet_id_;
2266  std::size_t remaining_length_;
2267  boost::container::static_vector<char, 4> remaining_length_buf_;
2268  std::size_t property_length_;
2269  boost::container::static_vector<char, 4> property_length_buf_;
2270  properties props_;
2271  std::size_t num_of_const_buffer_sequence_;
2272 };
2273 
2275 
2276 template <std::size_t PacketIdBytes>
2278 private:
2279  struct entry {
2280  entry(as::const_buffer topic_filter)
2281  : topic_filter_(topic_filter),
2282  topic_filter_length_buf_ { num_to_2bytes(boost::numeric_cast<std::uint16_t>(topic_filter.size())) }
2283  {}
2284 
2285  as::const_buffer topic_filter_;
2286  boost::container::static_vector<char, 2> topic_filter_length_buf_;
2287  };
2288 
2289 public:
2291  std::vector<as::const_buffer> params,
2292  typename packet_id_type<PacketIdBytes>::type packet_id,
2293  properties props
2294  )
2295  : fixed_header_(make_fixed_header(control_packet_type::unsubscribe, 0b0010)),
2296  remaining_length_(PacketIdBytes),
2297  property_length_(
2298  std::accumulate(
2299  props.begin(),
2300  props.end(),
2301  std::size_t(0U),
2302  [](std::size_t total, property_variant const& pv) {
2303  return total + v5::size(pv);
2304  }
2305  )
2306  ),
2307  props_(force_move(props)),
2308  num_of_const_buffer_sequence_(
2309  1 + // fixed header
2310  1 + // remaining length
2311  1 + // packet id
2312  1 + // property length
2313  std::accumulate(
2314  props_.begin(),
2315  props_.end(),
2316  std::size_t(0U),
2317  [](std::size_t total, property_variant const& pv) {
2318  return total + v5::num_of_const_buffer_sequence(pv);
2319  }
2320  ) +
2321  params.size() * 2 // topic filter length, topic filter
2322  )
2323  {
2324  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
2325 
2326  auto pb = variable_bytes(property_length_);
2327  for (auto e : pb) {
2328  property_length_buf_.push_back(e);
2329  }
2330 
2331  remaining_length_ +=
2332  property_length_buf_.size() +
2333  property_length_;
2334 
2335  // Check for errors before allocating.
2336  for (auto&& e : params) {
2337  utf8string_check(e);
2338  }
2339 
2340  entries_.reserve(params.size());
2341  for (auto&& e : params) {
2342  auto size = e.size();
2343  entries_.emplace_back(e);
2344  remaining_length_ +=
2345  2 + // topic filter length
2346  size; // topic filter
2347  }
2348  auto rb = remaining_bytes(remaining_length_);
2349  for (auto e : rb) {
2350  remaining_length_buf_.push_back(e);
2351  }
2352  }
2353 
2359  std::vector<as::const_buffer> const_buffer_sequence() const {
2360  std::vector<as::const_buffer> ret;
2361  ret.reserve(num_of_const_buffer_sequence());
2362 
2363  ret.emplace_back(as::buffer(&fixed_header_, 1));
2364  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2365 
2366  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
2367 
2368  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2369  for (auto const& p : props_) {
2371  }
2372 
2373  for (auto const& e : entries_) {
2374  ret.emplace_back(as::buffer(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size()));
2375  ret.emplace_back(as::buffer(e.topic_filter_));
2376  }
2377 
2378  return ret;
2379  }
2380 
2385  std::size_t size() const {
2386  return
2387  1 + // fixed header
2388  remaining_length_buf_.size() +
2389  remaining_length_;
2390  }
2391 
2396  constexpr std::size_t num_of_const_buffer_sequence() const {
2397  return num_of_const_buffer_sequence_;
2398  }
2399 
2406  std::string continuous_buffer() const {
2407  std::string ret;
2408  ret.reserve(size());
2409 
2410  ret.push_back(static_cast<char>(fixed_header_));
2411 
2412  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2413 
2414  ret.append(packet_id_.data(), packet_id_.size());
2415 
2416  auto it = ret.end();
2417  ret.resize(ret.size() + property_length_);
2418  auto end = ret.end();
2419  for (auto const& p : props_) {
2420  v5::fill(p, it, end);
2421  it += static_cast<std::string::difference_type>(v5::size(p));
2422  }
2423 
2424  for (auto const& e : entries_) {
2425  ret.append(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size());
2426  ret.append(get_pointer(e.topic_filter_), get_size(e.topic_filter_));
2427  }
2428 
2429  return ret;
2430  }
2431 
2432 private:
2433  std::uint8_t fixed_header_;
2434  std::vector<entry> entries_;
2435  boost::container::static_vector<char, PacketIdBytes> packet_id_;
2436  std::size_t remaining_length_;
2437  boost::container::static_vector<char, 4> remaining_length_buf_;
2438  std::size_t property_length_;
2439  boost::container::static_vector<char, 4> property_length_buf_;
2440  properties props_;
2441  std::size_t num_of_const_buffer_sequence_;
2442 };
2443 
2445 
2446 template <std::size_t PacketIdBytes>
2448 public:
2450  std::vector<v5::unsuback_reason_code> reason_codes,
2451  typename packet_id_type<PacketIdBytes>::type packet_id,
2452  properties props
2453  )
2454  : fixed_header_(make_fixed_header(control_packet_type::unsuback, 0b0000)),
2455  reason_codes_(force_move(reason_codes)),
2456  remaining_length_(reason_codes_.size() + PacketIdBytes),
2457  property_length_(
2458  std::accumulate(
2459  props.begin(),
2460  props.end(),
2461  std::size_t(0U),
2462  [](std::size_t total, property_variant const& pv) {
2463  return total + v5::size(pv);
2464  }
2465  )
2466  ),
2467  props_(force_move(props)),
2468  num_of_const_buffer_sequence_(
2469  1 + // fixed header
2470  1 + // remaining length
2471  1 + // packet id
2472  1 + // property length
2473  std::accumulate(
2474  props_.begin(),
2475  props_.end(),
2476  std::size_t(0U),
2477  [](std::size_t total, property_variant const& pv) {
2478  return total + v5::num_of_const_buffer_sequence(pv);
2479  }
2480  )
2481  )
2482  {
2483  add_packet_id_to_buf<PacketIdBytes>::apply(packet_id_, packet_id);
2484 
2485  auto pb = variable_bytes(property_length_);
2486  for (auto e : pb) {
2487  property_length_buf_.push_back(e);
2488  }
2489 
2490  remaining_length_ +=
2491  property_length_buf_.size() +
2492  property_length_;
2493 
2494  auto rb = remaining_bytes(remaining_length_);
2495  for (auto e : rb) {
2496  remaining_length_buf_.push_back(e);
2497  }
2498  }
2499 
2505  std::vector<as::const_buffer> const_buffer_sequence() const {
2506  std::vector<as::const_buffer> ret;
2507  ret.reserve(num_of_const_buffer_sequence());
2508 
2509  ret.emplace_back(as::buffer(&fixed_header_, 1));
2510  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2511  ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size()));
2512 
2513  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2514  for (auto const& p : props_) {
2516  }
2517 
2518  ret.emplace_back(as::buffer(reinterpret_cast<char const*>(reason_codes_.data()), reason_codes_.size()));
2519 
2520  return ret;
2521  }
2522 
2527  std::size_t size() const {
2528  return
2529  1 + // fixed header
2530  remaining_length_buf_.size() +
2531  remaining_length_;
2532  }
2533 
2538  constexpr std::size_t num_of_const_buffer_sequence() const {
2539  return num_of_const_buffer_sequence_;
2540  }
2541 
2548  std::string continuous_buffer() const {
2549  std::string ret;
2550 
2551  ret.reserve(size());
2552 
2553  ret.push_back(static_cast<char>(fixed_header_));
2554  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2555 
2556  ret.append(packet_id_.data(), packet_id_.size());
2557 
2558  auto it = ret.end();
2559  ret.resize(ret.size() + property_length_);
2560  auto end = ret.end();
2561  for (auto const& p : props_) {
2562  v5::fill(p, it, end);
2563  it += static_cast<std::string::difference_type>(v5::size(p));
2564  }
2565 
2566  ret.append(reinterpret_cast<char const*>(reason_codes_.data()), reason_codes_.size());
2567 
2568  return ret;
2569  }
2570 
2571 private:
2572  std::uint8_t fixed_header_;
2573  std::vector<v5::unsuback_reason_code> reason_codes_;
2574  boost::container::static_vector<char, PacketIdBytes> packet_id_;
2575  std::size_t remaining_length_;
2576  boost::container::static_vector<char, 4> remaining_length_buf_;
2577  std::size_t property_length_;
2578  boost::container::static_vector<char, 4> property_length_buf_;
2579  properties props_;
2580  std::size_t num_of_const_buffer_sequence_;
2581 };
2582 
2584 
2587  : detail::header_only_message(control_packet_type::pingreq, 0b0000)
2588  {}
2589 };
2590 
2593  : detail::header_only_message(control_packet_type::pingresp, 0b0000)
2594  {}
2595 };
2596 
2599  v5::disconnect_reason_code reason_code,
2600  properties props
2601  )
2602  : fixed_header_(make_fixed_header(control_packet_type::disconnect, 0b0000)),
2603  remaining_length_(0),
2604  reason_code_(reason_code),
2605  property_length_(
2606  std::accumulate(
2607  props.begin(),
2608  props.end(),
2609  std::size_t(0U),
2610  [](std::size_t total, property_variant const& pv) {
2611  return total + v5::size(pv);
2612  }
2613  )
2614  ),
2615  props_(force_move(props)),
2616  num_of_const_buffer_sequence_(
2617  1 + // fixed header
2618  1 + // remaining length
2619  (
2620  // TODO: This is wrong. The reason code MUST be provided
2621  // if there are properties. Not the other way around.
2622  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
2623  // 3.14.2.1 Disconnect Reason Code
2624  // The Reason Code and Property Length can be omitted if
2625  // the Reason Code is 0x00 (Normal disconnecton) and there are no
2626  // Properties. In this case the DISCONNECT has a Remaining Length of 0.
2627  reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE ? (
2628  1 + // reason code
2629  1 + // property length
2630  std::accumulate(
2631  props_.begin(),
2632  props_.end(),
2633  std::size_t(0U),
2634  [](std::size_t total, property_variant const& pv) {
2635  return total + v5::num_of_const_buffer_sequence(pv);
2636  }
2637  )
2638  )
2639  : 0
2640  )
2641  )
2642  {
2643  auto pb = variable_bytes(property_length_);
2644  for (auto e : pb) {
2645  property_length_buf_.push_back(e);
2646  }
2647  // TODO: This is wrong. The reason code MUST be provided
2648  // if there are properties. Not the other way around.
2649  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
2650  // 3.14.2.1 Disconnect Reason Code
2651  // The Reason Code and Property Length can be omitted if
2652  // the Reason Code is 0x00 (Normal disconnecton) and there are no
2653  // Properties. In this case the DISCONNECT has a Remaining Length of 0.
2654  if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) {
2655  remaining_length_ =
2656  1 + // reason code
2657  property_length_buf_.size() +
2658  property_length_;
2659  }
2660  auto rb = remaining_bytes(remaining_length_);
2661  for (auto e : rb) {
2662  remaining_length_buf_.push_back(e);
2663  }
2664  }
2670  std::vector<as::const_buffer> const_buffer_sequence() const {
2671  std::vector<as::const_buffer> ret;
2672  ret.reserve(num_of_const_buffer_sequence());
2673 
2674  ret.emplace_back(as::buffer(&fixed_header_, 1));
2675  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2676 
2677  // TODO: This is wrong. The reason code MUST be provided
2678  // if there are properties. Not the other way around.
2679  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
2680  // 3.14.2.1 Disconnect Reason Code
2681  // The Reason Code and Property Length can be omitted if
2682  // the Reason Code is 0x00 (Normal disconnecton) and there are no
2683  // Properties. In this case the DISCONNECT has a Remaining Length of 0.
2684  if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) {
2685  ret.emplace_back(as::buffer(&reason_code_, 1));
2686 
2687  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2688  for (auto const& p : props_) {
2690  }
2691  }
2692 
2693  return ret;
2694  }
2695 
2700  std::size_t size() const {
2701  return
2702  1 + // fixed header
2703  remaining_length_buf_.size() +
2704  remaining_length_;
2705  }
2706 
2711  constexpr std::size_t num_of_const_buffer_sequence() const {
2712  return num_of_const_buffer_sequence_;
2713  }
2714 
2721  std::string continuous_buffer() const {
2722  std::string ret;
2723 
2724  ret.reserve(size());
2725 
2726  ret.push_back(static_cast<char>(fixed_header_));
2727  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2728 
2729  // TODO: This is wrong. The reason code MUST be provided
2730  // if there are properties. Not the other way around.
2731  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
2732  // 3.14.2.1 Disconnect Reason Code
2733  // The Reason Code and Property Length can be omitted if
2734  // the Reason Code is 0x00 (Normal disconnecton) and there are no
2735  // Properties. In this case the DISCONNECT has a Remaining Length of 0.
2736  if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) {
2737  ret.push_back(static_cast<char>(reason_code_));
2738 
2739  auto it = ret.end();
2740  ret.resize(ret.size() + property_length_);
2741  auto end = ret.end();
2742  for (auto const& p : props_) {
2743  v5::fill(p, it, end);
2744  it += static_cast<std::string::difference_type>(v5::size(p));
2745  }
2746  }
2747 
2748  return ret;
2749  }
2750 
2751 private:
2752  std::uint8_t fixed_header_;
2753 
2754  std::size_t remaining_length_;
2755  boost::container::static_vector<char, 4> remaining_length_buf_;
2756 
2757  v5::disconnect_reason_code reason_code_;
2758 
2759  std::size_t property_length_;
2760  boost::container::static_vector<char, 4> property_length_buf_;
2761  properties props_;
2762  std::size_t num_of_const_buffer_sequence_;
2763 };
2764 
2767  v5::auth_reason_code reason_code,
2768  properties props
2769  )
2770  : fixed_header_(make_fixed_header(control_packet_type::auth, 0b0000)),
2771  remaining_length_(0),
2772  reason_code_(reason_code),
2773  property_length_(
2774  std::accumulate(
2775  props.begin(),
2776  props.end(),
2777  std::size_t(0U),
2778  [](std::size_t total, property_variant const& pv) {
2779  return total + v5::size(pv);
2780  }
2781  )
2782  ),
2783  props_(force_move(props)),
2784  num_of_const_buffer_sequence_(
2785  1 + // fixed header
2786  1 + // remaining length
2787  (
2788  // TODO: This is wrong. The reason code MUST be provided
2789  // if there are properties. Not the other way around.
2790  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
2791  // 3.15.2.1 Authenticate Reason Code
2792  // The Reason Code and Property Length can be omitted if
2793  // the Reason Code is 0x00 (Success) and there are no
2794  // Properties. In this case the AUTH has a Remaining Length of 0.
2795  reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE ?
2796  (
2797  1 + // reason code
2798  1 + // property length
2799  std::accumulate(
2800  props_.begin(),
2801  props_.end(),
2802  std::size_t(0U),
2803  [](std::size_t total, property_variant const& pv) {
2804  return total + v5::num_of_const_buffer_sequence(pv);
2805  }
2806  )
2807  )
2808  : 0
2809  )
2810  )
2811  {
2812  auto pb = variable_bytes(property_length_);
2813  for (auto e : pb) {
2814  property_length_buf_.push_back(e);
2815  }
2816  // TODO: This is wrong. The reason code MUST be provided
2817  // if there are properties. Not the other way around.
2818  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
2819  // 3.15.2.1 Authenticate Reason Code
2820  // The Reason Code and Property Length can be omitted if
2821  // the Reason Code is 0x00 (Success) and there are no
2822  // Properties. In this case the AUTH has a Remaining Length of 0.
2823  if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
2824  remaining_length_ =
2825  1 + // reason code
2826  property_length_buf_.size() +
2827  property_length_;
2828  }
2829  auto rb = remaining_bytes(remaining_length_);
2830  for (auto e : rb) {
2831  remaining_length_buf_.push_back(e);
2832  }
2833  }
2834 
2840  std::vector<as::const_buffer> const_buffer_sequence() const {
2841  std::vector<as::const_buffer> ret;
2842  ret.reserve(num_of_const_buffer_sequence());
2843 
2844  ret.emplace_back(as::buffer(&fixed_header_, 1));
2845  ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size()));
2846 
2847  // TODO: This is wrong. The reason code MUST be provided
2848  // if there are properties. Not the other way around.
2849  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
2850  // 3.15.2.1 Authenticate Reason Code
2851  // The Reason Code and Property Length can be omitted if
2852  // the Reason Code is 0x00 (Success) and there are no
2853  // Properties. In this case the AUTH has a Remaining Length of 0.
2854  if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
2855  ret.emplace_back(as::buffer(&reason_code_, 1));
2856 
2857  ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size()));
2858  for (auto const& p : props_) {
2860  }
2861  }
2862 
2863  return ret;
2864  }
2865 
2870  std::size_t size() const {
2871  return
2872  1 + // fixed header
2873  remaining_length_buf_.size() +
2874  remaining_length_;
2875  }
2876 
2881  constexpr std::size_t num_of_const_buffer_sequence() const {
2882  return num_of_const_buffer_sequence_;
2883  }
2884 
2891  std::string continuous_buffer() const {
2892  std::string ret;
2893 
2894  ret.reserve(size());
2895 
2896  ret.push_back(static_cast<char>(fixed_header_));
2897  ret.append(remaining_length_buf_.data(), remaining_length_buf_.size());
2898 
2899  // TODO: This is wrong. The reason code MUST be provided
2900  // if there are properties. Not the other way around.
2901  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
2902  // 3.15.2.1 Authenticate Reason Code
2903  // The Reason Code and Property Length can be omitted if
2904  // the Reason Code is 0x00 (Success) and there are no
2905  // Properties. In this case the AUTH has a Remaining Length of 0.
2906  if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) {
2907  ret.push_back(static_cast<char>(reason_code_));
2908 
2909  auto it = ret.end();
2910  ret.resize(ret.size() + property_length_);
2911  auto end = ret.end();
2912  for (auto const& p : props_) {
2913  v5::fill(p, it, end);
2914  it += static_cast<std::string::difference_type>(v5::size(p));
2915  }
2916  }
2917 
2918  return ret;
2919  }
2920 
2921 private:
2922  std::uint8_t fixed_header_;
2923 
2924  std::size_t remaining_length_;
2925  boost::container::static_vector<char, 4> remaining_length_buf_;
2926 
2927  v5::auth_reason_code reason_code_;
2928 
2929  std::size_t property_length_;
2930  boost::container::static_vector<char, 4> property_length_buf_;
2931  properties props_;
2932  std::size_t num_of_const_buffer_sequence_;
2933 };
2934 
2935 } // namespace v5
2936 
2937 } // namespace MQTT_NS
2938 
2939 #endif // MQTT_V5_MESSAGE_HPP
buffer that has string_view interface This class provides string_view interface. This class hold stri...
Definition: buffer.hpp:30
buffer substr(std::size_t offset, std::size_t length=string_view::npos) const &
get substring The returned buffer ragnge is the same as std::string_view::substr()....
Definition: buffer.hpp:68
Definition: v5_message.hpp:544
void set_topic_name(as::const_buffer topic_name)
Set topic name.
Definition: v5_message.hpp:980
constexpr bool is_retain() const
Check retain flag.
Definition: v5_message.hpp:820
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:714
constexpr void set_dup(bool dup)
Set dup flag.
Definition: v5_message.hpp:972
basic_publish_message(buffer buf)
Definition: v5_message.hpp:629
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:741
constexpr bool is_dup() const
Check dup flag.
Definition: v5_message.hpp:828
properties const & props() const
Get properties.
Definition: v5_message.hpp:886
packet_id_type< PacketIdBytes >::type packet_id() const
Get packet id.
Definition: v5_message.hpp:796
void remove_prop(v5::property::id id)
Remove property.
Definition: v5_message.hpp:939
std::vector< string_view > payload() const
Get payload.
Definition: v5_message.hpp:844
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:752
std::enable_if_t< std::is_base_of< property::detail::n_bytes_property< 1 >, Property >::value||std::is_base_of< property::detail::n_bytes_property< 2 >, Property >::value||std::is_base_of< property::detail::n_bytes_property< 4 >, Property >::value > update_prop(Property update_prop)
Update property Only fixed size property can be updated.
Definition: v5_message.hpp:923
buffer payload_as_buffer() const
Get payload as single buffer.
Definition: v5_message.hpp:857
basic_publish_message(typename packet_id_type< PacketIdBytes >::type packet_id, as::const_buffer topic_name, ConstBufferSequence payloads, publish_options pubopts, properties props)
Definition: v5_message.hpp:553
void add_prop(property_variant p)
Add property.
Definition: v5_message.hpp:894
string_view topic() const
Get topic name.
Definition: v5_message.hpp:836
constexpr publish_options get_options() const
Get publish_options.
Definition: v5_message.hpp:804
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:762
constexpr qos get_qos() const
Get qos.
Definition: v5_message.hpp:812
Definition: v5_message.hpp:2134
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2229
basic_suback_message(std::vector< suback_reason_code > reason_codes, typename packet_id_type< PacketIdBytes >::type packet_id, properties props)
Definition: v5_message.hpp:2136
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2239
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2218
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2196
Definition: v5_message.hpp:1952
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2080
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2069
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2041
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2090
basic_subscribe_message(std::vector< std::tuple< as::const_buffer, subscribe_options >> params, typename packet_id_type< PacketIdBytes >::type packet_id, properties props)
Definition: v5_message.hpp:1967
Definition: v5_message.hpp:2447
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2505
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2538
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2527
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2548
basic_unsuback_message(std::vector< v5::unsuback_reason_code > reason_codes, typename packet_id_type< PacketIdBytes >::type packet_id, properties props)
Definition: v5_message.hpp:2449
Definition: v5_message.hpp:2277
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2385
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2359
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2406
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2396
basic_unsubscribe_message(std::vector< as::const_buffer > params, typename packet_id_type< PacketIdBytes >::type packet_id, properties props)
Definition: v5_message.hpp:2290
Definition: v5_message.hpp:405
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:484
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:463
connack_message(bool session_present, connect_reason_code reason_code, properties props)
Definition: v5_message.hpp:407
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:495
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:505
Definition: v5_message.hpp:102
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:298
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:309
connect_message(std::uint16_t keep_alive_sec, buffer client_id, bool clean_start, optional< will > w, optional< buffer > user_name, optional< buffer > password, properties props)
Definition: v5_message.hpp:104
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:319
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:252
Definition: v5_message.hpp:53
header_only_message(control_packet_type type, std::uint8_t flags)
Create empty header_packet_id_message.
Definition: v5_message.hpp:58
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:93
static constexpr std::size_t num_of_const_buffer_sequence()
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:83
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:67
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:75
constexpr bool has_password_flag(char v)
Definition: connect_flags.hpp:43
constexpr char const will_retain
Definition: connect_flags.hpp:21
constexpr char const user_name_flag
Definition: connect_flags.hpp:23
constexpr char const will_flag
Definition: connect_flags.hpp:20
constexpr bool has_user_name_flag(char v)
Definition: connect_flags.hpp:47
constexpr char const clean_start
Definition: connect_flags.hpp:19
constexpr void set_will_qos(char &v, qos qos_value)
Definition: connect_flags.hpp:51
constexpr bool has_will_flag(char v)
Definition: connect_flags.hpp:33
constexpr char const password_flag
Definition: connect_flags.hpp:22
constexpr bool is_dup(std::uint8_t v)
Definition: publish.hpp:22
constexpr qos get_qos(std::uint8_t v)
Definition: publish.hpp:26
constexpr void set_dup(std::uint8_t &fixed_header, bool dup)
Definition: publish.hpp:34
constexpr bool is_retain(std::uint8_t v)
Definition: publish.hpp:30
std::vector< property_variant > parse(buffer buf)
Definition: property_parse.hpp:232
id
Definition: property_id.hpp:19
connect_reason_code
Definition: reason_code.hpp:50
std::size_t size(property_variant const &pv)
Definition: property_variant.hpp:117
auth_reason_code
Definition: reason_code.hpp:385
std::size_t num_of_const_buffer_sequence(property_variant const &pv)
Definition: property_variant.hpp:121
void fill(property_variant const &pv, Iterator b, Iterator e)
Definition: property_variant.hpp:127
pubrel_reason_code
Definition: reason_code.hpp:341
puback_reason_code
Definition: reason_code.hpp:269
pubrec_reason_code
Definition: reason_code.hpp:305
pubcomp_reason_code
Definition: reason_code.hpp:363
void add_const_buffer_sequence(std::vector< as::const_buffer > &v, property_variant const &pv)
Definition: property_variant.hpp:109
std::vector< property_variant > properties
Definition: property_variant.hpp:51
disconnect_reason_code
Definition: reason_code.hpp:114
property::id id(property_variant const &pv)
Definition: property_variant.hpp:113
variant< property::payload_format_indicator, property::message_expiry_interval, property::content_type, property::response_topic, property::correlation_data, property::subscription_identifier, property::session_expiry_interval, property::assigned_client_identifier, property::server_keep_alive, property::authentication_method, property::authentication_data, property::request_problem_information, property::will_delay_interval, property::request_response_information, property::response_information, property::server_reference, property::reason_string, property::receive_maximum, property::topic_alias_maximum, property::topic_alias, property::maximum_qos, property::retain_available, property::user_property, property::maximum_packet_size, property::wildcard_subscription_available, property::subscription_identifier_available, property::shared_subscription_available > property_variant
Definition: property_variant.hpp:49
Definition: any.hpp:27
std::string variable_bytes(std::size_t size)
Definition: variable_length.hpp:18
std::string remaining_bytes(std::size_t size)
Definition: remaining_length.hpp:17
boost::string_ref string_view
Definition: string_view.hpp:64
constexpr decltype(auto) visit(Visitor &&vis, Variants &&... vars)
Definition: variant.hpp:60
void utf8string_check(string_view str)
Definition: string_check.hpp:20
constexpr std::tuple< std::size_t, std::size_t > remaining_length(string_view bytes)
Definition: remaining_length.hpp:24
control_packet_type
Definition: control_packet_type.hpp:18
constexpr std::remove_reference_t< T > && force_move(T &&t)
Definition: move.hpp:20
boost::container::static_vector< char, 2 > num_to_2bytes(std::uint16_t val)
Definition: two_byte_util.hpp:20
void add_uint16_t_to_buf(T &buf, std::uint16_t num)
Definition: two_byte_util.hpp:28
dup
Definition: publish.hpp:48
std::size_t num_of_const_buffer_sequence(basic_message_variant< PacketIdBytes > const &mv)
Definition: message_variant.hpp:98
char const * get_pointer(as::const_buffer const &cb)
Definition: const_buffer_util.hpp:17
buffer const * buffer_sequence_end(buffer const &buf)
Definition: buffer.hpp:155
buffer const * buffer_sequence_begin(buffer const &buf)
Definition: buffer.hpp:151
lambda_visitor< Lambdas... > make_lambda_visitor(Lambdas &&... lambdas)
Definition: visitor_util.hpp:37
std::size_t size(basic_message_variant< PacketIdBytes > const &mv)
Definition: message_variant.hpp:93
constexpr std::tuple< std::size_t, std::size_t > variable_length(T const &bytes)
Definition: variable_length.hpp:42
qos
Definition: subscribe_options.hpp:34
constexpr std::uint16_t make_uint16_t(It b, It e)
Definition: two_byte_util.hpp:34
constexpr std::uint8_t make_fixed_header(control_packet_type type, std::uint8_t flags)
Definition: fixed_header.hpp:15
std::size_t get_size(as::const_buffer const &cb)
Definition: const_buffer_util.hpp:21
Definition: buffer.hpp:242
const_buffer buffer(MQTT_NS::buffer const &data)
create boost::asio::const_buffer from the MQTT_NS::buffer boost::asio::const_buffer is a kind of view...
Definition: buffer.hpp:253
Definition: buffer.hpp:241
shared_ptr_array make_shared_ptr_array(std::size_t size)
shared_ptr_array creating function. You can choose the target type.
Definition: two_or_four_byte_util.hpp:52
Definition: two_or_four_byte_util.hpp:33
Definition: exception.hpp:115
Definition: exception.hpp:21
Definition: publish.hpp:53
Definition: exception.hpp:33
Definition: subscribe_options.hpp:40
Definition: v5_message.hpp:2765
auth_message(v5::auth_reason_code reason_code, properties props)
Definition: v5_message.hpp:2766
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2870
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2840
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2881
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2891
Definition: v5_message.hpp:1013
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:1168
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:1147
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:1114
boost::container::static_vector< char, PacketIdBytes > packet_id_
Definition: v5_message.hpp:1206
boost::container::static_vector< char, 4 > property_length_buf_
Definition: v5_message.hpp:1209
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:1158
basic_puback_message(typename packet_id_type< PacketIdBytes >::type packet_id, v5::puback_reason_code reason_code, properties props)
Definition: v5_message.hpp:1014
boost::container::static_vector< char, 4 > remaining_length_buf_
Definition: v5_message.hpp:1205
std::size_t remaining_length_
Definition: v5_message.hpp:1204
std::size_t property_length_
Definition: v5_message.hpp:1208
properties props_
Definition: v5_message.hpp:1210
std::size_t num_of_const_buffer_sequence_
Definition: v5_message.hpp:1211
std::uint8_t fixed_header_
Definition: v5_message.hpp:1203
v5::puback_reason_code reason_code_
Definition: v5_message.hpp:1207
Definition: v5_message.hpp:1746
std::size_t num_of_const_buffer_sequence_
Definition: v5_message.hpp:1946
std::uint8_t fixed_header_
Definition: v5_message.hpp:1938
pubcomp_reason_code reason_code_
Definition: v5_message.hpp:1942
basic_pubcomp_message(typename packet_id_type< PacketIdBytes >::type packet_id, pubcomp_reason_code reason_code, properties props)
Definition: v5_message.hpp:1747
boost::container::static_vector< char, PacketIdBytes > packet_id_
Definition: v5_message.hpp:1941
std::size_t property_length_
Definition: v5_message.hpp:1943
std::size_t remaining_length_
Definition: v5_message.hpp:1939
properties props_
Definition: v5_message.hpp:1945
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:1847
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:1881
boost::container::static_vector< char, 4 > property_length_buf_
Definition: v5_message.hpp:1944
boost::container::static_vector< char, 4 > remaining_length_buf_
Definition: v5_message.hpp:1940
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:1892
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:1902
Definition: v5_message.hpp:1217
std::uint8_t fixed_header_
Definition: v5_message.hpp:1408
basic_pubrec_message(typename packet_id_type< PacketIdBytes >::type packet_id, pubrec_reason_code reason_code, properties props)
Definition: v5_message.hpp:1218
std::size_t property_length_
Definition: v5_message.hpp:1413
boost::container::static_vector< char, 4 > property_length_buf_
Definition: v5_message.hpp:1414
boost::container::static_vector< char, PacketIdBytes > packet_id_
Definition: v5_message.hpp:1411
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:1318
boost::container::static_vector< char, 4 > remaining_length_buf_
Definition: v5_message.hpp:1410
std::size_t num_of_const_buffer_sequence_
Definition: v5_message.hpp:1416
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:1351
properties props_
Definition: v5_message.hpp:1415
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:1372
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:1362
std::size_t remaining_length_
Definition: v5_message.hpp:1409
pubrec_reason_code reason_code_
Definition: v5_message.hpp:1412
Definition: v5_message.hpp:1422
basic_pubrel_message(buffer buf)
Definition: v5_message.hpp:1518
v5::pubrel_reason_code reason_code() const
Get reason_code.
Definition: v5_message.hpp:1719
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:1671
std::size_t property_length_
Definition: v5_message.hpp:1736
boost::container::static_vector< char, PacketIdBytes > packet_id_
Definition: v5_message.hpp:1734
boost::container::static_vector< char, 4 > property_length_buf_
Definition: v5_message.hpp:1737
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:1650
properties const & props() const
Get properties.
Definition: v5_message.hpp:1727
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:1616
boost::container::static_vector< char, 4 > remaining_length_buf_
Definition: v5_message.hpp:1733
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:1661
std::size_t remaining_length_
Definition: v5_message.hpp:1732
std::size_t num_of_const_buffer_sequence_
Definition: v5_message.hpp:1739
v5::pubrel_reason_code reason_code_
Definition: v5_message.hpp:1735
basic_pubrel_message(typename packet_id_type< PacketIdBytes >::type packet_id, v5::pubrel_reason_code reason_code, properties props)
Definition: v5_message.hpp:1423
properties props_
Definition: v5_message.hpp:1738
std::uint8_t fixed_header_
Definition: v5_message.hpp:1731
Definition: v5_message.hpp:2597
constexpr std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition: v5_message.hpp:2711
disconnect_message(v5::disconnect_reason_code reason_code, properties props)
Definition: v5_message.hpp:2598
std::string continuous_buffer() const
Create one continuours buffer. All sequence of buffers are concatinated. It is useful to store to fil...
Definition: v5_message.hpp:2721
std::size_t size() const
Get whole size of sequence.
Definition: v5_message.hpp:2700
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence it is for boost asio APIs.
Definition: v5_message.hpp:2670
Definition: v5_message.hpp:2585
pingreq_message()
Definition: v5_message.hpp:2586
Definition: v5_message.hpp:2591
pingresp_message()
Definition: v5_message.hpp:2592
#define MQTT_ALWAYS_SEND_REASON_CODE
Definition: v5_message.hpp:42