mqtt_cpp
endpoint.hpp
Go to the documentation of this file.
1 // Copyright Takatoshi Kondo 2015
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_ENDPOINT_HPP)
8 #define MQTT_ENDPOINT_HPP
9 
10 #include <mqtt/config.hpp> // should be top to configure variant limit
11 
12 #include <string>
13 #include <vector>
14 #include <deque>
15 #include <functional>
16 #include <set>
17 #include <memory>
18 #include <mutex>
19 #include <atomic>
20 #include <algorithm>
21 
22 #include <boost/any.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio.hpp>
25 #include <boost/lexical_cast.hpp>
26 #include <boost/multi_index_container.hpp>
27 #include <boost/multi_index/sequenced_index.hpp>
28 #include <boost/multi_index/ordered_index.hpp>
29 #include <boost/multi_index/member.hpp>
30 #include <boost/multi_index/mem_fun.hpp>
31 #include <boost/multi_index/composite_key.hpp>
32 #include <boost/system/error_code.hpp>
33 #include <boost/assert.hpp>
34 
35 #include <mqtt/namespace.hpp>
36 #include <mqtt/tls.hpp>
37 #include <mqtt/namespace.hpp>
38 #include <mqtt/attributes.hpp>
39 #include <mqtt/any.hpp>
40 #include <mqtt/fixed_header.hpp>
43 #include <mqtt/connect_flags.hpp>
44 #include <mqtt/will.hpp>
45 #include <mqtt/session_present.hpp>
47 #include <mqtt/publish.hpp>
49 #include <mqtt/exception.hpp>
50 #include <mqtt/tcp_endpoint.hpp>
52 #include <mqtt/message_variant.hpp>
53 #include <mqtt/two_byte_util.hpp>
54 #include <mqtt/four_byte_util.hpp>
55 #include <mqtt/packet_id_type.hpp>
56 #include <mqtt/optional.hpp>
59 #include <mqtt/reason_code.hpp>
60 #include <mqtt/buffer.hpp>
63 #include <mqtt/move.hpp>
64 #include <mqtt/deprecated.hpp>
65 #include <mqtt/deprecated_msg.hpp>
66 #include <mqtt/error_code.hpp>
67 #include <mqtt/log.hpp>
68 #include <mqtt/variant_visit.hpp>
71 #include <mqtt/subscribe_entry.hpp>
74 
75 #if defined(MQTT_USE_WS)
76 #include <mqtt/ws_endpoint.hpp>
77 #endif // defined(MQTT_USE_WS)
78 
79 // When https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90415 is fixed,
80 // update the condition.
81 
82 // https://gcc.gnu.org/develop.html#timeline
83 #define MQTT_LIBSTDCXX_GCC_730 20180125 // workaround required
84 #define MQTT_LIBSTDCXX_GCC_740 20181206 // workaround required
85 #define MQTT_LIBSTDCXX_GCC_750 20191114 // workaround required
86 #define MQTT_LIBSTDCXX_GCC_810 20180502 // workaround required
87 #define MQTT_LIBSTDCXX_GCC_820 20180726
88 #define MQTT_LIBSTDCXX_GCC_830 20190222
89 #define MQTT_LIBSTDCXX_GCC_910 20190503 // workaround required
90 #define MQTT_LIBSTDCXX_GCC_920 20190812 // workaround required
91 
92 #if !defined(MQTT_DISABLE_LIBSTDCXX_TUPLE_ANY_WORKAROUND)
93 #if defined(MQTT_STD_ANY) && defined(__GLIBCXX__) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_820) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_830)
94 
95 template <>
96 struct std::is_constructible<std::tuple<std::any>> : std::true_type {
97 };
98 
99 template <>
100 struct std::is_constructible<std::tuple<std::any>, std::tuple<std::any> const&> : std::true_type {
101 };
102 
103 template <>
104 struct std::is_copy_constructible<std::tuple<std::any>> : std::true_type {
105 };
106 
107 template <>
108 struct std::is_copy_constructible<std::_Head_base<0, std::any, false>> : std::true_type {
109 };
110 
111 template <>
112 struct std::is_constructible<std::_Head_base<0, std::any, false>, std::_Head_base<0, std::any, false> const&> : std::true_type {
113 };
114 
115 #endif // defined(MQTT_STD_ANY) && defined(__GLIBCXX__) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_820) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_830)
116 #endif // !defined(MQTT_DISABLE_LIBSTDCXX_TUPLE_ANY_WORKAROUND)
117 
118 #undef MQTT_LIBSTDCXX_GCC_730
119 #undef MQTT_LIBSTDCXX_GCC_740
120 #undef MQTT_LIBSTDCXX_GCC_750
121 #undef MQTT_LIBSTDCXX_GCC_810
122 #undef MQTT_LIBSTDCXX_GCC_820
123 #undef MQTT_LIBSTDCXX_GCC_830
124 #undef MQTT_LIBSTDCXX_GCC_910
125 #undef MQTT_LIBSTDCXX_GCC_920
126 
127 #if defined(__GNUC__)
128 #pragma GCC diagnostic push
129 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
130 #endif // defined(__GNUC__)
131 
132 #include <boost/asio/yield.hpp>
133 
134 namespace MQTT_NS {
135 
136 namespace detail {
137 
138 
139 template <typename T>
140 constexpr
141 std::enable_if_t< ! std::is_convertible<std::decay_t<T>, publish_options>::value, bool>
142 check_qos_value(T const&) {
143  return false;
144 }
145 
146 constexpr bool check_qos_value(publish_options pubopts) {
147  return pubopts.get_qos() != qos::at_most_once;
148 }
149 
150 template<typename ... Params>
151 constexpr bool should_generate_packet_id(Params const& ... params) {
152 #if __cplusplus >= 201703L // C++20 date is not determined yet
153  return (check_qos_value(params) || ...); // defaults to false for empty.
154 #else // __cplusplus >= 201703L
155  const bool results[] = {false, check_qos_value(params)... };
156  bool ret = false;
157  for(const bool val : results)
158  {
159  ret |= val;
160  }
161  return ret;
162 #endif // __cplusplus >= 201703L
163 }
164 
165 } // namespace detail
166 
167 namespace as = boost::asio;
168 namespace mi = boost::multi_index;
169 
170 template <typename Mutex = std::mutex, template<typename...> class LockGuard = std::lock_guard, std::size_t PacketIdBytes = 2>
171 class endpoint : public std::enable_shared_from_this<endpoint<Mutex, LockGuard, PacketIdBytes>> {
173  using this_type_sp = std::shared_ptr<this_type>;
174 
175 public:
176  using async_handler_t = std::function<void(error_code ec)>;
178 
182  endpoint(as::io_context& ioc, protocol_version version = protocol_version::undetermined, bool async_send_store = false)
183  :async_send_store_{async_send_store},
184  version_(version),
185  tim_pingresp_(ioc)
186  {
187  MQTT_LOG("mqtt_api", info)
188  << MQTT_ADD_VALUE(address, this)
189  << "create"
190  << " version:" << version
191  << " async_send_store:" << std::boolalpha << async_send_store;
192  }
193 
198  explicit endpoint(as::io_context& ioc, std::shared_ptr<MQTT_NS::socket> socket, protocol_version version = protocol_version::undetermined, bool async_send_store = false)
199  :socket_(force_move(socket)),
200  connected_(true),
201  async_send_store_{async_send_store},
202  version_(version),
203  tim_pingresp_(ioc)
204  {
205  MQTT_LOG("mqtt_api", info)
206  << MQTT_ADD_VALUE(address, this)
207  << "create"
208  << " version:" << version
209  << " async_send_store:" << std::boolalpha << async_send_store;
210  }
211 
212  // MQTT Common handlers
213 
214 private:
221  virtual bool on_pingreq() noexcept = 0;
222 
229  virtual bool on_pingresp() noexcept = 0;
230 
231 
232  // MQTT v3_1_1 handlers
233 
271  virtual bool on_connect(buffer client_id,
272  optional<buffer> user_name,
273  optional<buffer> password,
274  optional<will> will,
275  bool clean_session,
276  std::uint16_t keep_alive) noexcept = 0;
277 
290  virtual bool on_connack(bool session_present, connect_return_code return_code) noexcept = 0;
291 
309  virtual bool on_publish(optional<packet_id_t> packet_id,
310  publish_options pubopts,
311  buffer topic_name,
312  buffer contents) noexcept = 0;
313 
322  virtual bool on_puback(packet_id_t packet_id) noexcept = 0;
323 
332  virtual bool on_pubrec(packet_id_t packet_id) noexcept = 0;
333 
342  virtual bool on_pubrel(packet_id_t packet_id) noexcept = 0;
343 
352  virtual bool on_pubcomp(packet_id_t packet_id) noexcept = 0;
353 
364  virtual bool on_subscribe(packet_id_t packet_id,
365  std::vector<subscribe_entry> entries) noexcept = 0;
366 
378  virtual bool on_suback(packet_id_t packet_id, std::vector<suback_return_code> returns) noexcept = 0;
379 
390  virtual bool on_unsubscribe(packet_id_t packet_id, std::vector<unsubscribe_entry> entries) noexcept = 0;
391 
399  virtual bool on_unsuback(packet_id_t) noexcept = 0;
400 
406  virtual void on_disconnect() noexcept = 0;
407 
408  // MQTT v5 handlers
409 
453  virtual bool on_v5_connect(buffer client_id,
454  optional<buffer> user_name,
455  optional<buffer> password,
456  optional<will> will,
457  bool clean_start,
458  std::uint16_t keep_alive,
459  v5::properties props) noexcept = 0;
460 
477  virtual bool on_v5_connack(bool session_present,
478  v5::connect_reason_code reason_code,
479  v5::properties props) noexcept = 0;
480 
506  virtual bool on_v5_publish(optional<packet_id_t> packet_id,
507  publish_options pubopts,
508  buffer topic_name,
509  buffer contents,
510  v5::properties props) noexcept = 0;
511 
528  virtual bool on_v5_puback(packet_id_t packet_id,
529  v5::puback_reason_code reason_code,
530  v5::properties props) noexcept = 0;
531 
548  virtual bool on_v5_pubrec(packet_id_t packet_id,
549  v5::pubrec_reason_code reason_code,
550  v5::properties props) noexcept = 0;
551 
568  virtual bool on_v5_pubrel(packet_id_t packet_id,
569  v5::pubrel_reason_code reason_code,
570  v5::properties props) noexcept = 0;
571 
588  virtual bool on_v5_pubcomp(packet_id_t packet_id,
589  v5::pubcomp_reason_code reason_code,
590  v5::properties props) noexcept = 0;
591 
606  virtual bool on_v5_subscribe(packet_id_t packet_id,
607  std::vector<subscribe_entry> entries,
608  v5::properties props) noexcept = 0;
609 
625  virtual bool on_v5_suback(packet_id_t packet_id,
626  std::vector<v5::suback_reason_code> reasons,
627  v5::properties props) noexcept = 0;
628 
644  virtual bool on_v5_unsubscribe(packet_id_t packet_id,
645  std::vector<unsubscribe_entry> entries,
646  v5::properties props) noexcept = 0;
647 
663  virtual bool on_v5_unsuback(packet_id_t,
664  std::vector<v5::unsuback_reason_code> reasons,
665  v5::properties props) noexcept = 0;
666 
680  virtual void on_v5_disconnect(v5::disconnect_reason_code reason_code,
681  v5::properties props) noexcept = 0;
682 
697  virtual bool on_v5_auth(v5::auth_reason_code reason_code,
698  v5::properties props) noexcept = 0;
699 
700  // Original handlers
701 
702 protected:
709  virtual void on_close() noexcept = 0;
710 
718  virtual void on_error(error_code ec) noexcept = 0;
719 
720 private:
729  virtual void on_pub_res_sent(packet_id_t packet_id) noexcept = 0;
730 
737  virtual void on_serialize_publish_message(basic_publish_message<sizeof(packet_id_t)> msg) noexcept = 0;
738 
745  virtual void on_serialize_v5_publish_message(v5::basic_publish_message<sizeof(packet_id_t)> msg) noexcept = 0;
746 
755  virtual void on_serialize_pubrel_message(basic_pubrel_message<sizeof(packet_id_t)> msg) noexcept = 0;
756 
765  virtual void on_serialize_v5_pubrel_message(v5::basic_pubrel_message<sizeof(packet_id_t)> msg) noexcept = 0;
766 
771  virtual void on_serialize_remove(packet_id_t packet_id) noexcept = 0;
772 
773 protected:
778  virtual void on_pre_send() noexcept = 0;
779 
780 private:
788  virtual bool check_is_valid_length(control_packet_type packet_type, std::size_t remaining_length) noexcept = 0;
789 
790 protected:
796  MQTT_ALWAYS_INLINE virtual void on_mqtt_message_processed(any session_life_keeper) {
797  if (async_read_on_message_processed_) {
798  async_read_control_packet_type(force_move(session_life_keeper));
799  }
800  }
801 
802 public:
803  endpoint(this_type const&) = delete;
804  endpoint(this_type&&) = delete;
805  endpoint& operator=(this_type const&) = delete;
807 
816  bool clean_session() const {
817  return clean_start();
818  }
819 
828  bool clean_start() const {
829  return clean_start_;
830  }
831 
836  std::size_t get_total_bytes_received() const {
837  return total_bytes_received_;
838  }
839 
844  std::size_t get_total_bytes_sent() const {
845  return total_bytes_sent_;
846  }
847 
855  void set_auto_pub_response(bool b = true, bool async = true) {
856  auto_pub_response_ = b;
857  auto_pub_response_async_ = async;
858  }
859 
868  void set_auto_map_topic_alias_send(bool b = true) {
869  auto_map_topic_alias_send_ = b;
870  }
871 
880  void set_auto_replace_topic_alias_send(bool b = true) {
881  auto_replace_topic_alias_send_ = b;
882  }
883 
884  void set_packet_bulk_read_limit(std::size_t size) {
885  packet_bulk_read_limit_ = size;
886  }
887 
888  void set_props_bulk_read_limit(std::size_t size) {
889  props_bulk_read_limit_ = size;
890  }
891 
898  LockGuard<Mutex> lck (topic_alias_recv_mtx_);
899  topic_alias_recv_.emplace(max);
900  }
901 
907  void start_session(any session_life_keeper = any()) {
908  MQTT_LOG("mqtt_api", info)
909  << MQTT_ADD_VALUE(address, this)
910  << "start_session";
911  async_read_control_packet_type(force_move(session_life_keeper));
912  }
913 
914  // Blocking APIs
915 
939  template <typename T, typename... Params>
940  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value, packet_id_t >
941  publish(T&& t, Params&&... params) {
942  if(detail::should_generate_packet_id(params...)) {
944  publish(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
945  return packet_id;
946  }
947  else {
948  publish(0, std::forward<T>(t), std::forward<Params>(params)...);
949  return 0;
950  }
951  }
952 
970  template <typename T, typename... Params>
971  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value, packet_id_t >
972  subscribe(T&& t, Params&&... params) {
974  subscribe(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
975  return packet_id;
976  }
977 
991  template <typename T, typename... Params>
992  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value, packet_id_t >
993  unsubscribe(T&& t, Params&&... params) {
995  unsubscribe(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
996  return packet_id;
997  }
998 
1016  v5::properties props = {}
1017  ) {
1018  MQTT_LOG("mqtt_api", info)
1019  << MQTT_ADD_VALUE(address, this)
1020  << "disconnect"
1021  << " reason:" << reason;
1022 
1023  if (connected_ && mqtt_connected_) {
1024  disconnect_requested_ = true;
1025  send_disconnect(reason, force_move(props));
1026  }
1027  }
1028 
1035  MQTT_LOG("mqtt_api", info)
1036  << MQTT_ADD_VALUE(address, this)
1037  << "force_disconnect";
1038 
1039  shutdown(socket());
1040 
1041  {
1042  LockGuard<Mutex> lck (topic_alias_send_mtx_);
1043  if (topic_alias_send_) topic_alias_send_.value().clear();
1044  }
1045  {
1046  LockGuard<Mutex> lck (topic_alias_recv_mtx_);
1047  if (topic_alias_recv_) topic_alias_recv_.value().clear();
1048  }
1049  }
1050 
1076  void publish(
1077  packet_id_t packet_id,
1078  std::string topic_name,
1079  std::string contents,
1080  publish_options pubopts = {},
1081  v5::properties props = {},
1082  any life_keeper = {}
1083  ) {
1084  MQTT_LOG("mqtt_api", info)
1085  << MQTT_ADD_VALUE(address, this)
1086  << "publish"
1087  << " pid:" << packet_id
1088  << " topic:" << topic_name
1089  << " qos:" << pubopts.get_qos()
1090  << " retain:" << pubopts.get_retain()
1091  << " dup:" << pubopts.get_dup();
1092 
1093  if (pubopts.get_qos() == qos::at_most_once) {
1094  // In the at_most_once case, we know a priori that send_publish won't track the lifetime.
1095  send_publish(packet_id,
1096  as::buffer(topic_name),
1097  as::buffer(contents),
1098  pubopts,
1099  force_move(props),
1100  any{});
1101  }
1102  else {
1103  auto sp_topic_name = std::make_shared<std::string>(force_move(topic_name));
1104  auto sp_contents = std::make_shared<std::string>(force_move(contents));
1105  auto topic_buf = as::buffer(*sp_topic_name);
1106  auto contents_buf = as::buffer(*sp_contents);
1107 
1108  send_publish(
1109  packet_id,
1110  topic_buf,
1111  contents_buf,
1112  pubopts,
1113  force_move(props),
1114  std::make_tuple(
1115  force_move(life_keeper),
1116  force_move(sp_topic_name),
1117  force_move(sp_contents)
1118  )
1119  );
1120  }
1121  }
1122 
1148  template <typename ConstBufferSequence>
1149  typename std::enable_if<
1150  as::is_const_buffer_sequence<ConstBufferSequence>::value
1151  >::type
1153  packet_id_t packet_id,
1154  as::const_buffer topic_name,
1155  ConstBufferSequence contents,
1156  publish_options pubopts,
1157  v5::properties props,
1158  any life_keeper
1159  ) {
1160  MQTT_LOG("mqtt_api", info)
1161  << MQTT_ADD_VALUE(address, this)
1162  << "publish"
1163  << " pid:" << packet_id
1164  << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name))
1165  << " qos:" << pubopts.get_qos()
1166  << " retain:" << pubopts.get_retain()
1167  << " dup:" << pubopts.get_dup();
1168 
1169  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
1170 
1171  send_publish(
1172  packet_id,
1173  topic_name,
1174  force_move(contents),
1175  pubopts,
1176  force_move(props),
1177  force_move(life_keeper)
1178  );
1179  }
1180 
1202  template <typename ConstBufferSequence>
1203  typename std::enable_if<
1204  as::is_const_buffer_sequence<ConstBufferSequence>::value
1205  >::type
1207  packet_id_t packet_id,
1208  as::const_buffer topic_name,
1209  ConstBufferSequence contents,
1210  publish_options pubopts,
1211  any life_keeper
1212  ) {
1213  MQTT_LOG("mqtt_api", info)
1214  << MQTT_ADD_VALUE(address, this)
1215  << "publish"
1216  << " pid:" << packet_id
1217  << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name))
1218  << " qos:" << pubopts.get_qos()
1219  << " retain:" << pubopts.get_retain()
1220  << " dup:" << pubopts.get_dup();
1221 
1222  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
1223 
1224  send_publish(
1225  packet_id,
1226  topic_name,
1227  force_move(contents),
1228  pubopts,
1229  v5::properties{},
1230  force_move(life_keeper)
1231  );
1232  }
1233 
1257  template <typename BufferSequence>
1258  typename std::enable_if<
1260  >::type
1262  packet_id_t packet_id,
1263  buffer topic_name,
1264  BufferSequence contents,
1265  publish_options pubopts = {},
1266  any life_keeper = {}
1267  ) {
1268  MQTT_LOG("mqtt_api", info)
1269  << MQTT_ADD_VALUE(address, this)
1270  << "publish"
1271  << " pid:" << packet_id
1272  << " topic:" << topic_name
1273  << " qos:" << pubopts.get_qos()
1274  << " retain:" << pubopts.get_retain()
1275  << " dup:" << pubopts.get_dup();
1276 
1277  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
1278 
1279  auto topic_name_buf = as::buffer(topic_name);
1280 
1281  std::vector<as::const_buffer> cbs;
1282  {
1283  auto b = MQTT_NS::buffer_sequence_begin(contents);
1284  auto e = MQTT_NS::buffer_sequence_end(contents);
1285  cbs.reserve(static_cast<std::size_t>(std::distance(b, e)));
1286  for (; b != e; ++b) {
1287  cbs.emplace_back(as::buffer(*b));
1288  }
1289  }
1290 
1291  send_publish(
1292  packet_id,
1293  topic_name_buf,
1294  force_move(cbs),
1295  pubopts,
1296  v5::properties{},
1297  std::make_tuple(
1298  force_move(life_keeper),
1299  force_move(topic_name),
1300  force_move(contents)
1301  )
1302  );
1303  }
1304 
1330  template <typename BufferSequence>
1331  typename std::enable_if<
1332  is_buffer_sequence<BufferSequence>::value
1333  >::type
1335  packet_id_t packet_id,
1336  buffer topic_name,
1337  BufferSequence contents,
1338  publish_options pubopts,
1339  v5::properties props,
1340  any life_keeper = {}
1341  ) {
1342  MQTT_LOG("mqtt_api", info)
1343  << MQTT_ADD_VALUE(address, this)
1344  << "publish"
1345  << " pid:" << packet_id
1346  << " topic:" << topic_name
1347  << " qos:" << pubopts.get_qos()
1348  << " retain:" << pubopts.get_retain()
1349  << " dup:" << pubopts.get_dup();
1350 
1351  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
1352 
1353  auto topic_name_buf = as::buffer(topic_name);
1354 
1355  std::vector<as::const_buffer> cbs;
1356  {
1357  auto b = MQTT_NS::buffer_sequence_begin(contents);
1358  auto e = MQTT_NS::buffer_sequence_end(contents);
1359  cbs.reserve(static_cast<std::size_t>(std::distance(b, e)));
1360  for (; b != e; ++b) {
1361  cbs.emplace_back(as::buffer(*b));
1362  }
1363  }
1364 
1365  send_publish(
1366  packet_id,
1367  topic_name_buf,
1368  force_move(cbs),
1369  pubopts,
1370  force_move(props),
1371  std::make_tuple(
1372  force_move(life_keeper),
1373  force_move(topic_name),
1374  force_move(contents)
1375  )
1376  );
1377  }
1378 
1398  packet_id_t packet_id,
1399  string_view topic_filter,
1400  subscribe_options option,
1401  v5::properties props = {}
1402  ) {
1403  MQTT_LOG("mqtt_api", info)
1404  << MQTT_ADD_VALUE(address, this)
1405  << "subscribe"
1406  << " pid:" << packet_id
1407  << " topic:" << topic_filter
1408  << " qos:" << option.get_qos()
1409  << " rh:" << option.get_retain_handling()
1410  << " nl:" << option.get_nl()
1411  << " rap:" << option.get_rap();
1412 
1413  send_subscribe(
1414  std::vector<std::tuple<as::const_buffer, subscribe_options>>{
1415  { as::buffer(topic_filter.data(), topic_filter.size()), option }
1416  },
1417  packet_id,
1418  force_move(props)
1419  );
1420  }
1421 
1441  packet_id_t packet_id,
1442  as::const_buffer topic_filter,
1443  subscribe_options option,
1444  v5::properties props = {}
1445  ) {
1446  MQTT_LOG("mqtt_api", info)
1447  << MQTT_ADD_VALUE(address, this)
1448  << "subscribe"
1449  << " pid:" << packet_id
1450  << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter))
1451  << " qos:" << option.get_qos()
1452  << " rh:" << option.get_retain_handling()
1453  << " nl:" << option.get_nl()
1454  << " rap:" << option.get_rap();
1455 
1456  send_subscribe(
1457  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter, option } },
1458  packet_id,
1459  force_move(props)
1460  );
1461  }
1462 
1477  packet_id_t packet_id,
1478  std::vector<std::tuple<string_view, subscribe_options>> params,
1479  v5::properties props = {}
1480  ) {
1481  MQTT_LOG("mqtt_api", info)
1482  << MQTT_ADD_VALUE(address, this)
1483  << "subscribe"
1484  << " pid:" << packet_id;
1485 
1486  std::vector<std::tuple<as::const_buffer, subscribe_options>> cb_params;
1487  cb_params.reserve(params.size());
1488  for (auto const& e : params) {
1489  cb_params.emplace_back(as::buffer(std::get<0>(e).data(), std::get<0>(e).size()), std::get<1>(e));
1490  }
1491  send_subscribe(force_move(cb_params), packet_id, force_move(props));
1492  }
1493 
1508  packet_id_t packet_id,
1509  std::vector<std::tuple<buffer, subscribe_options>> params,
1510  v5::properties props = {}
1511  ) {
1512  MQTT_LOG("mqtt_api", info)
1513  << MQTT_ADD_VALUE(address, this)
1514  << "subscribe"
1515  << " pid:" << packet_id;
1516 
1517  std::vector<std::tuple<as::const_buffer, subscribe_options>> buffers;
1518  buffers.reserve(params.size());
1519  for (auto const& tup : params) {
1520  buffers.emplace_back(as::buffer(std::get<0>(tup)), std::get<1>(tup));
1521  }
1522  send_subscribe(force_move(buffers), packet_id, force_move(props));
1523  }
1524 
1540  packet_id_t packet_id,
1541  string_view topic_filter,
1542  v5::properties props = {}
1543  ) {
1544  MQTT_LOG("mqtt_api", info)
1545  << MQTT_ADD_VALUE(address, this)
1546  << "unsubscribe"
1547  << " pid:" << packet_id
1548  << " topic:" << topic_filter;
1549 
1550  send_unsubscribe(
1551  std::vector<as::const_buffer> {
1552  as::buffer(topic_filter.data(), topic_filter.size())
1553  },
1554  packet_id,
1555  force_move(props)
1556  );
1557  }
1558 
1574  packet_id_t packet_id,
1575  as::const_buffer topic_filter,
1576  v5::properties props = {}
1577  ) {
1578  MQTT_LOG("mqtt_api", info)
1579  << MQTT_ADD_VALUE(address, this)
1580  << "unsubscribe"
1581  << " pid:" << packet_id
1582  << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter));
1583 
1584  send_unsubscribe(std::vector<as::const_buffer>{ topic_filter }, packet_id, force_move(props));
1585  }
1586 
1601  packet_id_t packet_id,
1602  std::vector<string_view> params,
1603  v5::properties props = {}
1604  ) {
1605  MQTT_LOG("mqtt_api", info)
1606  << MQTT_ADD_VALUE(address, this)
1607  << "unsubscribe"
1608  << " pid:" << packet_id;
1609 
1610  std::vector<as::const_buffer> cb_params;
1611  cb_params.reserve(params.size());
1612 
1613  for (auto&& e : params) {
1614  cb_params.emplace_back(as::buffer(e.data(), e.size()));
1615  }
1616  send_unsubscribe(force_move(cb_params), packet_id, force_move(props));
1617  }
1618 
1633  packet_id_t packet_id,
1634  std::vector<as::const_buffer> params,
1635  v5::properties props = {}
1636  ) {
1637  MQTT_LOG("mqtt_api", info)
1638  << MQTT_ADD_VALUE(address, this)
1639  << "unsubscribe"
1640  << " pid:" << packet_id;
1641 
1642  std::vector<buffer> cb_params;
1643  cb_params.reserve(params.size());
1644 
1645  for (auto&& e : params) {
1646  cb_params.emplace_back(buffer(string_view(get_pointer(e), get_size(e))));
1647  }
1648  send_unsubscribe(params, packet_id, force_move(props));
1649  }
1650 
1665  packet_id_t packet_id,
1666  std::vector<buffer> params,
1667  v5::properties props = {}
1668  ) {
1669  MQTT_LOG("mqtt_api", info)
1670  << MQTT_ADD_VALUE(address, this)
1671  << "unsubscribe"
1672  << " pid:" << packet_id;
1673 
1674  std::vector<as::const_buffer> cb_params;
1675  cb_params.reserve(params.size());
1676 
1677  for (auto&& e : params) {
1678  cb_params.emplace_back(as::buffer(e));
1679  }
1680  send_unsubscribe(force_move(cb_params), packet_id, force_move(props));
1681  }
1682 
1687  void pingreq() {
1688  // pingreq might frequently send, so SEV is set to trace
1689  MQTT_LOG("mqtt_api", trace)
1690  << MQTT_ADD_VALUE(address, this)
1691  << "pingreq";
1692 
1693  if (connected_ && mqtt_connected_) send_pingreq();
1694  }
1695 
1700  void pingresp() {
1701  // pingresp might frequently send, so SEV is set to trace
1702  MQTT_LOG("mqtt_api", trace)
1703  << MQTT_ADD_VALUE(address, this)
1704  << "pingrsp";
1705 
1706  send_pingresp();
1707  }
1708 
1721  void auth(
1723  v5::properties props = {}
1724  ) {
1725  MQTT_LOG("mqtt_api", info)
1726  << MQTT_ADD_VALUE(address, this)
1727  << "auth"
1728  << " reason:" << reason_code;
1729 
1730  send_auth(reason_code, force_move(props));
1731  }
1732 
1763  void connect(
1764  std::string const& client_id,
1765  optional<std::string> const& user_name,
1766  optional<std::string> const& password,
1767  optional<will> w,
1768  std::uint16_t keep_alive_sec,
1769  v5::properties props = {}
1770  ) {
1771  MQTT_LOG("mqtt_api", info)
1772  << MQTT_ADD_VALUE(address, this)
1773  << "connect"
1774  << " client_id:" << client_id
1775  << " user_name:" << (user_name ? user_name.value() : "none")
1776  << " keep_alive:" << std::dec << keep_alive_sec;
1777 
1778  connect_requested_ = true;
1779  send_connect(
1780  buffer(string_view(client_id)),
1781  [&] {
1782  if (user_name) {
1783  return buffer(string_view(user_name.value()));
1784  }
1785  else {
1786  return buffer();
1787  }
1788  } (),
1789  [&] {
1790  if (password) {
1791  return buffer(string_view(password.value()));
1792  }
1793  else {
1794  return buffer();
1795  }
1796  } (),
1797  force_move(w),
1798  keep_alive_sec,
1799  force_move(props)
1800  );
1801  }
1802 
1833  void connect(
1834  buffer client_id,
1835  optional<buffer> user_name,
1836  optional<buffer> password,
1837  optional<will> w,
1838  std::uint16_t keep_alive_sec,
1839  v5::properties props = {}
1840  ) {
1841  MQTT_LOG("mqtt_api", info)
1842  << MQTT_ADD_VALUE(address, this)
1843  << "connect"
1844  << " client_id:" << client_id
1845  << " user_name:" << (user_name ? string_view(user_name.value()) : string_view("none"))
1846  << " keep_alive:" << std::dec << keep_alive_sec;
1847 
1848  connect_requested_ = true;
1849  send_connect(
1850  force_move(client_id),
1851  force_move(user_name),
1852  force_move(password),
1853  force_move(w),
1854  keep_alive_sec,
1855  force_move(props)
1856  );
1857  }
1858 
1869  void connack(
1870  bool session_present,
1871  variant<connect_return_code, v5::connect_reason_code> reason_code,
1872  v5::properties props = {}
1873  ) {
1874  MQTT_LOG("mqtt_api", info)
1875  << MQTT_ADD_VALUE(address, this)
1876  << "connack"
1877  << " session_present:" << std::boolalpha << session_present
1878  << " reason:" << reason_code;
1879 
1880  send_connack(session_present, reason_code, force_move(props));
1881  }
1882 
1895  void puback(
1896  packet_id_t packet_id,
1898  v5::properties props = {}
1899  ) {
1900  MQTT_LOG("mqtt_api", info)
1901  << MQTT_ADD_VALUE(address, this)
1902  << "puback"
1903  << " pid:" << packet_id
1904  << " reason:" << reason_code;
1905 
1906  send_puback(packet_id, reason_code, force_move(props));
1907  }
1908 
1921  void pubrec(
1922  packet_id_t packet_id,
1924  v5::properties props = {}
1925  ) {
1926  MQTT_LOG("mqtt_api", info)
1927  << MQTT_ADD_VALUE(address, this)
1928  << "pubrec"
1929  << " pid:" << packet_id
1930  << " reason:" << reason_code;
1931 
1932  send_pubrec(packet_id, reason_code, force_move(props));
1933  }
1934 
1954  void pubrel(
1955  packet_id_t packet_id,
1957  v5::properties props = {},
1958  any life_keeper = {}
1959  ) {
1960  MQTT_LOG("mqtt_api", info)
1961  << MQTT_ADD_VALUE(address, this)
1962  << "pubrel"
1963  << " pid:" << packet_id
1964  << " reason:" << reason_code;
1965 
1966  send_pubrel(packet_id, reason_code, force_move(props), force_move(life_keeper));
1967  }
1968 
1981  void pubcomp(
1982  packet_id_t packet_id,
1984  v5::properties props = {}
1985  ) {
1986  MQTT_LOG("mqtt_api", info)
1987  << MQTT_ADD_VALUE(address, this)
1988  << "pubcomp"
1989  << " pid:" << packet_id
1990  << " reason:" << reason_code;
1991 
1992  send_pubcomp(packet_id, reason_code, force_move(props));
1993  }
1994 
2007  void suback(
2008  packet_id_t packet_id,
2009  variant<suback_return_code, v5::suback_reason_code> reason,
2010  v5::properties props = {}
2011  ) {
2012  MQTT_LOG("mqtt_api", info)
2013  << MQTT_ADD_VALUE(address, this)
2014  << "suback"
2015  << " pid:" << packet_id
2016  << " reason:" < reason;
2017 
2018  if (variant_idx(reason) == 0) {
2019  send_suback(std::vector<suback_return_code>{ variant_get<suback_return_code>(reason) }, packet_id, force_move(props));
2020  }
2021  else {
2022  send_suback(std::vector<v5::suback_reason_code>{ variant_get<v5::suback_reason_code>(reason) }, packet_id, force_move(props));
2023  }
2024  }
2025 
2038  void suback(
2039  packet_id_t packet_id,
2040  variant<std::vector<suback_return_code>, std::vector<v5::suback_reason_code>> reasons,
2041  v5::properties props = {}
2042  ) {
2043  MQTT_LOG("mqtt_api", info)
2044  << MQTT_ADD_VALUE(address, this)
2045  << "suback"
2046  << " pid:" << packet_id;
2047 
2048  send_suback(force_move(reasons), packet_id, force_move(props));
2049  }
2050 
2055  void unsuback(
2056  packet_id_t packet_id
2057  ) {
2058  MQTT_LOG("mqtt_api", info)
2059  << MQTT_ADD_VALUE(address, this)
2060  << "unsuback"
2061  << " pid:" << packet_id;
2062 
2063  send_unsuback(packet_id);
2064  }
2065 
2078  void unsuback(
2079  packet_id_t packet_id,
2080  v5::unsuback_reason_code reason,
2081  v5::properties props = {}
2082  ) {
2083  MQTT_LOG("mqtt_api", info)
2084  << MQTT_ADD_VALUE(address, this)
2085  << "unsuback"
2086  << " pid:" << packet_id
2087  << " reason:" << reason;
2088 
2089  send_unsuback(std::vector<v5::unsuback_reason_code>{ reason }, packet_id, force_move(props));
2090  }
2091 
2104  void unsuback(
2105  packet_id_t packet_id,
2106  std::vector<v5::unsuback_reason_code> reasons,
2107  v5::properties props = {}
2108  ) {
2109  MQTT_LOG("mqtt_api", info)
2110  << MQTT_ADD_VALUE(address, this)
2111  << "unsuback"
2112  << " pid:" << packet_id;
2113 
2114  send_unsuback(force_move(reasons), packet_id, force_move(props));
2115  }
2116 
2141  template <typename T, typename... Params>
2142  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value >
2143  async_publish(T&& t, Params&&... params) {
2144  if(detail::should_generate_packet_id(params...)) {
2145  packet_id_t packet_id = acquire_unique_packet_id();
2146  async_publish(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
2147  }
2148  else {
2149  async_publish(0, std::forward<T>(t), std::forward<Params>(params)...);
2150  }
2151  }
2152 
2162  async_handler_t func = {}
2163  ) {
2164  MQTT_LOG("mqtt_api", info)
2165  << MQTT_ADD_VALUE(address, this)
2166  << "async_disconnect";
2167 
2168  if (connected_ && mqtt_connected_) {
2169  disconnect_requested_ = true;
2170  // The reason code and property vector are only used if we're using mqttv5.
2172  v5::properties{},
2173  force_move(func));
2174  }
2175  }
2176 
2195  v5::properties props,
2196  async_handler_t func = {}
2197  ) {
2198  MQTT_LOG("mqtt_api", info)
2199  << MQTT_ADD_VALUE(address, this)
2200  << "async_disconnect"
2201  << " reason:" << reason;
2202 
2203  if (connected_ && mqtt_connected_) {
2204  disconnect_requested_ = true;
2205  async_send_disconnect(reason, force_move(props), force_move(func));
2206  }
2207  }
2208 
2209  // packet_id manual setting version
2210 
2225  template <typename T, typename... Params>
2226  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value >
2227  async_subscribe(T&& t, Params&&... params) {
2228  packet_id_t packet_id = acquire_unique_packet_id();
2229  async_subscribe(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
2230  }
2231 
2242  template <typename T, typename... Params>
2243  std::enable_if_t< ! std::is_convertible<std::decay_t<T>, packet_id_t>::value >
2244  async_unsubscribe(T&& t, Params&&... params) {
2245  packet_id_t packet_id = acquire_unique_packet_id();
2246  async_unsubscribe(packet_id, std::forward<T>(t), std::forward<Params>(params)...);
2247  }
2248 
2265  packet_id_t packet_id,
2266  std::string topic_name,
2267  std::string contents,
2268  publish_options pubopts = {},
2269  async_handler_t func = {}
2270  ) {
2271  MQTT_LOG("mqtt_api", info)
2272  << MQTT_ADD_VALUE(address, this)
2273  << "async_publish"
2274  << " pid:" << packet_id
2275  << " topic:" << topic_name
2276  << " qos:" << pubopts.get_qos()
2277  << " retain:" << pubopts.get_retain()
2278  << " dup:" << pubopts.get_dup();
2279 
2280  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2281 
2282  auto sp_topic_name = std::make_shared<std::string>(force_move(topic_name));
2283  auto sp_contents = std::make_shared<std::string>(force_move(contents));
2284  auto topic_name_buf = as::buffer(*sp_topic_name);
2285  auto contents_buf = as::buffer(*sp_contents);
2286 
2287  async_send_publish(
2288  packet_id,
2289  topic_name_buf,
2290  contents_buf,
2291  pubopts,
2292  v5::properties{},
2293  std::make_pair(force_move(sp_topic_name), force_move(sp_contents)),
2294  force_move(func)
2295  );
2296  }
2297 
2326  packet_id_t packet_id,
2327  std::string topic_name,
2328  std::string contents,
2329  publish_options pubopts,
2330  v5::properties props,
2331  any life_keeper = {},
2332  async_handler_t func = {}
2333  ) {
2334  MQTT_LOG("mqtt_api", info)
2335  << MQTT_ADD_VALUE(address, this)
2336  << "async_publish"
2337  << " pid:" << packet_id
2338  << " topic:" << topic_name
2339  << " qos:" << pubopts.get_qos()
2340  << " retain:" << pubopts.get_retain()
2341  << " dup:" << pubopts.get_dup();
2342 
2343  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2344 
2345  auto sp_topic_name = std::make_shared<std::string>(force_move(topic_name));
2346  auto sp_contents = std::make_shared<std::string>(force_move(contents));
2347  auto topic_name_buf = as::buffer(*sp_topic_name);
2348  auto contents_buf = as::buffer(*sp_contents);
2349 
2350  async_send_publish(
2351  packet_id,
2352  topic_name_buf,
2353  contents_buf,
2354  pubopts,
2355  force_move(props),
2356  std::make_tuple(
2357  force_move(life_keeper),
2358  force_move(sp_topic_name),
2359  force_move(sp_contents)
2360  ),
2361  force_move(func)
2362  );
2363  }
2364 
2388  template <typename ConstBufferSequence>
2389  typename std::enable_if<
2390  as::is_const_buffer_sequence<ConstBufferSequence>::value
2391  >::type
2393  packet_id_t packet_id,
2394  as::const_buffer topic_name,
2395  ConstBufferSequence contents,
2396  publish_options pubopts = {},
2397  any life_keeper = {},
2398  async_handler_t func = {}
2399  ) {
2400  MQTT_LOG("mqtt_api", info)
2401  << MQTT_ADD_VALUE(address, this)
2402  << "async_publish"
2403  << " pid:" << packet_id
2404  << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name))
2405  << " qos:" << pubopts.get_qos()
2406  << " retain:" << pubopts.get_retain()
2407  << " dup:" << pubopts.get_dup();
2408 
2409  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2410 
2411  async_send_publish(
2412  packet_id,
2413  topic_name,
2414  force_move(contents),
2415  pubopts,
2416  v5::properties{},
2417  force_move(life_keeper),
2418  force_move(func)
2419  );
2420  }
2421 
2445  template <typename ConstBufferSequence>
2446  typename std::enable_if<
2447  as::is_const_buffer_sequence<ConstBufferSequence>::value
2448  >::type
2450  packet_id_t packet_id,
2451  as::const_buffer topic_name,
2452  ConstBufferSequence contents,
2453  publish_options pubopts,
2454  v5::properties props,
2455  any life_keeper = {},
2456  async_handler_t func = {}
2457  ) {
2458  MQTT_LOG("mqtt_api", info)
2459  << MQTT_ADD_VALUE(address, this)
2460  << "async_publish"
2461  << " pid:" << packet_id
2462  << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name))
2463  << " qos:" << pubopts.get_qos()
2464  << " retain:" << pubopts.get_retain()
2465  << " dup:" << pubopts.get_dup();
2466 
2467  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2468 
2469  async_send_publish(
2470  packet_id,
2471  topic_name,
2472  force_move(contents),
2473  pubopts,
2474  force_move(props),
2475  force_move(life_keeper),
2476  force_move(func)
2477  );
2478  }
2479 
2499  template <typename BufferSequence>
2500  typename std::enable_if<
2501  is_buffer_sequence<BufferSequence>::value
2502  >::type
2504  packet_id_t packet_id,
2505  buffer topic_name,
2506  BufferSequence contents,
2507  publish_options pubopts = {},
2508  any life_keeper = {},
2509  async_handler_t func = {}
2510  ) {
2511  MQTT_LOG("mqtt_api", info)
2512  << MQTT_ADD_VALUE(address, this)
2513  << "async_publish"
2514  << " pid:" << packet_id
2515  << " topic:" << topic_name
2516  << " qos:" << pubopts.get_qos()
2517  << " retain:" << pubopts.get_retain()
2518  << " dup:" << pubopts.get_dup();
2519 
2520  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2521 
2522  auto topic_name_buf = as::buffer(topic_name);
2523 
2524  std::vector<as::const_buffer> cbs;
2525  {
2526  auto b = MQTT_NS::buffer_sequence_begin(contents);
2527  auto e = MQTT_NS::buffer_sequence_end(contents);
2528  cbs.reserve(static_cast<std::size_t>(std::distance(b, e)));
2529  for (; b != e; ++b) {
2530  cbs.emplace_back(as::buffer(*b));
2531  }
2532  }
2533 
2534  async_send_publish(
2535  packet_id,
2536  topic_name_buf,
2537  force_move(cbs),
2538  pubopts,
2539  v5::properties{},
2540  std::make_tuple(
2541  force_move(life_keeper),
2542  force_move(topic_name),
2543  force_move(contents)
2544  ),
2545  force_move(func)
2546  );
2547  }
2548 
2576  template <typename BufferSequence>
2577  typename std::enable_if<
2578  is_buffer_sequence<BufferSequence>::value
2579  >::type
2581  packet_id_t packet_id,
2582  buffer topic_name,
2583  BufferSequence contents,
2584  publish_options pubopts,
2585  v5::properties props,
2586  any life_keeper = {},
2587  async_handler_t func = {}
2588  ) {
2589  MQTT_LOG("mqtt_api", info)
2590  << MQTT_ADD_VALUE(address, this)
2591  << "async_publish"
2592  << " pid:" << packet_id
2593  << " topic:" << topic_name
2594  << " qos:" << pubopts.get_qos()
2595  << " retain:" << pubopts.get_retain()
2596  << " dup:" << pubopts.get_dup();
2597 
2598  BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0));
2599 
2600  auto topic_name_buf = as::buffer(topic_name);
2601 
2602  std::vector<as::const_buffer> cbs;
2603  {
2604  auto b = MQTT_NS::buffer_sequence_begin(contents);
2605  auto e = MQTT_NS::buffer_sequence_end(contents);
2606  cbs.reserve(static_cast<std::size_t>(std::distance(b, e)));
2607  for (; b != e; ++b) {
2608  cbs.emplace_back(as::buffer(*b));
2609  }
2610  }
2611 
2612  async_send_publish(
2613  packet_id,
2614  topic_name_buf,
2615  force_move(cbs),
2616  pubopts,
2617  force_move(props),
2618  std::make_tuple(
2619  force_move(life_keeper),
2620  force_move(topic_name),
2621  force_move(contents)
2622  ),
2623  force_move(func)
2624  );
2625  }
2647  packet_id_t packet_id,
2648  std::string topic_filter,
2649  subscribe_options option,
2650  async_handler_t func = {}
2651  ) {
2652  MQTT_LOG("mqtt_api", info)
2653  << MQTT_ADD_VALUE(address, this)
2654  << "async_subscribe"
2655  << " pid:" << packet_id
2656  << " topic:" << topic_filter
2657  << " qos:" << option.get_qos()
2658  << " rh:" << option.get_retain_handling()
2659  << " nl:" << option.get_nl()
2660  << " rap:" << option.get_rap();
2661 
2662  auto sp_topic_filter = std::make_shared<std::string>(force_move(topic_filter));
2663  auto topic_filter_buf = as::buffer(*sp_topic_filter);
2664 
2665  async_send_subscribe(
2666  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter_buf, option } },
2667  packet_id,
2668  v5::properties{},
2669  [life_keeper = force_move(sp_topic_filter), func = force_move(func)]
2670  (error_code ec) {
2671  if(func) func(ec);
2672  }
2673  );
2674  }
2675 
2697  packet_id_t packet_id,
2698  std::string topic_filter,
2699  subscribe_options option,
2700  v5::properties props,
2701  async_handler_t func = {}
2702  ) {
2703  MQTT_LOG("mqtt_api", info)
2704  << MQTT_ADD_VALUE(address, this)
2705  << "async_subscribe"
2706  << " pid:" << packet_id
2707  << " topic:" << topic_filter
2708  << " qos:" << option.get_qos()
2709  << " rh:" << option.get_retain_handling()
2710  << " nl:" << option.get_nl()
2711  << " rap:" << option.get_rap();
2712 
2713  auto sp_topic_filter = std::make_shared<std::string>(force_move(topic_filter));
2714  auto topic_filter_buf = as::buffer(*sp_topic_filter);
2715 
2716  async_send_subscribe(
2717  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter_buf, option } },
2718  packet_id,
2719  force_move(props),
2720  [life_keeper = force_move(sp_topic_filter), func = force_move(func)]
2721  (error_code ec) {
2722  if(func) func(ec);
2723  }
2724  );
2725  }
2726 
2745  packet_id_t packet_id,
2746  as::const_buffer topic_filter,
2747  subscribe_options option,
2748  async_handler_t func
2749  ) {
2750  MQTT_LOG("mqtt_api", info)
2751  << MQTT_ADD_VALUE(address, this)
2752  << "async_subscribe"
2753  << " pid:" << packet_id
2754  << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter))
2755  << " qos:" << option.get_qos()
2756  << " rh:" << option.get_retain_handling()
2757  << " nl:" << option.get_nl()
2758  << " rap:" << option.get_rap();
2759 
2760  async_send_subscribe(
2761  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter, option } },
2762  packet_id,
2763  v5::properties{},
2764  force_move(func)
2765  );
2766  }
2767 
2790  packet_id_t packet_id,
2791  as::const_buffer topic_filter,
2792  subscribe_options option,
2793  v5::properties props,
2794  async_handler_t func
2795  ) {
2796  MQTT_LOG("mqtt_api", info)
2797  << MQTT_ADD_VALUE(address, this)
2798  << "async_subscribe"
2799  << " pid:" << packet_id
2800  << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter))
2801  << " qos:" << option.get_qos()
2802  << " rh:" << option.get_retain_handling()
2803  << " nl:" << option.get_nl()
2804  << " rap:" << option.get_rap();
2805 
2806  async_send_subscribe(
2807  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter, option } },
2808  packet_id,
2809  force_move(props),
2810  force_move(func)
2811  );
2812  }
2813 
2831  packet_id_t packet_id,
2832  buffer topic_filter,
2833  subscribe_options option,
2834  async_handler_t func = {}
2835  ) {
2836  MQTT_LOG("mqtt_api", info)
2837  << MQTT_ADD_VALUE(address, this)
2838  << "async_subscribe"
2839  << " pid:" << packet_id
2840  << " topic:" << topic_filter
2841  << " qos:" << option.get_qos()
2842  << " rh:" << option.get_retain_handling()
2843  << " nl:" << option.get_nl()
2844  << " rap:" << option.get_rap();
2845 
2846  auto topic_filter_buf = as::buffer(topic_filter);
2847  async_send_subscribe(
2848  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter_buf, option } },
2849  packet_id,
2850  v5::properties{},
2851  [life_keeper = force_move(topic_filter), func = force_move(func)]
2852  (error_code ec) {
2853  if(func) func(ec);
2854  }
2855  );
2856  }
2857 
2879  packet_id_t packet_id,
2880  buffer topic_filter,
2881  subscribe_options option,
2882  v5::properties props,
2883  async_handler_t func = {}
2884  ) {
2885  MQTT_LOG("mqtt_api", info)
2886  << MQTT_ADD_VALUE(address, this)
2887  << "async_subscribe"
2888  << " pid:" << packet_id
2889  << " topic:" << topic_filter
2890  << " qos:" << option.get_qos()
2891  << " rh:" << option.get_retain_handling()
2892  << " nl:" << option.get_nl()
2893  << " rap:" << option.get_rap();
2894 
2895  auto topic_filter_buf = as::buffer(topic_filter);
2896  async_send_subscribe(
2897  std::vector<std::tuple<as::const_buffer, subscribe_options>>{ { topic_filter_buf, option } },
2898  packet_id,
2899  force_move(props),
2900  [life_keeper = force_move(topic_filter), func = force_move(func)]
2901  (error_code ec) {
2902  if(func) func(ec);
2903  }
2904  );
2905  }
2906 
2922  packet_id_t packet_id,
2923  std::vector<std::tuple<std::string, subscribe_options>> params,
2924  async_handler_t func = {}
2925  ) {
2926  MQTT_LOG("mqtt_api", info)
2927  << MQTT_ADD_VALUE(address, this)
2928  << "async_subscribe"
2929  << " pid:" << packet_id;
2930 
2931  std::vector<std::tuple<as::const_buffer, subscribe_options>> cb_params;
2932  cb_params.reserve(params.size());
2933 
2934  std::vector<std::shared_ptr<std::string>> life_keepers;
2935  life_keepers.reserve(params.size());
2936 
2937  for (auto&& e : params) {
2938  auto sp_topic_filter = std::make_shared<std::string>(force_move(std::get<0>(e)));
2939  cb_params.emplace_back(as::buffer(*sp_topic_filter), std::get<1>(e));
2940  life_keepers.emplace_back(force_move(sp_topic_filter));
2941  }
2942 
2943  async_send_subscribe(
2944  force_move(cb_params),
2945  packet_id,
2946  v5::properties{},
2947  [life_keeper = force_move(life_keepers), func = force_move(func)]
2948  (error_code ec) {
2949  if(func) func(ec);
2950  }
2951  );
2952  }
2953 
2973  packet_id_t packet_id,
2974  std::vector<std::tuple<std::string, subscribe_options>> params,
2975  v5::properties props,
2976  async_handler_t func = {}
2977  ) {
2978  MQTT_LOG("mqtt_api", info)
2979  << MQTT_ADD_VALUE(address, this)
2980  << "async_subscribe"
2981  << " pid:" << packet_id;
2982 
2983  std::vector<std::tuple<as::const_buffer, subscribe_options>> cb_params;
2984  cb_params.reserve(params.size());
2985 
2986  std::vector<std::shared_ptr<std::string>> life_keepers;
2987  life_keepers.reserve(params.size());
2988 
2989  for (auto&& e : params) {
2990  auto sp_topic_filter = std::make_shared<std::string>(force_move(std::get<0>(e)));
2991  cb_params.emplace_back(as::buffer(*sp_topic_filter), std::get<1>(e));
2992  life_keepers.emplace_back(force_move(sp_topic_filter));
2993  }
2994  async_send_subscribe(
2995  force_move(cb_params),
2996  packet_id,
2997  force_move(props),
2998  [life_keeper = force_move(life_keepers), func = force_move(func)]
2999  (error_code ec) {
3000  if(func) func(ec);
3001  }
3002  );
3003  }
3004 
3018  packet_id_t packet_id,
3019  std::vector<std::tuple<as::const_buffer, subscribe_options>> params,
3020  async_handler_t func
3021  ) {
3022  MQTT_LOG("mqtt_api", info)
3023  << MQTT_ADD_VALUE(address, this)
3024  << "async_subscribe"
3025  << " pid:" << packet_id;
3026 
3027  async_send_subscribe(
3028  force_move(params),
3029  packet_id,
3030  v5::properties{},
3031  force_move(func)
3032  );
3033  }
3034 
3051  packet_id_t packet_id,
3052  std::vector<std::tuple<as::const_buffer, subscribe_options>> params,
3053  v5::properties props,
3054  async_handler_t func
3055  ) {
3056  MQTT_LOG("mqtt_api", info)
3057  << MQTT_ADD_VALUE(address, this)
3058  << "async_subscribe"
3059  << " pid:" << packet_id;
3060 
3061  async_send_subscribe(
3062  force_move(params),
3063  packet_id,
3064  force_move(props),
3065  force_move(func)
3066  );
3067  }
3068 
3081  packet_id_t packet_id,
3082  std::vector<std::tuple<buffer, subscribe_options>> params,
3083  async_handler_t func = {}
3084  ) {
3085  MQTT_LOG("mqtt_api", info)
3086  << MQTT_ADD_VALUE(address, this)
3087  << "async_subscribe"
3088  << " pid:" << packet_id;
3089 
3090  std::vector<std::tuple<as::const_buffer, subscribe_options>> cb_params;
3091  cb_params.reserve(params.size());
3092 
3093  for (auto&& e : params) {
3094  cb_params.emplace_back(
3095  as::buffer(std::get<0>(e)),
3096  std::get<1>(e)
3097  );
3098  }
3099 
3100  async_send_subscribe(
3101  force_move(cb_params),
3102  packet_id,
3103  v5::properties{},
3104  [life_keeper = force_move(params), func = force_move(func)]
3105  (error_code ec) {
3106  if(func) func(ec);
3107  }
3108  );
3109  }
3110 
3126  packet_id_t packet_id,
3127  std::vector<std::tuple<buffer, subscribe_options>> params,
3128  v5::properties props,
3129  async_handler_t func = {}
3130  ) {
3131  MQTT_LOG("mqtt_api", info)
3132  << MQTT_ADD_VALUE(address, this)
3133  << "async_subscribe"
3134  << " pid:" << packet_id;
3135 
3136  std::vector<std::tuple<as::const_buffer, subscribe_options>> cb_params;
3137  cb_params.reserve(params.size());
3138 
3139  for (auto&& e : params) {
3140  cb_params.emplace_back(
3141  as::buffer(std::get<0>(e)),
3142  std::get<1>(e)
3143  );
3144  }
3145 
3146  async_send_subscribe(
3147  force_move(cb_params),
3148  packet_id,
3149  force_move(props),
3150  [life_keeper = force_move(params), func = force_move(func)]
3151  (error_code ec) {
3152  if(func) func(ec);
3153  }
3154  );
3155  }
3156 
3169  packet_id_t packet_id,
3170  std::string topic_filter,
3171  async_handler_t func = {}
3172  ) {
3173  MQTT_LOG("mqtt_api", info)
3174  << MQTT_ADD_VALUE(address, this)
3175  << "async_unsubscribe"
3176  << " pid:" << packet_id
3177  << " topic:" << topic_filter;
3178 
3179  auto sp_topic_filter = std::make_shared<std::string>(force_move(topic_filter));
3180  auto topic_filter_buf = as::buffer(*sp_topic_filter);
3181  async_send_unsubscribe(
3182  std::vector<as::const_buffer>{ topic_filter_buf },
3183  packet_id,
3184  v5::properties{},
3185  [life_keeper = force_move(sp_topic_filter), func = force_move(func)]
3186  (error_code ec) {
3187  if(func) func(ec);
3188  }
3189  );
3190  }
3191 
3205  packet_id_t packet_id,
3206  as::const_buffer topic_filter,
3207  async_handler_t func
3208  ) {
3209  MQTT_LOG("mqtt_api", info)
3210  << MQTT_ADD_VALUE(address, this)
3211  << "async_unsubscribe"
3212  << " pid:" << packet_id
3213  << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter));
3214 
3215  async_send_unsubscribe(std::vector<as::const_buffer>{ topic_filter }, packet_id, v5::properties{}, force_move(func));
3216  }
3217 
3230  packet_id_t packet_id,
3231  buffer topic_filter,
3232  async_handler_t func = {}
3233  ) {
3234  MQTT_LOG("mqtt_api", info)
3235  << MQTT_ADD_VALUE(address, this)
3236  << "async_unsubscribe"
3237  << " pid:" << packet_id
3238  << " topic:" << topic_filter;
3239 
3240  auto topic_filter_buf = as::buffer(topic_filter);
3241  async_send_unsubscribe(std::vector<as::const_buffer>{ topic_filter_buf },
3242  packet_id,
3243  v5::properties{},
3244  [life_keeper = force_move(topic_filter), func = force_move(func)]
3245  (error_code ec) {
3246  if(func) func(ec);
3247  });
3248  }
3249 
3266  packet_id_t packet_id,
3267  buffer topic_filter,
3268  v5::properties props,
3269  async_handler_t func = {}
3270  ) {
3271  MQTT_LOG("mqtt_api", info)
3272  << MQTT_ADD_VALUE(address, this)
3273  << "async_unsubscribe"
3274  << " pid:" << packet_id
3275  << " topic:" << topic_filter;
3276 
3277  auto topic_filter_buf = as::buffer(topic_filter);
3278  async_send_unsubscribe(std::vector<as::const_buffer>{ topic_filter_buf },
3279  packet_id,
3280  force_move(props),
3281  [life_keeper = force_move(topic_filter), func = force_move(func)]
3282  (error_code ec) {
3283  if(func) func(ec);
3284  });
3285  }
3286 
3300  packet_id_t packet_id,
3301  std::vector<std::string> params,
3302  async_handler_t func = {}
3303  ) {
3304  MQTT_LOG("mqtt_api", info)
3305  << MQTT_ADD_VALUE(address, this)
3306  << "async_unsubscribe"
3307  << " pid:" << packet_id;
3308 
3309  std::vector<as::const_buffer> cb_params;
3310  cb_params.reserve(params.size());
3311 
3312  std::vector<std::shared_ptr<std::string>> life_keepers;
3313  life_keepers.reserve(params.size());
3314 
3315  for (auto&& e : params) {
3316  life_keepers.emplace_back(std::make_shared<std::string>(force_move(e)));
3317  cb_params.emplace_back(as::buffer(*life_keepers.back()));
3318  }
3319 
3320  async_send_unsubscribe(
3321  force_move(cb_params),
3322  packet_id,
3323  v5::properties{},
3324  [life_keeper = force_move(life_keepers), func = force_move(func)]
3325  (error_code ec) {
3326  if(func) func(ec);
3327  }
3328  );
3329  }
3330 
3348  packet_id_t packet_id,
3349  std::vector<std::string> params,
3350  v5::properties props,
3351  async_handler_t func = {}
3352  ) {
3353  MQTT_LOG("mqtt_api", info)
3354  << MQTT_ADD_VALUE(address, this)
3355  << "async_unsubscribe"
3356  << " pid:" << packet_id;
3357 
3358  std::vector<as::const_buffer> cb_params;
3359  cb_params.reserve(params.size());
3360 
3361  // TOOD: Theoretically, std::vector's storage remains stationary
3362  // as long as it's never copied...
3363  // Perhaps a wrapper that disables copies, and forces move only?
3364  // that would allow us to avoid the std::shared_ptr<std::string> vector.
3365  // TODO: Does vector do short-buffer-optimization? If so, this is an invalid idea.
3366  std::vector<std::shared_ptr<std::string>> life_keepers;
3367  life_keepers.reserve(params.size());
3368 
3369  for (auto&& e : params) {
3370  life_keepers.emplace_back(std::make_shared<std::string>(force_move(e)));
3371  cb_params.emplace_back(as::buffer(*life_keepers.back()));
3372  }
3373 
3374  async_send_unsubscribe(
3375  force_move(cb_params),
3376  packet_id,
3377  force_move(props),
3378  [life_keeper = force_move(life_keepers), func = force_move(func)]
3379  (error_code ec) {
3380  if(func) func(ec);
3381  }
3382  );
3383  }
3384 
3399  packet_id_t packet_id,
3400  std::vector<as::const_buffer> params,
3401  async_handler_t func
3402  ) {
3403  MQTT_LOG("mqtt_api", info)
3404  << MQTT_ADD_VALUE(address, this)
3405  << "async_unsubscribe"
3406  << " pid:" << packet_id;
3407 
3408  async_send_unsubscribe(
3409  force_move(params),
3410  packet_id,
3411  v5::properties{},
3412  force_move(func)
3413  );
3414  }
3415 
3434  packet_id_t packet_id,
3435  std::vector<as::const_buffer> params,
3436  v5::properties props,
3437  async_handler_t func
3438  ) {
3439  MQTT_LOG("mqtt_api", info)
3440  << MQTT_ADD_VALUE(address, this)
3441  << "async_unsubscribe"
3442  << " pid:" << packet_id;
3443 
3444  async_send_unsubscribe(
3445  force_move(params),
3446  packet_id,
3447  force_move(props),
3448  force_move(func)
3449  );
3450  }
3451 
3465  packet_id_t packet_id,
3466  std::vector<buffer> params,
3467  async_handler_t func = {}
3468  ) {
3469  MQTT_LOG("mqtt_api", info)
3470  << MQTT_ADD_VALUE(address, this)
3471  << "async_unsubscribe"
3472  << " pid:" << packet_id;
3473 
3474  std::vector<as::const_buffer> cb_params;
3475  cb_params.reserve(params.size());
3476  for (auto const& buf : params) {
3477  cb_params.emplace_back(as::buffer(buf));
3478  }
3479 
3480  async_send_unsubscribe(
3481  force_move(cb_params),
3482  packet_id,
3483  v5::properties{},
3484  [life_keeper = force_move(params), func = force_move(func)]
3485  (error_code ec) {
3486  if(func) func(ec);
3487  }
3488  );
3489  }
3490 
3508  packet_id_t packet_id,
3509  std::vector<buffer> params,
3510  v5::properties props,
3511  async_handler_t func = {}
3512  ) {
3513  MQTT_LOG("mqtt_api", info)
3514  << MQTT_ADD_VALUE(address, this)
3515  << "async_unsubscribe"
3516  << " pid:" << packet_id;
3517 
3518  std::vector<as::const_buffer> cb_params;
3519  cb_params.reserve(params.size());
3520  for (auto const& buf : params) {
3521  cb_params.emplace_back(as::buffer(buf));
3522  }
3523 
3524  async_send_unsubscribe(
3525  force_move(cb_params),
3526  packet_id,
3527  force_move(props),
3528  [life_keeper = force_move(params), func = force_move(func)]
3529  (error_code ec) {
3530  if(func) func(ec);
3531  }
3532  );
3533  }
3534 
3541  void async_pingreq(async_handler_t func = {}) {
3542  MQTT_LOG("mqtt_api", trace)
3543  << MQTT_ADD_VALUE(address, this)
3544  << "async_pingreq";
3545 
3546  if (connected_ && mqtt_connected_) async_send_pingreq(force_move(func));
3547  }
3548 
3556  MQTT_LOG("mqtt_api", trace)
3557  << MQTT_ADD_VALUE(address, this)
3558  << "async_pingrsp";
3559 
3560  async_send_pingresp(force_move(func));
3561  }
3562 
3579  v5::properties props = {},
3580  async_handler_t func = {}
3581  ) {
3582  MQTT_LOG("mqtt_api", info)
3583  << MQTT_ADD_VALUE(address, this)
3584  << "async_auth"
3585  << " reason:" << reason_code;
3586 
3587  async_send_auth(reason_code, force_move(props), force_move(func));
3588  }
3589 
3614  buffer client_id,
3615  optional<buffer> user_name,
3616  optional<buffer> password,
3617  optional<will> w,
3618  std::uint16_t keep_alive_sec,
3619  async_handler_t func = {}
3620  ) {
3621  async_connect(
3622  force_move(client_id),
3623  force_move(user_name),
3624  force_move(password),
3625  force_move(w),
3626  keep_alive_sec,
3627  v5::properties{},
3628  force_move(func));
3629  }
3630 
3659  buffer client_id,
3660  optional<buffer> user_name,
3661  optional<buffer> password,
3662  optional<will> w,
3663  std::uint16_t keep_alive_sec,
3664  v5::properties props,
3665  async_handler_t func = {}
3666  ) {
3667  MQTT_LOG("mqtt_api", info)
3668  << MQTT_ADD_VALUE(address, this)
3669  << "async_connect"
3670  << " client_id:" << client_id
3671  << " user_name:" << (user_name ? string_view(user_name.value()) : string_view("none"))
3672  << " keep_alive:" << std::dec << keep_alive_sec;
3673 
3674  connect_requested_ = true;
3675  async_send_connect(
3676  force_move(client_id),
3677  force_move(user_name),
3678  force_move(password),
3679  force_move(w),
3680  keep_alive_sec,
3681  force_move(props),
3682  force_move(func));
3683  }
3684 
3694  bool session_present,
3695  variant<connect_return_code, v5::connect_reason_code> reason_code,
3696  async_handler_t func = {}
3697  ) {
3698  MQTT_LOG("mqtt_api", info)
3699  << MQTT_ADD_VALUE(address, this)
3700  << "async_connack"
3701  << " session_present:" << std::boolalpha << session_present
3702  << " reason:" << reason_code;
3703 
3704  async_send_connack(session_present, force_move(reason_code), v5::properties{}, force_move(func));
3705  }
3706 
3720  bool session_present,
3721  variant<connect_return_code, v5::connect_reason_code> reason_code,
3722  v5::properties props,
3723  async_handler_t func = {}
3724  ) {
3725  MQTT_LOG("mqtt_api", info)
3726  << MQTT_ADD_VALUE(address, this)
3727  << "async_connack"
3728  << " session_present:" << std::boolalpha << session_present
3729  << " reason:" << reason_code;
3730 
3731  async_send_connack(session_present, force_move(reason_code), force_move(props), force_move(func));
3732  }
3733 
3742  packet_id_t packet_id,
3743  async_handler_t func = {}
3744  ) {
3745  MQTT_LOG("mqtt_api", info)
3746  << MQTT_ADD_VALUE(address, this)
3747  << "async_puback"
3748  << " pid:" << packet_id;
3749 
3750  async_send_puback(packet_id, v5::puback_reason_code::success, v5::properties{}, force_move(func));
3751  }
3752 
3769  packet_id_t packet_id,
3770  v5::puback_reason_code reason_code,
3771  v5::properties props,
3772  async_handler_t func = {}
3773  ) {
3774  MQTT_LOG("mqtt_api", info)
3775  << MQTT_ADD_VALUE(address, this)
3776  << "async_puback"
3777  << " pid:" << packet_id
3778  << " reason:" << reason_code;
3779 
3780  async_send_puback(packet_id, reason_code, force_move(props), force_move(func));
3781  }
3782 
3791  packet_id_t packet_id,
3792  async_handler_t func = {}
3793  ) {
3794  MQTT_LOG("mqtt_api", info)
3795  << MQTT_ADD_VALUE(address, this)
3796  << "async_pubrec"
3797  << " pid:" << packet_id;
3798 
3799  async_send_pubrec(packet_id, v5::pubrec_reason_code::success, v5::properties{}, force_move(func));
3800  }
3801 
3818  packet_id_t packet_id,
3819  v5::pubrec_reason_code reason_code,
3820  v5::properties props,
3821  async_handler_t func = {}
3822  ) {
3823  MQTT_LOG("mqtt_api", info)
3824  << MQTT_ADD_VALUE(address, this)
3825  << "async_pubrec"
3826  << " pid:" << packet_id
3827  << " reason:" << reason_code;
3828 
3829  async_send_pubrec(packet_id, reason_code, force_move(props), force_move(func));
3830  }
3831 
3840  packet_id_t packet_id,
3841  async_handler_t func = {}
3842  ) {
3843  MQTT_LOG("mqtt_api", info)
3844  << MQTT_ADD_VALUE(address, this)
3845  << "async_pubrel"
3846  << " pid:" << packet_id;
3847 
3848  async_send_pubrel(packet_id, v5::pubrel_reason_code::success, v5::properties{}, any(), force_move(func));
3849  }
3850 
3875  packet_id_t packet_id,
3876  v5::pubrel_reason_code reason_code,
3877  v5::properties props = {},
3878  any life_keeper = {},
3879  async_handler_t func = {}
3880  ) {
3881  MQTT_LOG("mqtt_api", info)
3882  << MQTT_ADD_VALUE(address, this)
3883  << "async_pubrel"
3884  << " pid:" << packet_id
3885  << " reason:" << reason_code;
3886 
3887  async_send_pubrel(packet_id, reason_code, force_move(props), force_move(life_keeper), force_move(func));
3888  }
3889 
3898  packet_id_t packet_id,
3899  async_handler_t func = {}
3900  ) {
3901  MQTT_LOG("mqtt_api", info)
3902  << MQTT_ADD_VALUE(address, this)
3903  << "async_pubcomp"
3904  << " pid:" << packet_id;
3905 
3906  async_send_pubcomp(packet_id, v5::pubcomp_reason_code::success, v5::properties{}, force_move(func));
3907  }
3908 
3925  packet_id_t packet_id,
3926  v5::pubcomp_reason_code reason_code,
3927  v5::properties props,
3928  async_handler_t func = {}
3929  ) {
3930  MQTT_LOG("mqtt_api", info)
3931  << MQTT_ADD_VALUE(address, this)
3932  << "async_pubcomp"
3933  << " pid:" << packet_id
3934  << " reason:" << reason_code;
3935 
3936  async_send_pubcomp(packet_id, reason_code, force_move(props), force_move(func));
3937  }
3938 
3951  packet_id_t packet_id,
3952  variant<suback_return_code, v5::suback_reason_code> reason,
3953  async_handler_t func = {}
3954  ) {
3955  MQTT_LOG("mqtt_api", info)
3956  << MQTT_ADD_VALUE(address, this)
3957  << "async_suback"
3958  << " pid:" << packet_id
3959  << " reason:" < reason;
3960 
3961  if (variant_idx(reason) == 0) {
3962  async_send_suback(std::vector<suback_return_code>{ variant_get<suback_return_code>(reason) }, packet_id, v5::properties{}, force_move(func));
3963  }
3964  else {
3965  async_send_suback(std::vector<v5::suback_reason_code>{ variant_get<v5::suback_reason_code>(reason) }, packet_id, v5::properties{}, force_move(func));
3966  }
3967  }
3968 
3985  packet_id_t packet_id,
3986  variant<suback_return_code, v5::suback_reason_code> reason,
3987  v5::properties props,
3988  async_handler_t func = {}
3989  ) {
3990  MQTT_LOG("mqtt_api", info)
3991  << MQTT_ADD_VALUE(address, this)
3992  << "async_suback"
3993  << " pid:" << packet_id
3994  << " reason:" < reason;
3995 
3996  if (variant_idx(reason) == 0) {
3997  async_send_suback(std::vector<suback_return_code>{ variant_get<suback_return_code>(reason) }, packet_id, force_move(props), force_move(func));
3998  }
3999  else {
4000  async_send_suback(std::vector<v5::suback_reason_code>{ variant_get<v5::suback_reason_code>(reason) }, packet_id, force_move(props), force_move(func));
4001  }
4002  }
4003 
4016  packet_id_t packet_id,
4017  variant<std::vector<suback_return_code>, std::vector<v5::suback_reason_code>> reasons,
4018  async_handler_t func = {}
4019  ) {
4020  MQTT_LOG("mqtt_api", info)
4021  << MQTT_ADD_VALUE(address, this)
4022  << "async_suback"
4023  << " pid:" << packet_id;
4024 
4025  async_send_suback(force_move(reasons), packet_id, v5::properties{}, force_move(func));
4026  }
4027 
4044  packet_id_t packet_id,
4045  variant<std::vector<suback_return_code>, std::vector<v5::suback_reason_code>> reasons,
4046  v5::properties props,
4047  async_handler_t func = {}
4048  ) {
4049  MQTT_LOG("mqtt_api", info)
4050  << MQTT_ADD_VALUE(address, this)
4051  << "async_suback"
4052  << " pid:" << packet_id;
4053 
4054  async_send_suback(force_move(reasons), packet_id, force_move(props), force_move(func));
4055  }
4056 
4069  packet_id_t packet_id,
4070  v5::unsuback_reason_code reason,
4071  async_handler_t func = {}
4072  ) {
4073  MQTT_LOG("mqtt_api", info)
4074  << MQTT_ADD_VALUE(address, this)
4075  << "async_unsuback"
4076  << " pid:" << packet_id
4077  << " reason:" < reason;
4078 
4079  async_send_unsuback(std::vector<v5::unsuback_reason_code>{ reason }, packet_id, force_move(func));
4080  }
4081 
4098  packet_id_t packet_id,
4099  v5::unsuback_reason_code reason,
4100  v5::properties props,
4101  async_handler_t func = {}
4102  ) {
4103  MQTT_LOG("mqtt_api", info)
4104  << MQTT_ADD_VALUE(address, this)
4105  << "async_unsuback"
4106  << " pid:" << packet_id
4107  << " reason:" < reason;
4108 
4109  async_send_unsuback(std::vector<v5::unsuback_reason_code>{ reason }, packet_id, force_move(props), force_move(func));
4110  }
4111 
4124  packet_id_t packet_id,
4125  std::vector<v5::unsuback_reason_code> reasons,
4126  async_handler_t func = {}
4127  ) {
4128  MQTT_LOG("mqtt_api", info)
4129  << MQTT_ADD_VALUE(address, this)
4130  << "async_unsuback"
4131  << " pid:" << packet_id;
4132 
4133  async_send_unsuback(force_move(reasons), packet_id, v5::properties{}, force_move(func));
4134  }
4135 
4152  packet_id_t packet_id,
4153  std::vector<v5::unsuback_reason_code> reasons,
4154  v5::properties props,
4155  async_handler_t func = {}
4156  ) {
4157  MQTT_LOG("mqtt_api", info)
4158  << MQTT_ADD_VALUE(address, this)
4159  << "async_unsuback"
4160  << " pid:" << packet_id;
4161 
4162  async_send_unsuback(force_move(reasons), packet_id, force_move(props), force_move(func));
4163  }
4164 
4174  packet_id_t packet_id,
4175  async_handler_t func = {}
4176  ) {
4177  MQTT_LOG("mqtt_api", info)
4178  << MQTT_ADD_VALUE(address, this)
4179  << "async_unsuback"
4180  << " pid:" << packet_id;
4181 
4182  async_send_unsuback(packet_id, force_move(func));
4183  }
4184 
4190  LockGuard<Mutex> lck (store_mtx_);
4191  auto& idx = store_.template get<tag_packet_id>();
4192  auto r = idx.equal_range(packet_id);
4193  idx.erase(std::get<0>(r), std::get<1>(r));
4194  pid_man_.release_id(packet_id);
4195  }
4196 
4201  void for_each_store(std::function<void(char const*, std::size_t)> const& f) {
4202  MQTT_LOG("mqtt_api", info)
4203  << MQTT_ADD_VALUE(address, this)
4204  << "for_each_store(ptr, size)";
4205  LockGuard<Mutex> lck (store_mtx_);
4206  auto const& idx = store_.template get<tag_seq>();
4207  for (auto const & e : idx) {
4208  auto const& m = e.message();
4209  auto cb = continuous_buffer(m);
4210  f(cb.data(), cb.size());
4211  }
4212  }
4213 
4218  void for_each_store(std::function<void(basic_store_message_variant<PacketIdBytes>)> const& f) {
4219  MQTT_LOG("mqtt_api", info)
4220  << MQTT_ADD_VALUE(address, this)
4221  << "for_each_store(store_message_variant)";
4222  LockGuard<Mutex> lck (store_mtx_);
4223  auto const& idx = store_.template get<tag_seq>();
4224  for (auto const & e : idx) {
4225  f(e.message());
4226  }
4227  }
4228 
4234  MQTT_LOG("mqtt_api", info)
4235  << MQTT_ADD_VALUE(address, this)
4236 
4237  << "for_each_store(store_message_variant, life_keeper)";
4238  LockGuard<Mutex> lck (store_mtx_);
4239  auto const& idx = store_.template get<tag_seq>();
4240  for (auto const & e : idx) {
4241  f(e.message(), e.life_keeper());
4242  }
4243  }
4244 
4245  // manual packet_id management for advanced users
4246 
4256  if (auto pid = acquire_unique_packet_id_no_except()) return pid.value();
4257  throw packet_id_exhausted_error();
4258  }
4259 
4268  optional<packet_id_t> acquire_unique_packet_id_no_except() {
4269  LockGuard<Mutex> lck (store_mtx_);
4270  return pid_man_.acquire_unique_id();
4271  }
4272 
4281  LockGuard<Mutex> lck (store_mtx_);
4282  return pid_man_.register_id(packet_id);
4283  }
4284 
4291  void release_packet_id(packet_id_t packet_id) {
4292  LockGuard<Mutex> lck (store_mtx_);
4293  pid_man_.release_id(packet_id);
4294  }
4295 
4302  template <typename Iterator>
4303  std::enable_if_t< std::is_convertible<typename Iterator::value_type, char>::value >
4304  restore_serialized_message(Iterator b, Iterator e) {
4305  static_assert(
4306  std::is_same<
4307  typename std::iterator_traits<Iterator>::iterator_category,
4308  std::random_access_iterator_tag
4309  >::value,
4310  "Iterators provided to restore_serialized_message() must be random access iterators."
4311  );
4312 
4313  MQTT_LOG("mqtt_api", info)
4314  << MQTT_ADD_VALUE(address, this)
4315  << "restore_serialized_message(b, e)";
4316 
4317  if (b == e) return;
4318 
4319  auto fixed_header = static_cast<std::uint8_t>(*b);
4320  auto cpt_opt = get_control_packet_type_with_check(fixed_header);
4321  if (!cpt_opt) {
4322  MQTT_LOG("mqtt_api", error)
4323  << MQTT_ADD_VALUE(address, this)
4324  << "invalid fixed_header ignored. "
4325  << std::hex << static_cast<int>(fixed_header);
4326  throw malformed_packet_error();
4327  }
4328  switch (cpt_opt.value()) {
4330  auto buf = allocate_buffer(b, e);
4333  buf
4334  ),
4335  buf
4336  );
4337  } break;
4341  // basic_pubrel_message have no member variable that type is buffer.
4342  // When creating basic_pubrel_message, the constructor just read buffer
4343  // and convert to some values.
4344  // So the argument buffer(...) doesn't need to hold the lifetime.
4345  buffer(string_view(&*b, static_cast<std::size_t>(std::distance(b, e))))
4346  )
4347  );
4348  } break;
4349  default:
4350  MQTT_LOG("mqtt_api", error)
4351  << MQTT_ADD_VALUE(address, this)
4352  << "invalid control packet type. "
4353  << std::hex << static_cast<int>(fixed_header);
4354  throw protocol_error();
4355  break;
4356  }
4357  }
4358 
4367  auto packet_id = msg.packet_id();
4368  qos qos_value = msg.get_qos();
4369  LockGuard<Mutex> lck (store_mtx_);
4370  if (pid_man_.register_id(packet_id)) {
4371  auto ret = store_.emplace(
4372  packet_id,
4375  force_move(msg),
4376  force_move(life_keeper)
4377  );
4378  // When client want to restore serialized messages,
4379  // endpoint might keep the message that has the same packet_id.
4380  // In this case, overwrite store_.
4381  if (!ret.second) {
4382  store_.modify(
4383  ret.first,
4384  [&] (auto& e) {
4385  e = store(
4386  packet_id,
4387  ((qos_value == qos::at_least_once) ? control_packet_type::puback
4388  : control_packet_type::pubrec),
4389  force_move(msg),
4390  force_move(life_keeper)
4391  );
4392  }
4393  );
4394  }
4395  }
4396  }
4397 
4404  auto packet_id = msg.packet_id();
4405  LockGuard<Mutex> lck (store_mtx_);
4406  if (pid_man_.register_id(packet_id)) {
4407  auto ret = store_.emplace(
4408  packet_id,
4410  force_move(msg),
4411  force_move(life_keeper)
4412  );
4413  // When client want to restore serialized messages,
4414  // endpoint might keep the message that has the same packet_id.
4415  // In this case, overwrite store_.
4416  if (!ret.second) {
4417  store_.modify(
4418  ret.first,
4419  [&] (auto& e) {
4420  e = store(
4421  packet_id,
4422  control_packet_type::pubcomp,
4423  force_move(msg),
4424  force_move(life_keeper)
4425  );
4426  }
4427  );
4428  }
4429  }
4430  }
4431 
4439  template <typename Iterator>
4440  std::enable_if_t< std::is_convertible<typename Iterator::value_type, char>::value >
4441  restore_v5_serialized_message(Iterator b, Iterator e) {
4442  if (b == e) return;
4443 
4444  auto fixed_header = static_cast<std::uint8_t>(*b);
4445  auto cpt_opt = get_control_packet_type_with_check(fixed_header);
4446  if (!cpt_opt) {
4447  MQTT_LOG("mqtt_api", error)
4448  << MQTT_ADD_VALUE(address, this)
4449  << "invalid fixed_header ignored. "
4450  << std::hex << static_cast<int>(fixed_header);
4451  throw malformed_packet_error();
4452  }
4453  switch (cpt_opt.value()) {
4455  auto buf = allocate_buffer(b, e);
4458  buf
4459  );
4460  } break;
4462  auto buf = allocate_buffer(b, e);
4465  buf
4466  );
4467  } break;
4468  default:
4469  MQTT_LOG("mqtt_api", error)
4470  << MQTT_ADD_VALUE(address, this)
4471  << "invalid control packet type. "
4472  << std::hex << static_cast<int>(fixed_header);
4473  throw protocol_error();
4474  break;
4475  }
4476  }
4477 
4486  BOOST_ASSERT(!msg.topic().empty());
4487  auto packet_id = msg.packet_id();
4488  auto qos = msg.get_qos();
4489  LockGuard<Mutex> lck (store_mtx_);
4490  if (pid_man_.register_id(packet_id)) {
4491  auto ret = store_.emplace(
4492  packet_id,
4495  force_move(msg),
4496  force_move(life_keeper)
4497  );
4498  // When client want to restore serialized messages,
4499  // endpoint might keep the message that has the same packet_id.
4500  // In this case, overwrite store_.
4501  if (!ret.second) {
4502  store_.modify(
4503  ret.first,
4504  [&] (auto& e) {
4505  e = store(
4506  packet_id,
4507  qos == qos::at_least_once ? control_packet_type::puback
4508  : control_packet_type::pubrec,
4509  force_move(msg),
4510  force_move(life_keeper)
4511  );
4512  }
4513  );
4514  }
4515  }
4516  }
4517 
4526  auto packet_id = msg.packet_id();
4527  LockGuard<Mutex> lck (store_mtx_);
4528  if (pid_man_.register_id(packet_id)) {
4529  auto ret = store_.emplace(
4530  packet_id,
4532  force_move(msg),
4533  force_move(life_keeper)
4534  );
4535  // When client want to restore serialized messages,
4536  // endpoint might keep the message that has the same packet_id.
4537  // In this case, overwrite store_.
4538  if (!ret.second) {
4539  store_.modify(
4540  ret.first,
4541  [&] (auto& e) {
4542  e = store(
4543  packet_id,
4544  control_packet_type::pubcomp,
4545  force_move(msg)
4546  );
4547  }
4548  );
4549  }
4550  }
4551  }
4552 
4553 private:
4554  struct restore_basic_message_variant_visitor {
4555  restore_basic_message_variant_visitor(this_type& ep, any life_keeper):ep_(ep), life_keeper_(force_move(life_keeper)) {}
4556 
4557  void operator()(basic_publish_message<PacketIdBytes>&& msg) {
4558  ep_.restore_serialized_message(force_move(msg), force_move(life_keeper_));
4559  }
4560  void operator()(basic_pubrel_message<PacketIdBytes>&& msg) {
4561  ep_.restore_serialized_message(force_move(msg), force_move(life_keeper_));
4562  }
4563  void operator()(v5::basic_publish_message<PacketIdBytes>&& msg) {
4564  ep_.restore_v5_serialized_message(force_move(msg), force_move(life_keeper_));
4565  }
4566  void operator()(v5::basic_pubrel_message<PacketIdBytes>&& msg) {
4567  ep_.restore_v5_serialized_message(force_move(msg), force_move(life_keeper_));
4568  }
4569  template <typename T>
4570  void operator()(T&&) const {
4571  throw restore_type_error();
4572  }
4573  private:
4574  this_type& ep_;
4575  any life_keeper_;
4576  };
4577 
4578 public:
4580  MQTT_NS::visit(restore_basic_message_variant_visitor(*this, force_move(life_keeper)), force_move(msg));
4581  }
4582 
4583 
4585  auto publish_proc =
4586  [&](auto msg, auto const& serialize) {
4587  preprocess_publish_message(
4588  msg,
4589  life_keeper,
4590  serialize,
4591  true // register packet_id
4592  );
4593  do_sync_write(force_move(msg));
4594  };
4595 
4596  auto pubrel_proc =
4597  [&](auto msg, auto const& serialize) {
4598  auto packet_id = msg.packet_id();
4599 
4600  LockGuard<Mutex> lck (store_mtx_);
4601  pid_man_.register_id(packet_id);
4602  auto ret = store_.emplace(
4603  packet_id,
4605  msg,
4606  force_move(life_keeper)
4607  );
4608  (void)ret;
4609  BOOST_ASSERT(ret.second);
4610  (this->*serialize)(msg);
4611  do_sync_write(force_move(msg));
4612  };
4613 
4616  [this, &publish_proc](v3_1_1::basic_publish_message<PacketIdBytes>& m) {
4617  MQTT_LOG("mqtt_api", info)
4618  << MQTT_ADD_VALUE(address, this)
4619  << "send_store_message publish v3.1.1";
4620  publish_proc(force_move(m), &endpoint::on_serialize_publish_message);
4621  },
4622  [this, &pubrel_proc](v3_1_1::basic_pubrel_message<PacketIdBytes>& m) {
4623  MQTT_LOG("mqtt_api", info)
4624  << MQTT_ADD_VALUE(address, this)
4625  << "send_store_message pubrel v3.1.1";
4626  pubrel_proc(force_move(m), &endpoint::on_serialize_pubrel_message);
4627  },
4628  [this, &publish_proc](v5::basic_publish_message<PacketIdBytes>& m) {
4629  MQTT_LOG("mqtt_api", info)
4630  << MQTT_ADD_VALUE(address, this)
4631  << "send_store_message publish v5";
4632  publish_proc(force_move(m), &endpoint::on_serialize_v5_publish_message);
4633  },
4634  [this, &pubrel_proc](v5::basic_pubrel_message<PacketIdBytes>& m) {
4635  MQTT_LOG("mqtt_api", info)
4636  << MQTT_ADD_VALUE(address, this)
4637  << "send_store_message pubrel v5";
4638  pubrel_proc(force_move(m), &endpoint::on_serialize_v5_pubrel_message);
4639  }
4640  ),
4641  msg
4642  );
4643  }
4644 
4646  auto publish_proc =
4647  [&](auto msg, auto const& serialize) {
4648  preprocess_publish_message(
4649  msg,
4650  life_keeper,
4651  serialize,
4652  true // register packet_id
4653  );
4654  do_async_write(force_move(msg), force_move(func));
4655  };
4656 
4657  auto pubrel_proc =
4658  [&](auto msg, auto const& serialize) {
4659  auto packet_id = msg.packet_id();
4660 
4661  LockGuard<Mutex> lck (store_mtx_);
4662  pid_man_.register_id(packet_id);
4663  auto ret = store_.emplace(
4664  packet_id,
4666  msg,
4667  force_move(life_keeper)
4668  );
4669  (void)ret;
4670  BOOST_ASSERT(ret.second);
4671  (this->*serialize)(msg);
4672  do_async_write(force_move(msg), force_move(func));
4673  };
4674 
4677  [this, &publish_proc](v3_1_1::basic_publish_message<PacketIdBytes>& m) {
4678  MQTT_LOG("mqtt_api", info)
4679  << MQTT_ADD_VALUE(address, this)
4680  << "async_send_store_message publish v3.1.1";
4681  publish_proc(force_move(m), &endpoint::on_serialize_publish_message);
4682  },
4683  [this, &pubrel_proc](v3_1_1::basic_pubrel_message<PacketIdBytes>& m) {
4684  MQTT_LOG("mqtt_api", info)
4685  << MQTT_ADD_VALUE(address, this)
4686  << "async_send_store_message pubrel v3.1.1";
4687  pubrel_proc(force_move(m), &endpoint::on_serialize_pubrel_message);
4688  },
4689  [this, &publish_proc](v5::basic_publish_message<PacketIdBytes>& m) {
4690  MQTT_LOG("mqtt_api", info)
4691  << MQTT_ADD_VALUE(address, this)
4692  << "async_send_store_message publish v5";
4693  publish_proc(force_move(m), &endpoint::on_serialize_v5_publish_message);
4694  },
4695  [this, &pubrel_proc](v5::basic_pubrel_message<PacketIdBytes>& m) {
4696  MQTT_LOG("mqtt_api", info)
4697  << MQTT_ADD_VALUE(address, this)
4698  << "async_send_store_message pubrel v5";
4699  pubrel_proc(force_move(m), &endpoint::on_serialize_v5_pubrel_message);
4700  }
4701  ),
4702  msg
4703  );
4704  }
4705 
4710  bool connected() const {
4711  return connected_ && mqtt_connected_;
4712  }
4713 
4718  bool underlying_connected() const {
4719  return connected_;
4720  }
4721 
4727  void async_read_next_message(any session_life_keeper) {
4728  async_read_control_packet_type(force_move(session_life_keeper));
4729  }
4730 
4743  void set_max_queue_send_count(std::size_t count) {
4744  max_queue_send_count_ = count;
4745  }
4746 
4759  void set_max_queue_send_size(std::size_t size) {
4760  max_queue_send_size_ = size;
4761  }
4762 
4764  return version_;
4765  }
4766 
4767  MQTT_NS::socket const& socket() const {
4768  return *socket_;
4769  }
4770 
4772  return *socket_;
4773  }
4774 
4775  auto get_executor() {
4776  return socket_->get_executor();
4777  }
4778 
4789  void set_pingresp_timeout(std::chrono::steady_clock::duration tim) {
4790  pingresp_timeout_ = force_move(tim);
4791  }
4792 
4793 protected:
4794 
4799  std::shared_ptr<MQTT_NS::socket>& socket_sp_ref() {
4800  return socket_;
4801  }
4802 
4803  void async_read_control_packet_type(any session_life_keeper) {
4804  socket_->async_read(
4805  as::buffer(buf_.data(), 1),
4806  [this, self = this->shared_from_this(), session_life_keeper = force_move(session_life_keeper)](
4807  error_code ec,
4808  std::size_t bytes_transferred) mutable {
4809  this->total_bytes_received_ += bytes_transferred;
4810  if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return;
4811  handle_control_packet_type(force_move(session_life_keeper), force_move(self));
4812  }
4813  );
4814  }
4815 
4817  if (connected_) {
4818  if (!ec) return false;
4819  connected_ = false;
4820  mqtt_connected_ = false;
4821  {
4822  boost::system::error_code ignored_ec;
4823  socket_->close(ignored_ec);
4824  }
4825  }
4826  {
4827  LockGuard<Mutex> lck (topic_alias_send_mtx_);
4828  if (topic_alias_send_) topic_alias_send_.value().clear();
4829  }
4830  {
4831  LockGuard<Mutex> lck (topic_alias_recv_mtx_);
4832  if (topic_alias_recv_) topic_alias_recv_.value().clear();
4833  }
4834  if (disconnect_requested_) {
4835  disconnect_requested_ = false;
4836  connect_requested_ = false;
4837  clean_sub_unsub_inflight();
4838  on_close();
4839  return true;
4840  }
4841  disconnect_requested_ = false;
4842  connect_requested_ = false;
4843  if (!ec) ec = boost::system::errc::make_error_code(boost::system::errc::not_connected);
4844  clean_sub_unsub_inflight_on_error(ec);
4845  return true;
4846  }
4847 
4848  void set_connect() {
4849  connected_ = true;
4850  }
4851 
4853  version_ = version;
4854  }
4855 
4857  LockGuard<Mutex> lck (store_mtx_);
4858  store_.clear();
4859  pid_man_.clear();
4860  }
4861 
4862 private:
4863  bool check_transferred_length(
4864  std::size_t bytes_transferred,
4865  std::size_t bytes_expected) {
4866  if (bytes_transferred != bytes_expected) {
4867  call_bad_message_error_handlers();
4868  return false;
4869  }
4870  return true;
4871  }
4872 
4873  bool check_error_and_transferred_length(
4874  error_code ec,
4875  std::size_t bytes_transferred,
4876  std::size_t bytes_expected) {
4877  if (handle_close_or_error(ec)) return false;
4878  if (!check_transferred_length(bytes_transferred, bytes_expected)) return false;
4879  return true;
4880  }
4881 
4882  void call_bad_message_error_handlers() {
4883  clean_sub_unsub_inflight_on_error(boost::system::errc::make_error_code(boost::system::errc::bad_message));
4884  }
4885 
4886  void call_protocol_error_handlers() {
4887  clean_sub_unsub_inflight_on_error(boost::system::errc::make_error_code(boost::system::errc::protocol_error));
4888  }
4889 
4890  template <typename T>
4891  void shutdown(T& socket) {
4892  connected_ = false;
4893  mqtt_connected_ = false;
4894 
4896  socket.lowest_layer().close(ec);
4897  }
4898 
4899  class send_buffer {
4900  public:
4901  send_buffer():buf_(std::make_shared<std::string>(static_cast<int>(payload_position_), 0)) {}
4902 
4903  std::shared_ptr<std::string> const& buf() const {
4904  return buf_;
4905  }
4906 
4907  std::shared_ptr<std::string>& buf() {
4908  return buf_;
4909  }
4910 
4911  std::pair<char*, std::size_t> finalize(std::uint8_t fixed_header) {
4912  auto rb = remaining_bytes(buf_->size() - payload_position_);
4913  std::size_t start_position = payload_position_ - rb.size() - 1;
4914  (*buf_)[start_position] = fixed_header;
4915  buf_->replace(start_position + 1, rb.size(), rb);
4916  return std::make_pair(
4917  &(*buf_)[start_position],
4918  buf_->size() - start_position);
4919  }
4920  private:
4921  static constexpr std::size_t payload_position_ = 5;
4922  std::shared_ptr<std::string> buf_;
4923  };
4924 
4925  struct store {
4926  store(
4927  packet_id_t id,
4928  control_packet_type type,
4929  basic_store_message_variant<PacketIdBytes> smv,
4930  any life_keeper = any())
4931  : packet_id_(id)
4932  , expected_control_packet_type_(type)
4933  , smv_(force_move(smv))
4934  , life_keeper_(force_move(life_keeper)) {}
4935  packet_id_t packet_id() const { return packet_id_; }
4936  control_packet_type expected_control_packet_type() const { return expected_control_packet_type_; }
4937  basic_store_message_variant<PacketIdBytes> const& message() const {
4938  return smv_;
4939  }
4940  basic_store_message_variant<PacketIdBytes>& message() {
4941  return smv_;
4942  }
4943  any const& life_keeper() const {
4944  return life_keeper_;
4945  }
4946 
4947  private:
4948  packet_id_t packet_id_;
4949  control_packet_type expected_control_packet_type_;
4950  basic_store_message_variant<PacketIdBytes> smv_;
4951  any life_keeper_;
4952  };
4953 
4954  struct tag_packet_id {};
4955  struct tag_packet_id_type {};
4956  struct tag_seq {};
4957  using mi_store = mi::multi_index_container<
4958  store,
4959  mi::indexed_by<
4960  mi::ordered_unique<
4961  mi::tag<tag_packet_id_type>,
4962  mi::composite_key<
4963  store,
4964  mi::const_mem_fun<
4965  store, packet_id_t,
4966  &store::packet_id
4967  >,
4968  mi::const_mem_fun<
4969  store, control_packet_type,
4970  &store::expected_control_packet_type
4971  >
4972  >
4973  >,
4974  mi::ordered_non_unique<
4975  mi::tag<tag_packet_id>,
4976  mi::const_mem_fun<
4977  store, packet_id_t,
4978  &store::packet_id
4979  >
4980  >,
4981  mi::sequenced<
4982  mi::tag<tag_seq>
4983  >
4984  >
4985  >;
4986 
4987  void handle_control_packet_type(any session_life_keeper, this_type_sp self) {
4988  fixed_header_ = static_cast<std::uint8_t>(buf_.front());
4989  remaining_length_ = 0;
4990  remaining_length_multiplier_ = 1;
4991  socket_->async_read(
4992  as::buffer(buf_.data(), 1),
4993  [this, self = force_move(self), session_life_keeper = force_move(session_life_keeper)] (
4994  error_code ec,
4995  std::size_t bytes_transferred) mutable {
4996  this->total_bytes_received_ += bytes_transferred;
4997  if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return;
4998  handle_remaining_length(force_move(session_life_keeper), force_move(self));
4999  }
5000  );
5001  }
5002 
5003  bool calc_variable_length(std::size_t& v, std::size_t& multiplier, char buf) {
5004  v += (buf & 0b01111111) * multiplier;
5005  multiplier *= 128;
5006  return multiplier <= 128 * 128 * 128 * 128;
5007  }
5008 
5009  void handle_remaining_length(any session_life_keeper, this_type_sp self) {
5010  if (!calc_variable_length(remaining_length_, remaining_length_multiplier_, buf_.front())) {
5011  call_bad_message_error_handlers();
5012  return;
5013  }
5014  if (buf_.front() & variable_length_continue_flag) {
5015  socket_->async_read(
5016  as::buffer(buf_.data(), 1),
5017  [this, self = force_move(self), session_life_keeper = force_move(session_life_keeper)](
5018  error_code ec,
5019  std::size_t bytes_transferred) mutable {
5020  this->total_bytes_received_ += bytes_transferred;
5021  if (handle_close_or_error(ec)) {
5022  return;
5023  }
5024  if (bytes_transferred != 1) {
5025  call_bad_message_error_handlers();
5026  return;
5027  }
5028  handle_remaining_length(force_move(session_life_keeper), force_move(self));
5029  }
5030  );
5031  }
5032  else {
5033  auto cpt_opt = get_control_packet_type_with_check(fixed_header_);
5034  if (!cpt_opt) {
5035  call_bad_message_error_handlers();
5036  return;
5037  }
5038  auto cpt = cpt_opt.value();
5039  auto check =
5040  [&]() -> bool {
5041  switch (version_) {
5043  switch (cpt) {
5049  return check_is_valid_length(cpt, remaining_length_);
5051  return remaining_length_ == 2;
5057  return remaining_length_ == sizeof(packet_id_t);
5061  return remaining_length_ == 0;
5062  // Even though there is no auth packet type in v3.1.1
5063  // it's included in the switch case to provide a warning
5064  // about missing enum values if any are missing.
5066  return false;
5067  }
5068  return false;
5069  case protocol_version::v5:
5070  default:
5071  switch (cpt) {
5085  return check_is_valid_length(cpt, remaining_length_);
5088  return remaining_length_ == 0;
5089  }
5090  return false;
5091  }
5092  };
5093  if (!check()) {
5094  call_protocol_error_handlers();
5095  return;
5096  }
5097 
5098  process_payload(force_move(session_life_keeper), force_move(self));
5099  }
5100  }
5101 
5102  void process_payload(any session_life_keeper, this_type_sp self) {
5103  auto control_packet_type = get_control_packet_type(fixed_header_);
5104  switch (control_packet_type) {
5106  (*std::make_shared<process_connect>(*this, remaining_length_ < packet_bulk_read_limit_))
5107  (force_move(self), force_move(session_life_keeper));
5108  break;
5110  (*std::make_shared<process_connack>(*this, remaining_length_ < packet_bulk_read_limit_))
5111  (force_move(self), force_move(session_life_keeper));
5112  break;
5114  if (mqtt_connected_) {
5115  (*std::make_shared<process_publish>(*this, remaining_length_ < packet_bulk_read_limit_))
5116  (force_move(self), force_move(session_life_keeper));
5117  }
5118  else {
5119  call_protocol_error_handlers();
5120  }
5121  break;
5123  if (mqtt_connected_) {
5124  (*std::make_shared<process_puback>(*this, remaining_length_ < packet_bulk_read_limit_))
5125  (force_move(self), force_move(session_life_keeper));
5126  }
5127  else {
5128  call_protocol_error_handlers();
5129  }
5130  break;
5132  if (mqtt_connected_) {
5133  (*std::make_shared<process_pubrec>(*this, remaining_length_ < packet_bulk_read_limit_))
5134  (force_move(self), force_move(session_life_keeper));
5135  }
5136  else {
5137  call_protocol_error_handlers();
5138  }
5139  break;
5141  if (mqtt_connected_) {
5142  (*std::make_shared<process_pubrel>(*this, remaining_length_ < packet_bulk_read_limit_))
5143  (force_move(self), force_move(session_life_keeper));
5144  }
5145  else {
5146  call_protocol_error_handlers();
5147  }
5148  break;
5150  if (mqtt_connected_) {
5151  (*std::make_shared<process_pubcomp>(*this, remaining_length_ < packet_bulk_read_limit_))
5152  (force_move(self), force_move(session_life_keeper));
5153  }
5154  else {
5155  call_protocol_error_handlers();
5156  }
5157  break;
5159  if (mqtt_connected_) {
5160  (*std::make_shared<process_subscribe>(*this, remaining_length_ < packet_bulk_read_limit_))
5161  (force_move(self), force_move(session_life_keeper));
5162  }
5163  else {
5164  call_protocol_error_handlers();
5165  }
5166  break;
5168  if (mqtt_connected_) {
5169  (*std::make_shared<process_suback>(*this, remaining_length_ < packet_bulk_read_limit_))
5170  (force_move(self), force_move(session_life_keeper));
5171  }
5172  else {
5173  call_protocol_error_handlers();
5174  }
5175  break;
5177  if (mqtt_connected_) {
5178  (*std::make_shared<process_unsubscribe>(*this, remaining_length_ < packet_bulk_read_limit_))
5179  (force_move(self), force_move(session_life_keeper));
5180  }
5181  else {
5182  call_protocol_error_handlers();
5183  }
5184  break;
5186  if (mqtt_connected_) {
5187  (*std::make_shared<process_unsuback>(*this, remaining_length_ < packet_bulk_read_limit_))
5188  (force_move(self), force_move(session_life_keeper));
5189  }
5190  else {
5191  call_protocol_error_handlers();
5192  }
5193  break;
5195  if (mqtt_connected_) {
5196  process_pingreq(force_move(session_life_keeper));
5197  }
5198  else {
5199  call_protocol_error_handlers();
5200  }
5201  break;
5203  if (mqtt_connected_) {
5204  process_pingresp(force_move(session_life_keeper));
5205  }
5206  else {
5207  call_protocol_error_handlers();
5208  }
5209  break;
5211  (*std::make_shared<process_disconnect>(*this, remaining_length_ < packet_bulk_read_limit_))
5212  (force_move(self), force_move(session_life_keeper));
5213  break;
5215  (*std::make_shared<process_auth>(*this, remaining_length_ < packet_bulk_read_limit_))
5216  (force_move(self), force_move(session_life_keeper));
5217  break;
5218  default:
5219  break;
5220  }
5221  }
5222 
5223  using parse_handler_variant =
5224  variant<
5225  std::conditional_t<sizeof(std::size_t) == 4, std::nullptr_t, std::size_t>,
5226  std::uint32_t,
5227  std::uint16_t,
5228  buffer,
5230  >;
5231  using parse_handler =
5232  std::function<
5233  void(
5234  this_type_sp&& spep,
5235  any&& session_life_keeper,
5236  parse_handler_variant,
5237  buffer
5238  )
5239  >;
5240 
5241  // primitive read functions
5242  void process_nbytes(
5243  this_type_sp&& self,
5244  any&& session_life_keeper,
5245  buffer buf,
5246  std::size_t size,
5247  parse_handler&& handler
5248  ) {
5249  if (remaining_length_ < size) {
5250  call_protocol_error_handlers();
5251  return;
5252  }
5253  remaining_length_ -= size;
5254 
5255  if (buf.empty()) {
5256  auto spa = make_shared_ptr_array(size);
5257  auto ptr = spa.get();
5258  socket_->async_read(
5259  as::buffer(ptr, size),
5260  [
5261  this,
5262  self = force_move(self),
5263  session_life_keeper = force_move(session_life_keeper),
5264  handler = force_move(handler),
5265  buf = buffer(string_view(ptr, size), force_move(spa))
5266  ]
5267  (error_code ec,
5268  std::size_t bytes_transferred) mutable {
5269  this->total_bytes_received_ += bytes_transferred;
5270  if (!check_error_and_transferred_length(ec, bytes_transferred, buf.size())) return;
5271  handler(
5272  force_move(self),
5273  force_move(session_life_keeper),
5274  force_move(buf),
5275  buffer()
5276  );
5277  }
5278  );
5279  }
5280  else {
5281  if (buf.size() < size) {
5282  call_protocol_error_handlers();
5283  return;
5284  }
5285  handler(
5286  force_move(self),
5287  force_move(session_life_keeper),
5288  buf.substr(0, size),
5289  buf.substr(size)
5290  );
5291  }
5292  }
5293 
5294  template <std::size_t Bytes>
5295  void process_fixed_length(
5296  this_type_sp&& self,
5297  any&& session_life_keeper,
5298  buffer buf,
5299  parse_handler&& handler
5300  ) {
5301  if (remaining_length_ < Bytes) {
5302  call_protocol_error_handlers();
5303  return;
5304  }
5305 
5306  remaining_length_ -= Bytes;
5307 
5308  if (buf.empty()) {
5309  socket_->async_read(
5310  as::buffer(buf_.data(), Bytes),
5311  [
5312  this,
5313  self = force_move(self),
5314  session_life_keeper = force_move(session_life_keeper),
5315  handler = force_move(handler)
5316  ]
5317  (error_code ec,
5318  std::size_t bytes_transferred) mutable {
5319  this->total_bytes_received_ += bytes_transferred;
5320  if (!check_error_and_transferred_length(ec, bytes_transferred, Bytes)) return;
5321  handler(
5322  force_move(self),
5323  force_move(session_life_keeper),
5324  make_two_or_four_byte<Bytes>::apply(
5325  buf_.data(),
5326  std::next(buf_.data(), boost::numeric_cast<buffer::difference_type>(Bytes))
5327  ),
5328  buffer()
5329  );
5330  }
5331  );
5332  }
5333  else {
5334  auto val =
5335  make_two_or_four_byte<Bytes>::apply(
5336  buf.data(),
5337  std::next(buf.data(), boost::numeric_cast<buffer::difference_type>(Bytes))
5338  );
5339  buf.remove_prefix(Bytes);
5340  handler(
5341  force_move(self),
5342  force_move(session_life_keeper),
5343  val,
5344  force_move(buf)
5345 
5346  );
5347  }
5348  }
5349 
5350  // This function isn't used for remaining lengh.
5351  void process_variable_length(
5352  this_type_sp&& self,
5353  any&& session_life_keeper,
5354  buffer buf,
5355  parse_handler&& handler
5356  ) {
5357  process_variable_length_impl(
5358  force_move(self),
5359  force_move(session_life_keeper),
5360  force_move(buf),
5361  force_move(handler),
5362  0,
5363  1
5364  );
5365  }
5366 
5367  void process_variable_length_impl(
5368  this_type_sp&& self,
5369  any&& session_life_keeper,
5370  buffer buf,
5371  parse_handler&& handler,
5372  std::size_t size,
5373  std::size_t multiplier
5374  ) {
5375  if (remaining_length_ == 0) {
5376  call_protocol_error_handlers();
5377  return;
5378  }
5379  --remaining_length_;
5380 
5381  // I use rvalue reference parameter to reduce move constructor calling.
5382  // This is a local lambda expression invoked from this function, so
5383  // I can control all callers.
5384  auto proc =
5385  [this]
5386  (
5387  this_type_sp&& self,
5388  any&& session_life_keeper,
5389  buffer&& buf,
5390  auto&& handler,
5391  std::size_t size,
5392  std::size_t multiplier
5393  ) mutable {
5394  if (!calc_variable_length(size, multiplier, buf.front())) {
5395  call_protocol_error_handlers();
5396  return;
5397  }
5398  if (buf.front() & variable_length_continue_flag) {
5399  BOOST_ASSERT(!buf.empty());
5400  buf.remove_prefix(1);
5401  process_variable_length_impl(
5402  force_move(self),
5403  force_move(session_life_keeper),
5404  force_move(buf),
5405  std::forward<decltype(handler)>(handler),
5406  size,
5407  multiplier
5408  );
5409  }
5410  else {
5411  buf.remove_prefix(1);
5412  handler(
5413  force_move(self),
5414  force_move(session_life_keeper),
5415  size,
5416  force_move(buf)
5417  );
5418  }
5419  };
5420 
5421  if (buf.empty()) {
5422  socket_->async_read(
5423  as::buffer(buf_.data(), 1),
5424  [
5425  this,
5426  self = force_move(self),
5427  session_life_keeper = force_move(session_life_keeper),
5428  handler = force_move(handler),
5429  size,
5430  multiplier,
5431  proc = force_move(proc)
5432  ]
5433  (error_code ec,
5434  std::size_t bytes_transferred) mutable {
5435  this->total_bytes_received_ += bytes_transferred;
5436  if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return;
5437  proc(
5438  force_move(self),
5439  force_move(session_life_keeper),
5440  buffer(string_view(buf_.data(), 1)), // buf_'s lifetime is handled by `self`
5441  force_move(handler),
5442  size,
5443  multiplier
5444  );
5445  }
5446  );
5447  }
5448  else {
5449  proc(
5450  force_move(self),
5451  force_move(session_life_keeper),
5452  force_move(buf),
5453  force_move(handler),
5454  size,
5455  multiplier
5456  );
5457  }
5458  }
5459 
5460  void process_packet_id(
5461  this_type_sp&& self,
5462  any&& session_life_keeper,
5463  buffer buf,
5464  parse_handler&& handler
5465  ) {
5466  process_fixed_length<sizeof(packet_id_t)>(
5467  force_move(self),
5468  force_move(session_life_keeper),
5469  force_move(buf),
5470  [
5471  this,
5472  handler = force_move(handler)
5473  ]
5474  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5475  auto packet_id = variant_get<packet_id_t>(var);
5476  if (packet_id == 0) {
5477  call_protocol_error_handlers();
5478  return;
5479  }
5480  handler(
5481  force_move(self),
5482  force_move(session_life_keeper),
5483  static_cast<packet_id_t>(packet_id),
5484  force_move(buf)
5485  );
5486  }
5487  );
5488  }
5489 
5490  void process_binary(
5491  this_type_sp&& self,
5492  any&& session_life_keeper,
5493  buffer buf,
5494  parse_handler&& handler
5495  ) {
5496  if (remaining_length_ < 2) {
5497  call_protocol_error_handlers();
5498  return;
5499  }
5500  process_fixed_length<2>(
5501  force_move(self),
5502  force_move(session_life_keeper),
5503  force_move(buf),
5504  [
5505  this,
5506  handler = force_move(handler)
5507  ]
5508  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5509  auto size = variant_get<typename two_or_four_byte_type<2>::type>(var);
5510  if (remaining_length_ < size) {
5511  call_protocol_error_handlers();
5512  return;
5513  }
5514  process_nbytes(
5515  force_move(self),
5516  force_move(session_life_keeper),
5517  force_move(buf),
5518  size,
5519  force_move(handler)
5520  );
5521  }
5522  );
5523  }
5524 
5525  void process_string(
5526  this_type_sp&& self,
5527  any&& session_life_keeper,
5528  buffer buf,
5529  parse_handler&& handler
5530  ) {
5531  process_binary(
5532  force_move(self),
5533  force_move(session_life_keeper),
5534  force_move(buf),
5535  [this, handler = force_move(handler)]
5536  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5537  auto& str = variant_get<buffer>(var);
5538  auto r = utf8string::validate_contents(str);
5540  call_bad_message_error_handlers();
5541  return;
5542  }
5543  handler(
5544  force_move(self),
5545  force_move(session_life_keeper),
5546  force_move(str),
5547  force_move(buf)
5548  );
5549  }
5550  );
5551  }
5552 
5553 
5554  void process_properties(
5555  this_type_sp&& self,
5556  any&& session_life_keeper,
5557  buffer buf,
5558  parse_handler&& handler
5559  ) {
5560  process_variable_length(
5561  force_move(self),
5562  force_move(session_life_keeper),
5563  force_move(buf),
5564  [
5565  this,
5566  handler = force_move(handler)
5567  ]
5568  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5569  auto property_length = variant_get<std::size_t>(var);
5570  if (property_length > remaining_length_) {
5571  call_protocol_error_handlers();
5572  return;
5573  }
5574  if (property_length == 0) {
5575  handler(
5576  force_move(self),
5577  force_move(session_life_keeper),
5578  v5::properties(),
5579  force_move(buf)
5580  );
5581  return;
5582  }
5583 
5584  if (buf.empty()) {
5585  struct spa_address_len {
5586  shared_ptr_array spa;
5587  char* address;
5588  std::size_t len;
5589  };
5590  auto result =
5591  [&] () -> spa_address_len {
5592  if (property_length < props_bulk_read_limit_) {
5593  auto spa = make_shared_ptr_array(property_length);
5594  auto ptr = spa.get();
5595  return
5596  {
5597  force_move(spa),
5598  ptr,
5599  property_length
5600  };
5601  }
5602  return
5603  {
5604  nullptr,
5605  buf_.data(),
5606  1
5607  };
5608  } ();
5609  socket_->async_read(
5610  as::buffer(result.address, result.len),
5611  [
5612  this,
5613  handler = force_move(handler),
5614  self = force_move(self),
5615  session_life_keeper = force_move(session_life_keeper),
5616  property_length,
5617  result
5618  ]
5619  (error_code ec, std::size_t bytes_transferred) mutable {
5620  this->total_bytes_received_ += bytes_transferred;
5621  if (!check_error_and_transferred_length(ec, bytes_transferred, result.len)) return;
5622  process_property_id(
5623  force_move(self),
5624  force_move(session_life_keeper),
5625  buffer(string_view(result.address, result.len), result.spa),
5626  property_length,
5627  v5::properties(),
5628  force_move(handler)
5629  );
5630  }
5631  );
5632  }
5633  else {
5634  process_property_id(
5635  force_move(self),
5636  force_move(session_life_keeper),
5637  force_move(buf),
5638  property_length,
5639  v5::properties(),
5640  force_move(handler)
5641  );
5642  }
5643  }
5644  );
5645  }
5646 
5647  void process_property_id(
5648  this_type_sp&& self,
5649  any&& session_life_keeper,
5650  buffer buf,
5651  std::size_t property_length_rest,
5652  v5::properties props,
5653  parse_handler&& handler
5654  ) {
5655 
5656  if (property_length_rest == 0) {
5657  handler(
5658  force_move(self),
5659  force_move(session_life_keeper),
5660  force_move(props),
5661  force_move(buf)
5662  );
5663  return;
5664  }
5665 
5666  --remaining_length_;
5667  if (buf.empty()) {
5668  socket_->async_read(
5669  as::buffer(buf_.data(), 1),
5670  [
5671  this,
5672  self = force_move(self),
5673  session_life_keeper = force_move(session_life_keeper),
5674  props = force_move(props),
5675  handler = force_move(handler),
5676  property_length_rest
5677  ]
5678  (error_code ec,
5679  std::size_t bytes_transferred) mutable {
5680  this->total_bytes_received_ += bytes_transferred;
5681  if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return;
5682  process_property_body(
5683  force_move(self),
5684  force_move(session_life_keeper),
5685  buffer(),
5686  static_cast<v5::property::id>(buf_.front()),
5687  property_length_rest - 1,
5688  force_move(props),
5689  force_move(handler)
5690  );
5691  }
5692  );
5693  }
5694  else {
5695  auto id = static_cast<v5::property::id>(buf.front());
5696  buf.remove_prefix(1);
5697  process_property_body(
5698  force_move(self),
5699  force_move(session_life_keeper),
5700  force_move(buf),
5701  id,
5702  property_length_rest - 1,
5703  force_move(props),
5704  force_move(handler)
5705  );
5706  }
5707  }
5708 
5709  void process_property_body(
5710  this_type_sp&& self,
5711  any&& session_life_keeper,
5712  buffer buf,
5713  v5::property::id id,
5714  std::size_t property_length_rest,
5715  v5::properties props,
5716  parse_handler&& handler
5717  ) {
5718 
5719  static constexpr std::size_t length_bytes = 2;
5720 
5721  if (property_length_rest == 0) {
5722  call_protocol_error_handlers();
5723  return;
5724  }
5725 
5726  switch (id) {
5728  static constexpr std::size_t len = 1;
5729  if (property_length_rest < len) {
5730  call_protocol_error_handlers();
5731  return;
5732  }
5733  process_nbytes(
5734  force_move(self),
5735  force_move(session_life_keeper),
5736  force_move(buf),
5737  len,
5738  [
5739  this,
5740  props = force_move(props),
5741  handler = force_move(handler),
5742  rest = property_length_rest - len
5743  ]
5744  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5745  auto& body = variant_get<buffer>(var);
5746  props.emplace_back(
5747  v5::property::payload_format_indicator(body.begin(), body.end())
5748  );
5749  process_property_id(
5750  force_move(self),
5751  force_move(session_life_keeper),
5752  force_move(buf),
5753  rest,
5754  force_move(props),
5755  force_move(handler)
5756  );
5757  }
5758  );
5759  } break;
5761  static constexpr std::size_t len = 4;
5762  if (property_length_rest < len) {
5763  call_protocol_error_handlers();
5764  return;
5765  }
5766  process_nbytes(
5767  force_move(self),
5768  force_move(session_life_keeper),
5769  force_move(buf),
5770  len,
5771  [
5772  this,
5773  props = force_move(props),
5774  handler = force_move(handler),
5775  rest = property_length_rest - len
5776  ]
5777  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5778  auto& body = variant_get<buffer>(var);
5779  props.emplace_back(
5780  v5::property::message_expiry_interval(body.begin(), body.end())
5781  );
5782  process_property_id(
5783  force_move(self),
5784  force_move(session_life_keeper),
5785  force_move(buf),
5786  rest,
5787  force_move(props),
5788  force_move(handler)
5789  );
5790  }
5791  );
5792  } break;
5794  process_string(
5795  force_move(self),
5796  force_move(session_life_keeper),
5797  force_move(buf),
5798  [
5799  this,
5800  props = force_move(props),
5801  handler = force_move(handler),
5802  property_length_rest
5803  ]
5804  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5805  auto& body = variant_get<buffer>(var);
5806  auto rest = property_length_rest - length_bytes - body.size();
5807  props.emplace_back(
5808  v5::property::content_type(force_move(body), true)
5809  );
5810  process_property_id(
5811  force_move(self),
5812  force_move(session_life_keeper),
5813  force_move(buf),
5814  rest,
5815  force_move(props),
5816  force_move(handler)
5817  );
5818  }
5819  );
5820  } break;
5822  process_string(
5823  force_move(self),
5824  force_move(session_life_keeper),
5825  force_move(buf),
5826  [
5827  this,
5828  props = force_move(props),
5829  handler = force_move(handler),
5830  property_length_rest
5831  ]
5832  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5833  auto& body = variant_get<buffer>(var);
5834  auto rest = property_length_rest - length_bytes - body.size();
5835  props.emplace_back(
5836  v5::property::response_topic(force_move(body), true)
5837  );
5838  process_property_id(
5839  force_move(self),
5840  force_move(session_life_keeper),
5841  force_move(buf),
5842  rest,
5843  force_move(props),
5844  force_move(handler)
5845  );
5846  }
5847  );
5848  } break;
5850  process_string(
5851  force_move(self),
5852  force_move(session_life_keeper),
5853  force_move(buf),
5854  [
5855  this,
5856  props = force_move(props),
5857  handler = force_move(handler),
5858  property_length_rest
5859  ]
5860  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5861  auto& body = variant_get<buffer>(var);
5862  auto rest = property_length_rest - length_bytes - body.size();
5863  props.emplace_back(
5864  v5::property::correlation_data(force_move(body), true)
5865  );
5866  process_property_id(
5867  force_move(self),
5868  force_move(session_life_keeper),
5869  force_move(buf),
5870  rest,
5871  force_move(props),
5872  force_move(handler)
5873  );
5874  }
5875  );
5876  } break;
5878  process_variable_length(
5879  force_move(self),
5880  force_move(session_life_keeper),
5881  force_move(buf),
5882  [
5883  this,
5884  props = force_move(props),
5885  handler = force_move(handler),
5886  property_length_rest,
5887  remaining_length_before = remaining_length_
5888  ]
5889  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5890  auto size = variant_get<std::size_t>(var);
5891  auto consumed = remaining_length_before - remaining_length_;
5892  auto rest = property_length_rest - consumed;
5893  props.emplace_back(
5894  v5::property::subscription_identifier(size)
5895  );
5896  process_property_id(
5897  force_move(self),
5898  force_move(session_life_keeper),
5899  force_move(buf),
5900  rest,
5901  force_move(props),
5902  force_move(handler)
5903  );
5904  }
5905  );
5906  } break;
5908  static constexpr std::size_t len = 4;
5909  if (property_length_rest < len) {
5910  call_protocol_error_handlers();
5911  return;
5912  }
5913  process_nbytes(
5914  force_move(self),
5915  force_move(session_life_keeper),
5916  force_move(buf),
5917  len,
5918  [
5919  this,
5920  props = force_move(props),
5921  handler = force_move(handler),
5922  rest = property_length_rest - len
5923  ]
5924  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5925  auto& body = variant_get<buffer>(var);
5926  props.emplace_back(
5927  v5::property::session_expiry_interval(body.begin(), body.end())
5928  );
5929  process_property_id(
5930  force_move(self),
5931  force_move(session_life_keeper),
5932  force_move(buf),
5933  rest,
5934  force_move(props),
5935  force_move(handler)
5936  );
5937  }
5938  );
5939  } break;
5941  process_string(
5942  force_move(self),
5943  force_move(session_life_keeper),
5944  force_move(buf),
5945  [
5946  this,
5947  props = force_move(props),
5948  handler = force_move(handler),
5949  property_length_rest
5950  ]
5951  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5952  auto& body = variant_get<buffer>(var);
5953  auto rest = property_length_rest - length_bytes - body.size();
5954  props.emplace_back(
5955  v5::property::assigned_client_identifier(force_move(body), true)
5956  );
5957  process_property_id(
5958  force_move(self),
5959  force_move(session_life_keeper),
5960  force_move(buf),
5961  rest,
5962  force_move(props),
5963  force_move(handler)
5964  );
5965  }
5966  );
5967 
5968  } break;
5970  static constexpr std::size_t len = 2;
5971  if (property_length_rest < len) {
5972  call_protocol_error_handlers();
5973  return;
5974  }
5975  process_nbytes(
5976  force_move(self),
5977  force_move(session_life_keeper),
5978  force_move(buf),
5979  len,
5980  [
5981  this,
5982  props = force_move(props),
5983  handler = force_move(handler),
5984  rest = property_length_rest - len
5985  ]
5986  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
5987  auto& body = variant_get<buffer>(var);
5988  props.emplace_back(
5989  v5::property::server_keep_alive(body.begin(), body.end())
5990  );
5991  process_property_id(
5992  force_move(self),
5993  force_move(session_life_keeper),
5994  force_move(buf),
5995  rest,
5996  force_move(props),
5997  force_move(handler)
5998  );
5999  }
6000  );
6001  } break;
6003  process_string(
6004  force_move(self),
6005  force_move(session_life_keeper),
6006  force_move(buf),
6007  [
6008  this,
6009  props = force_move(props),
6010  handler = force_move(handler),
6011  property_length_rest
6012  ]
6013  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6014  auto& body = variant_get<buffer>(var);
6015  auto rest = property_length_rest - length_bytes - body.size();
6016  props.emplace_back(
6017  v5::property::authentication_method(force_move(body), true)
6018  );
6019  process_property_id(
6020  force_move(self),
6021  force_move(session_life_keeper),
6022  force_move(buf),
6023  rest,
6024  force_move(props),
6025  force_move(handler)
6026  );
6027  }
6028  );
6029  } break;
6031  process_binary(
6032  force_move(self),
6033  force_move(session_life_keeper),
6034  force_move(buf),
6035  [
6036  this,
6037  props = force_move(props),
6038  handler = force_move(handler),
6039  property_length_rest
6040  ]
6041  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6042  auto& body = variant_get<buffer>(var);
6043  auto rest = property_length_rest - length_bytes - body.size();
6044  props.emplace_back(
6045  v5::property::authentication_data(force_move(body))
6046  );
6047  process_property_id(
6048  force_move(self),
6049  force_move(session_life_keeper),
6050  force_move(buf),
6051  rest,
6052  force_move(props),
6053  force_move(handler)
6054  );
6055  }
6056  );
6057  } break;
6059  static constexpr std::size_t len = 1;
6060  if (property_length_rest < len) {
6061  call_protocol_error_handlers();
6062  return;
6063  }
6064  process_nbytes(
6065  force_move(self),
6066  force_move(session_life_keeper),
6067  force_move(buf),
6068  len,
6069  [
6070  this,
6071  props = force_move(props),
6072  handler = force_move(handler),
6073  rest = property_length_rest - len
6074  ]
6075  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6076  auto& body = variant_get<buffer>(var);
6077  props.emplace_back(
6078  v5::property::request_problem_information(body.begin(), body.end())
6079  );
6080  process_property_id(
6081  force_move(self),
6082  force_move(session_life_keeper),
6083  force_move(buf),
6084  rest,
6085  force_move(props),
6086  force_move(handler)
6087  );
6088  }
6089  );
6090  } break;
6092  static constexpr std::size_t len = 4;
6093  if (property_length_rest < len) {
6094  call_protocol_error_handlers();
6095  return;
6096  }
6097  process_nbytes(
6098  force_move(self),
6099  force_move(session_life_keeper),
6100  force_move(buf),
6101  len,
6102  [
6103  this,
6104  props = force_move(props),
6105  handler = force_move(handler),
6106  rest = property_length_rest - len
6107  ]
6108  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6109  auto& body = variant_get<buffer>(var);
6110  props.emplace_back(
6111  v5::property::will_delay_interval(body.begin(), body.end())
6112  );
6113  process_property_id(
6114  force_move(self),
6115  force_move(session_life_keeper),
6116  force_move(buf),
6117  rest,
6118  force_move(props),
6119  force_move(handler)
6120  );
6121  }
6122  );
6123  } break;
6125  static constexpr std::size_t len = 1;
6126  if (property_length_rest < len) {
6127  call_protocol_error_handlers();
6128  return;
6129  }
6130  process_nbytes(
6131  force_move(self),
6132  force_move(session_life_keeper),
6133  force_move(buf),
6134  len,
6135  [
6136  this,
6137  props = force_move(props),
6138  handler = force_move(handler),
6139  rest = property_length_rest - len
6140  ]
6141  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6142  auto& body = variant_get<buffer>(var);
6143  props.emplace_back(
6144  v5::property::request_response_information(body.begin(), body.end())
6145  );
6146  process_property_id(
6147  force_move(self),
6148  force_move(session_life_keeper),
6149  force_move(buf),
6150  rest,
6151  force_move(props),
6152  force_move(handler)
6153  );
6154  }
6155  );
6156  } break;
6158  process_string(
6159  force_move(self),
6160  force_move(session_life_keeper),
6161  force_move(buf),
6162  [
6163  this,
6164  props = force_move(props),
6165  handler = force_move(handler),
6166  property_length_rest
6167  ]
6168  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6169  auto& body = variant_get<buffer>(var);
6170  auto rest = property_length_rest - length_bytes - body.size();
6171  props.emplace_back(
6172  v5::property::response_information(force_move(body), true)
6173  );
6174  process_property_id(
6175  force_move(self),
6176  force_move(session_life_keeper),
6177  force_move(buf),
6178  rest,
6179  force_move(props),
6180  force_move(handler)
6181  );
6182  }
6183  );
6184  } break;
6186  process_string(
6187  force_move(self),
6188  force_move(session_life_keeper),
6189  force_move(buf),
6190  [
6191  this,
6192  props = force_move(props),
6193  handler = force_move(handler),
6194  property_length_rest
6195  ]
6196  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6197  auto& body = variant_get<buffer>(var);
6198  auto rest = property_length_rest - length_bytes - body.size();
6199  props.emplace_back(
6200  v5::property::server_reference(force_move(body), true)
6201  );
6202  process_property_id(
6203  force_move(self),
6204  force_move(session_life_keeper),
6205  force_move(buf),
6206  rest,
6207  force_move(props),
6208  force_move(handler)
6209  );
6210  }
6211  );
6212  } break;
6214  process_string(
6215  force_move(self),
6216  force_move(session_life_keeper),
6217  force_move(buf),
6218  [
6219  this,
6220  props = force_move(props),
6221  handler = force_move(handler),
6222  property_length_rest
6223  ]
6224  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6225  auto& body = variant_get<buffer>(var);
6226  auto rest = property_length_rest - length_bytes - body.size();
6227  props.emplace_back(
6228  v5::property::reason_string(force_move(body), true)
6229  );
6230  process_property_id(
6231  force_move(self),
6232  force_move(session_life_keeper),
6233  force_move(buf),
6234  rest,
6235  force_move(props),
6236  force_move(handler)
6237  );
6238  }
6239  );
6240  } break;
6242  static constexpr std::size_t len = 2;
6243  if (property_length_rest < len) {
6244  call_protocol_error_handlers();
6245  return;
6246  }
6247  process_nbytes(
6248  force_move(self),
6249  force_move(session_life_keeper),
6250  force_move(buf),
6251  len,
6252  [
6253  this,
6254  props = force_move(props),
6255  handler = force_move(handler),
6256  rest = property_length_rest - len
6257  ]
6258  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6259  auto& body = variant_get<buffer>(var);
6260  props.emplace_back(
6261  v5::property::receive_maximum(body.begin(), body.end())
6262  );
6263  process_property_id(
6264  force_move(self),
6265  force_move(session_life_keeper),
6266  force_move(buf),
6267  rest,
6268  force_move(props),
6269  force_move(handler)
6270  );
6271  }
6272  );
6273  } break;
6275  static constexpr std::size_t len = 2;
6276  if (property_length_rest < len) {
6277  call_protocol_error_handlers();
6278  return;
6279  }
6280  process_nbytes(
6281  force_move(self),
6282  force_move(session_life_keeper),
6283  force_move(buf),
6284  len,
6285  [
6286  this,
6287  props = force_move(props),
6288  handler = force_move(handler),
6289  rest = property_length_rest - len
6290  ]
6291  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6292  auto& body = variant_get<buffer>(var);
6293  props.emplace_back(
6294  v5::property::topic_alias_maximum(body.begin(), body.end())
6295  );
6296  process_property_id(
6297  force_move(self),
6298  force_move(session_life_keeper),
6299  force_move(buf),
6300  rest,
6301  force_move(props),
6302  force_move(handler)
6303  );
6304  }
6305  );
6306  } break;
6308  static constexpr std::size_t len = 2;
6309  if (property_length_rest < len) {
6310  call_protocol_error_handlers();
6311  return;
6312  }
6313  process_nbytes(
6314  force_move(self),
6315  force_move(session_life_keeper),
6316  force_move(buf),
6317  len,
6318  [
6319  this,
6320  props = force_move(props),
6321  handler = force_move(handler),
6322  rest = property_length_rest - len
6323  ]
6324  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6325  auto& body = variant_get<buffer>(var);
6326  props.emplace_back(
6327  v5::property::topic_alias(body.begin(), body.end())
6328  );
6329  process_property_id(
6330  force_move(self),
6331  force_move(session_life_keeper),
6332  force_move(buf),
6333  rest,
6334  force_move(props),
6335  force_move(handler)
6336  );
6337  }
6338  );
6339  } break;
6341  static constexpr std::size_t len = 1;
6342  if (property_length_rest < len) {
6343  call_protocol_error_handlers();
6344  return;
6345  }
6346  process_nbytes(
6347  force_move(self),
6348  force_move(session_life_keeper),
6349  force_move(buf),
6350  len,
6351  [
6352  this,
6353  props = force_move(props),
6354  handler = force_move(handler),
6355  rest = property_length_rest - len
6356  ]
6357  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6358  auto& body = variant_get<buffer>(var);
6359  props.emplace_back(
6360  v5::property::maximum_qos(body.begin(), body.end())
6361  );
6362  process_property_id(
6363  force_move(self),
6364  force_move(session_life_keeper),
6365  force_move(buf),
6366  rest,
6367  force_move(props),
6368  force_move(handler)
6369  );
6370  }
6371  );
6372  } break;
6374  static constexpr std::size_t len = 1;
6375  if (property_length_rest < len) {
6376  call_protocol_error_handlers();
6377  return;
6378  }
6379  process_nbytes(
6380  force_move(self),
6381  force_move(session_life_keeper),
6382  force_move(buf),
6383  len,
6384  [
6385  this,
6386  props = force_move(props),
6387  handler = force_move(handler),
6388  rest = property_length_rest - len
6389  ]
6390  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6391  auto& body = variant_get<buffer>(var);
6392  props.emplace_back(
6393  v5::property::retain_available(body.begin(), body.end())
6394  );
6395  process_property_id(
6396  force_move(self),
6397  force_move(session_life_keeper),
6398  force_move(buf),
6399  rest,
6400  force_move(props),
6401  force_move(handler)
6402  );
6403  }
6404  );
6405  } break;
6407  process_string(
6408  force_move(self),
6409  force_move(session_life_keeper),
6410  force_move(buf),
6411  [
6412  this,
6413  props = force_move(props),
6414  handler = force_move(handler),
6415  property_length_rest
6416  ]
6417  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6418  auto& key = variant_get<buffer>(var);
6419  auto rest = property_length_rest - length_bytes - key.size();
6420  process_string(
6421  force_move(self),
6422  force_move(session_life_keeper),
6423  force_move(buf),
6424  [
6425  this,
6426  props = force_move(props),
6427  handler = force_move(handler),
6428  key = force_move(key),
6429  property_length_rest = rest
6430  ]
6431  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6432  auto& val = variant_get<buffer>(var);
6433  auto rest = property_length_rest - length_bytes - val.size();
6434  props.emplace_back(
6435  v5::property::user_property(
6436  force_move(key),
6437  force_move(val),
6438  true,
6439  true
6440  )
6441  );
6442  process_property_id(
6443  force_move(self),
6444  force_move(session_life_keeper),
6445  force_move(buf),
6446  rest,
6447  force_move(props),
6448  force_move(handler)
6449  );
6450  }
6451  );
6452  }
6453  );
6454  } break;
6456  static constexpr std::size_t len = 4;
6457  if (property_length_rest < len) {
6458  call_protocol_error_handlers();
6459  return;
6460  }
6461  process_nbytes(
6462  force_move(self),
6463  force_move(session_life_keeper),
6464  force_move(buf),
6465  len,
6466  [
6467  this,
6468  props = force_move(props),
6469  handler = force_move(handler),
6470  rest = property_length_rest - len
6471  ]
6472  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6473  auto& body = variant_get<buffer>(var);
6474  props.emplace_back(
6475  v5::property::maximum_packet_size(body.begin(), body.end())
6476  );
6477  process_property_id(
6478  force_move(self),
6479  force_move(session_life_keeper),
6480  force_move(buf),
6481  rest,
6482  force_move(props),
6483  force_move(handler)
6484  );
6485  }
6486  );
6487  } break;
6489  static constexpr std::size_t len = 1;
6490  if (property_length_rest < len) {
6491  call_protocol_error_handlers();
6492  return;
6493  }
6494  process_nbytes(
6495  force_move(self),
6496  force_move(session_life_keeper),
6497  force_move(buf),
6498  len,
6499  [
6500  this,
6501  props = force_move(props),
6502  handler = force_move(handler),
6503  rest = property_length_rest - len
6504  ]
6505  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6506  auto& body = variant_get<buffer>(var);
6507  props.emplace_back(
6508  v5::property::wildcard_subscription_available(body.begin(), body.end())
6509  );
6510  process_property_id(
6511  force_move(self),
6512  force_move(session_life_keeper),
6513  force_move(buf),
6514  rest,
6515  force_move(props),
6516  force_move(handler)
6517  );
6518  }
6519  );
6520  } break;
6522  static constexpr std::size_t len = 1;
6523  if (property_length_rest < len) {
6524  call_protocol_error_handlers();
6525  return;
6526  }
6527  process_nbytes(
6528  force_move(self),
6529  force_move(session_life_keeper),
6530  force_move(buf),
6531  len,
6532  [
6533  this,
6534  props = force_move(props),
6535  handler = force_move(handler),
6536  rest = property_length_rest - len
6537  ]
6538  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6539  auto& body = variant_get<buffer>(var);
6540  props.emplace_back(
6541  v5::property::subscription_identifier_available(body.begin(), body.end())
6542  );
6543  process_property_id(
6544  force_move(self),
6545  force_move(session_life_keeper),
6546  force_move(buf),
6547  rest,
6548  force_move(props),
6549  force_move(handler)
6550  );
6551  }
6552  );
6553  } break;
6555  static constexpr std::size_t len = 1;
6556  if (property_length_rest < len) {
6557  call_protocol_error_handlers();
6558  return;
6559  }
6560  process_nbytes(
6561  force_move(self),
6562  force_move(session_life_keeper),
6563  force_move(buf),
6564  len,
6565  [
6566  this,
6567  props = force_move(props),
6568  handler = force_move(handler),
6569  rest = property_length_rest - len
6570  ]
6571  (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable {
6572  auto& body = variant_get<buffer>(var);
6573  props.emplace_back(
6574  v5::property::shared_subscription_available(body.begin(), body.end())
6575  );
6576  process_property_id(
6577  force_move(self),
6578  force_move(session_life_keeper),
6579  force_move(buf),
6580  rest,
6581  force_move(props),
6582  force_move(handler)
6583  );
6584  }
6585  );
6586  } break;
6587  }
6588  }
6589 
6590  // process common
6591 
6592  void process_header(
6593  this_type_sp&& self,
6594  any&& session_life_keeper,
6595  bool all_read,
6596  std::size_t header_len,
6597  parse_handler&& handler
6598  ) {
6599 
6600  if (all_read) {
6601  auto spa = make_shared_ptr_array(remaining_length_);
6602  auto ptr = spa.get();
6603  socket_->async_read(
6604  as::buffer(ptr, remaining_length_),
6605  [
6606  this,
6607  self = force_move(self),
6608  session_life_keeper = force_move(session_life_keeper),
6609  buf = buffer(string_view(ptr, remaining_length_), force_move(spa)),
6610  handler = force_move(handler)
6611  ]
6612  (error_code ec, std::size_t bytes_transferred) mutable {
6613  this->total_bytes_received_ += bytes_transferred;
6614  if (!check_error_and_transferred_length(ec, bytes_transferred, remaining_length_)) return;
6615  handler(
6616  force_move(self),
6617  force_move(session_life_keeper),
6618  force_move(buf),
6619  buffer()
6620  );
6621  }
6622  );
6623  return;
6624  }
6625 
6626  if (header_len == 0) {
6627  force_move(handler)(
6628  force_move(self),
6629  force_move(session_life_keeper),
6630  buffer(),
6631  buffer()
6632  );
6633  return;
6634  }
6635 
6636  socket_->async_read(
6637  as::buffer(buf_.data(), header_len),
6638  [
6639  this,
6640  self = force_move(self),
6641  session_life_keeper = force_move(session_life_keeper),
6642  header_len,
6643  handler = force_move(handler)
6644  ]
6645  (error_code ec,
6646  std::size_t bytes_transferred) mutable {
6647  this->total_bytes_received_ += bytes_transferred;
6648  if (!check_error_and_transferred_length(ec, bytes_transferred, header_len)) return;
6649  handler(
6650  force_move(self),
6651  force_move(session_life_keeper),
6652  buffer(string_view(buf_.data(), header_len)),
6653  buffer()
6654  );
6655  }
6656  );
6657  }
6658 
6659  // process connect
6660 
6661  struct process_connect : as::coroutine, std::enable_shared_from_this<process_connect> {
6662  using ep_t = this_type;
6663  using ep_t_sp = this_type_sp;
6664  using process_type = process_connect;
6665  using process_type_sp = std::shared_ptr<process_type>;
6666 
6668  ep_t& ep,
6669  bool all_read
6670  ):ep_{ep},
6671  all_read_{all_read} {
6672  }
6673  void operator()(
6674  ep_t_sp spep,
6675  any&& session_life_keeper,
6676  parse_handler_variant var = std::size_t(0),
6677  buffer remain_buf = buffer()
6678  ) {
6679  reenter(this) {
6680  if (ep_.remaining_length_ < header_len_) {
6681  ep_.call_protocol_error_handlers();
6682  return;
6683  }
6684  // header
6685  yield ep_.process_header(
6686  force_move(spep),
6687  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
6688  all_read_,
6689  header_len_,
6690  [this]
6691  (auto&&... args ) {
6692  (*this)(std::forward<decltype(args)>(args)...);
6693  }
6694  );
6695 
6696  yield {
6697  auto& buf = variant_get<buffer>(var);
6698 
6699  static constexpr char protocol_name[] = { 0x00, 0x04, 'M', 'Q', 'T', 'T' };
6700  if (std::memcmp(buf.data(), protocol_name, sizeof(protocol_name)) != 0) {
6701  ep_.call_protocol_error_handlers();
6702  return;
6703  }
6704  std::size_t i = sizeof(protocol_name);
6705  auto version = static_cast<protocol_version>(buf[i++]);
6706  if (version != protocol_version::v3_1_1 && version != protocol_version::v5) {
6707  ep_.call_protocol_error_handlers();
6708  return;
6709  }
6710 
6711  if (ep_.version_ == protocol_version::undetermined) {
6712  ep_.version_ = version;
6713  }
6714  else if (ep_.version_ != version) {
6715  ep_.call_protocol_error_handlers();
6716  return;
6717  }
6718 
6719  connect_flag_ = buf[i++];
6720 
6721  keep_alive_ = make_uint16_t(buf[i], buf[i + 1]);
6722  ep_.clean_start_ = connect_flags::has_clean_start(connect_flag_);
6723 
6724  buf.remove_prefix(header_len_); // consume buffer
6725  if (ep_.version_ == protocol_version::v5) {
6726  // properties
6727  ep_.process_properties(
6728  force_move(spep),
6729  force_move(session_life_keeper),
6730  force_move(buf),
6731  [this]
6732  (auto&&... args ) {
6733  (*this)(std::forward<decltype(args)>(args)...);
6734  }
6735  );
6736  }
6737  else {
6738  (*this)(force_move(spep), force_move(session_life_keeper), v5::properties(), force_move(buf));
6739  }
6740  }
6741  props_ = force_move(variant_get<v5::properties>(var));
6742 
6743  // client_id
6744  yield ep_.process_string(
6745  force_move(spep),
6746  force_move(session_life_keeper),
6747  force_move(remain_buf),
6748  [this]
6749  (auto&&... args ) {
6750  (*this)(std::forward<decltype(args)>(args)...);
6751  }
6752  );
6753  client_id_ = force_move(variant_get<buffer>(var));
6754  if (connect_flags::has_will_flag(connect_flag_)) {
6755  if (ep_.version_ == protocol_version::v5) {
6756  // will properties
6757  yield ep_.process_properties(
6758  force_move(spep),
6759  force_move(session_life_keeper),
6760  force_move(remain_buf),
6761  [this]
6762  (auto&&... args ) {
6763  (*this)(std::forward<decltype(args)>(args)...);
6764  }
6765  );
6766  will_props_ = force_move(variant_get<v5::properties>(var));
6767  }
6768  // will topic
6769  yield ep_.process_string(
6770  force_move(spep),
6771  force_move(session_life_keeper),
6772  force_move(remain_buf),
6773  [this]
6774  (auto&&... args ) {
6775  (*this)(std::forward<decltype(args)>(args)...);
6776  }
6777  );
6778  will_topic_ = force_move(variant_get<buffer>(var));
6779  // will payload
6780  yield ep_.process_binary(
6781  force_move(spep),
6782  force_move(session_life_keeper),
6783  force_move(remain_buf),
6784  [this]
6785  (auto&&... args ) {
6786  (*this)(std::forward<decltype(args)>(args)...);
6787  }
6788  );
6789  will_payload_ = force_move(variant_get<buffer>(var));
6790  }
6791  if (connect_flags::has_user_name_flag(connect_flag_)) {
6792  yield ep_.process_string(
6793  force_move(spep),
6794  force_move(session_life_keeper),
6795  force_move(remain_buf),
6796  [this]
6797  (auto&&... args ) {
6798  (*this)(std::forward<decltype(args)>(args)...);
6799  }
6800  );
6801  user_name_ = force_move(variant_get<buffer>(var));
6802  }
6803  if (connect_flags::has_password_flag(connect_flag_)) {
6804  yield ep_.process_binary(
6805  force_move(spep),
6806  force_move(session_life_keeper),
6807  force_move(remain_buf),
6808  [this]
6809  (auto&&... args ) {
6810  (*this)(std::forward<decltype(args)>(args)...);
6811  }
6812  );
6813  password_ = force_move(variant_get<buffer>(var));
6814  }
6815  ep_.mqtt_connected_ = true;
6816  switch (ep_.version_) {
6818  if (ep_.on_connect(
6819  force_move(client_id_),
6820  force_move(user_name_),
6821  force_move(password_),
6822  connect_flags::has_will_flag(connect_flag_)
6823  ? optional<will>(in_place_init,
6824  force_move(will_topic_),
6825  force_move(will_payload_),
6826  connect_flags::has_will_retain(connect_flag_) | connect_flags::will_qos(connect_flag_))
6827  : optional<will>(nullopt),
6828  ep_.clean_session(),
6829  keep_alive_
6830  )
6831  ) {
6832  ep_.on_mqtt_message_processed(
6833  force_move(
6834  std::get<0>(
6835  any_cast<
6836  std::tuple<any, process_type_sp>
6837  >(session_life_keeper)
6838  )
6839  )
6840  );
6841  }
6842  break;
6843  case protocol_version::v5:
6844  if (auto ta_opt = get_topic_alias_maximum_from_props(props_)) {
6845  if (ta_opt.value() > 0) {
6846  LockGuard<Mutex> lck (ep_.topic_alias_send_mtx_);
6847  ep_.topic_alias_send_.emplace(ta_opt.value());
6848  }
6849  }
6850  if (ep_.on_v5_connect(
6851  force_move(client_id_),
6852  force_move(user_name_),
6853  force_move(password_),
6854  connect_flags::has_will_flag(connect_flag_)
6855  ? optional<will>(in_place_init,
6856  force_move(will_topic_),
6857  force_move(will_payload_),
6858  connect_flags::has_will_retain(connect_flag_) | connect_flags::will_qos(connect_flag_),
6859  force_move(will_props_))
6860  : optional<will>(nullopt),
6861  ep_.clean_start(),
6862  keep_alive_,
6863  force_move(props_)
6864  )
6865  ) {
6866  ep_.on_mqtt_message_processed(
6867  force_move(
6868  std::get<0>(
6869  any_cast<
6870  std::tuple<any, process_type_sp>
6871  >(session_life_keeper)
6872  )
6873  )
6874  );
6875  }
6876  break;
6877  default:
6878  BOOST_ASSERT(false);
6879  }
6880  }
6881  }
6882 
6883  private:
6884  static constexpr std::size_t header_len_ =
6885  2 + // string length
6886  4 + // "MQTT" string
6887  1 + // ProtocolVersion
6888  1 + // ConnectFlag
6889  2; // KeepAlive
6890 
6891  ep_t& ep_;
6892  bool all_read_;
6893 
6894  char connect_flag_;
6895  std::uint16_t keep_alive_;
6896  v5::properties props_;
6897  buffer client_id_;
6898  v5::properties will_props_;
6899  buffer will_topic_;
6900  buffer will_payload_;
6901  optional<buffer> user_name_;
6902  optional<buffer> password_;
6903  };
6904  friend struct process_connect;
6905 
6906  // process connack
6907 
6908  struct process_connack : as::coroutine, std::enable_shared_from_this<process_connack> {
6909  using ep_t = this_type;
6910  using ep_t_sp = this_type_sp;
6911  using process_type = process_connack;
6912  using process_type_sp = std::shared_ptr<process_type>;
6913 
6915  ep_t& ep,
6916  bool all_read
6917  ):ep_{ep},
6918  all_read_{all_read} {
6919  }
6920  void operator()(
6921  ep_t_sp spep,
6922  any&& session_life_keeper,
6923  parse_handler_variant var = std::size_t(0),
6924  buffer /*remain_buf*/ = buffer()
6925  ) {
6926  reenter(this) {
6927  if (ep_.remaining_length_ < header_len_) {
6928  ep_.call_protocol_error_handlers();
6929  return;
6930  }
6931  // header
6932  yield ep_.process_header(
6933  force_move(spep),
6934  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
6935  all_read_,
6936  header_len_,
6937  [this]
6938  (auto&&... args ) {
6939  (*this)(std::forward<decltype(args)>(args)...);
6940  }
6941  );
6942 
6943  yield {
6944  auto& buf = variant_get<buffer>(var);
6945  session_present_ = is_session_present(buf[0]);
6946  switch (ep_.version_) {
6948  reason_code_ = static_cast<connect_return_code>(buf[1]);
6949  break;
6950  case protocol_version::v5:
6951  reason_code_ = static_cast<v5::connect_reason_code>(buf[1]);
6952  break;
6953  default:
6954  BOOST_ASSERT(false);
6955  }
6956  buf.remove_prefix(header_len_); // consume buffer
6957  if (ep_.version_ == protocol_version::v5) {
6958  // properties
6959  ep_.process_properties(
6960  force_move(spep),
6961  force_move(session_life_keeper),
6962  force_move(buf),
6963  [this]
6964  (auto&&... args ) {
6965  (*this)(std::forward<decltype(args)>(args)...);
6966  }
6967  );
6968  }
6969  else {
6970  (*this)(force_move(spep), force_move(session_life_keeper), v5::properties(), force_move(buf));
6971  }
6972  }
6973  props_ = force_move(variant_get<v5::properties>(var));
6974  ep_.mqtt_connected_ = true;
6975 
6976  {
6977  auto connack_proc =
6978  [this]
6979  (any&& session_life_keeper) mutable {
6980  switch (ep_.version_) {
6982  if (ep_.on_connack(
6983  session_present_,
6984  variant_get<connect_return_code>(reason_code_)
6985  )
6986  ) {
6987  ep_.on_mqtt_message_processed(
6988  force_move(
6989  std::get<0>(
6990  any_cast<
6991  std::tuple<any, process_type_sp>
6992  >(session_life_keeper)
6993  )
6994  )
6995  );
6996  }
6997  break;
6998  case protocol_version::v5:
6999  if (auto ta_opt = get_topic_alias_maximum_from_props(props_)) {
7000  if (ta_opt.value() > 0) {
7001  LockGuard<Mutex> lck (ep_.topic_alias_send_mtx_);
7002  ep_.topic_alias_send_.emplace(ta_opt.value());
7003  }
7004  }
7005  if (ep_.on_v5_connack(
7006  session_present_,
7007  variant_get<v5::connect_reason_code>(reason_code_),
7008  force_move(props_)
7009  )
7010  ) {
7011  ep_.on_mqtt_message_processed(
7012  force_move(
7013  std::get<0>(
7014  any_cast<
7015  std::tuple<any, process_type_sp>
7016  >(session_life_keeper)
7017  )
7018  )
7019  );
7020  }
7021  break;
7022  default:
7023  BOOST_ASSERT(false);
7024  }
7025  };
7026 
7027  // Note: boost:variant has no featue to query if the variant currently holds a specific type.
7028  // MQTT_CPP could create a type traits function to match the provided type to the index in
7029  // the boost::variant type list, but for now it does not appear to be needed.
7030  if ( ( (0 == variant_idx(reason_code_))
7031  && (connect_return_code::accepted == variant_get<connect_return_code>(reason_code_)))
7032  || ( (1 == variant_idx(reason_code_))
7033  && (v5::connect_reason_code::success == variant_get<v5::connect_reason_code>(reason_code_)))) {
7034 
7035  // If session_present is false, then call clear_session_data().
7036  // Here is the reason why it works well.
7037  // ---
7038  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078
7039  //
7040  // If the Server accepts a connection with Clean Start set to 1, the Server
7041  // MUST set Session Present to 0 in the CONNACK packet in addition to setting
7042  // a 0x00 (Success) Reason Code in the CONNACK packet [MQTT-3.2.2-2].
7043  //
7044  //
7045  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901048
7046  //
7047  // The Client can avoid implementing its own Session expiry and instead rely on
7048  // the Session Present flag returned from the Server to determine if the Session
7049  // had expired. If the Client does implement its own Session expiry, it needs to
7050  // store the time at which the Session State will be deleted as part of its
7051  // Session State.
7052  // ---
7053  //
7054  // Also it can avoid the following client side and broker side session state
7055  // mismatch autonatically.
7056  //
7057  // ---
7058  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078
7059  //
7060  // If the Client does not have Session State and receives Session Present
7061  // set to 1 it MUST close the Network Connection [MQTT-3.2.2-4]. If it
7062  // wishes to restart with a new Session the Client can reconnect using
7063  // Clean Start set to 1.
7064  // If the Client does have Session State and receives Session Present set
7065  // to 0 it MUST discard its Session State if it continues with the Network
7066  // Connection [MQTT-3.2.2-5].
7067  // ---
7068  if (session_present_) {
7069  if (ep_.async_send_store_) {
7070  // Until all stored messages are written to internal send buffer,
7071  // disable further async reading of incoming packets..
7072  ep_.async_read_on_message_processed_ = false;
7073  auto async_connack_proc =
7074  [
7075  this,
7076  spep = force_move(spep),
7077  session_life_keeper = force_move(session_life_keeper),
7078  connack_proc = force_move(connack_proc)
7079  ]
7080  () mutable {
7081  // All stored messages are sent, so re-enable reading of incoming packets.
7082  // and notify the end user code that the connack packet was received.
7083  ep_.async_read_on_message_processed_ = true;
7084  connack_proc(force_move(session_life_keeper));
7085  };
7086  ep_.async_send_store(force_move(async_connack_proc));
7087  return;
7088  }
7089  ep_.send_store();
7090  }
7091  else {
7092  ep_.clear_session_data();
7093  }
7094  }
7095  connack_proc(force_move(session_life_keeper));
7096  }
7097  }
7098  }
7099 
7100  private:
7101  static constexpr std::size_t header_len_ =
7102  1 + // Connect Acknowledge Flags
7103  1; // Reason Code
7104 
7105  ep_t& ep_;
7106  bool all_read_;
7107 
7108  bool session_present_;
7109  variant<connect_return_code, v5::connect_reason_code> reason_code_;
7110  v5::properties props_;
7111  };
7112  friend struct process_connack;
7113 
7114  // process publish
7115 
7116  struct process_publish : as::coroutine, std::enable_shared_from_this<process_publish> {
7117  using ep_t = this_type;
7118  using ep_t_sp = this_type_sp;
7119  using process_type = process_publish;
7120  using process_type_sp = std::shared_ptr<process_type>;
7121 
7123  ep_t& ep,
7124  bool all_read
7125  ):ep_{ep},
7126  all_read_{all_read} {
7127  }
7128  void operator()(
7129  ep_t_sp spep,
7130  any&& session_life_keeper,
7131  parse_handler_variant var = std::size_t(0),
7132  buffer remain_buf = buffer()
7133  ) {
7134  reenter(this) {
7135  if (ep_.remaining_length_ < min_len_) {
7136  ep_.call_protocol_error_handlers();
7137  return;
7138  }
7139  // header
7140  yield ep_.process_header(
7141  force_move(spep),
7142  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
7143  all_read_,
7144  0,
7145  [this]
7146  (auto&&... args ) {
7147  (*this)(std::forward<decltype(args)>(args)...);
7148  }
7149  );
7150 
7151  // topic_name
7152  yield ep_.process_string(
7153  force_move(spep),
7154  force_move(session_life_keeper),
7155  force_move(variant_get<buffer>(var)),
7156  [this]
7157  (auto&&... args ) {
7158  (*this)(std::forward<decltype(args)>(args)...);
7159  }
7160  );
7161  topic_name_ = force_move(variant_get<buffer>(var));
7162 
7163  qos_value_ = publish::get_qos(ep_.fixed_header_);
7164  if (qos_value_ != qos::at_most_once &&
7165  qos_value_ != qos::at_least_once &&
7166  qos_value_ != qos::exactly_once) {
7167  ep_.call_bad_message_error_handlers();
7168  return;
7169  }
7170 
7171  if (qos_value_ == qos::at_least_once ||
7172  qos_value_ == qos::exactly_once) {
7173  yield ep_.process_packet_id(
7174  force_move(spep),
7175  force_move(session_life_keeper),
7176  force_move(remain_buf),
7177  [this]
7178  (auto&&... args ) {
7179  (*this)(std::forward<decltype(args)>(args)...);
7180  }
7181  );
7182  packet_id_ = force_move(variant_get<packet_id_t>(var));
7183  }
7184  if (ep_.version_ == protocol_version::v5) {
7185  yield ep_.process_properties(
7186  force_move(spep),
7187  force_move(session_life_keeper),
7188  force_move(remain_buf),
7189  [this]
7190  (auto&&... args ) {
7191  (*this)(std::forward<decltype(args)>(args)...);
7192  }
7193  );
7194  props_ = force_move(variant_get<v5::properties>(var));
7195  }
7196  yield ep_.process_nbytes(
7197  force_move(spep),
7198  force_move(session_life_keeper),
7199  force_move(remain_buf),
7200  ep_.remaining_length_,
7201  [this]
7202  (auto&&... args ) {
7203  (*this)(std::forward<decltype(args)>(args)...);
7204  }
7205  );
7206  {
7207  auto handler_call =
7208  [&] {
7209  switch (ep_.version_) {
7211  if (ep_.on_publish(
7212  packet_id_,
7213  publish_options(ep_.fixed_header_),
7214  force_move(topic_name_),
7215  force_move(force_move(variant_get<buffer>(var))))) {
7216  ep_.on_mqtt_message_processed(
7217  force_move(
7218  std::get<0>(
7219  any_cast<
7220  std::tuple<any, process_type_sp>
7221  >(session_life_keeper)
7222  )
7223  )
7224  );
7225  return true;
7226  }
7227  break;
7228  case protocol_version::v5:
7229  if (topic_name_.empty()) {
7230  if (auto topic_alias = get_topic_alias_from_props(props_)) {
7231  auto topic_name = [&] {
7232  LockGuard<Mutex> lck (ep_.topic_alias_recv_mtx_);
7233  if (ep_.topic_alias_recv_) {
7234  return ep_.topic_alias_recv_.value().find(topic_alias.value());
7235  }
7236  return std::string();
7237  }();
7238  if (topic_name.empty()) {
7239  MQTT_LOG("mqtt_cb", error)
7240  << MQTT_ADD_VALUE(address, &ep_)
7241  << "no matching topic alias: "
7242  << topic_alias.value();
7243  ep_.call_protocol_error_handlers();
7244  return false;
7245  }
7246  else {
7247  topic_name_ = allocate_buffer(topic_name);
7248  }
7249  }
7250  }
7251  else {
7252  if (auto topic_alias = ep_.get_topic_alias_from_props(props_)) {
7253  LockGuard<Mutex> lck (ep_.topic_alias_recv_mtx_);
7254  if (ep_.topic_alias_recv_) {
7255  ep_.topic_alias_recv_.value().insert_or_update(topic_name_, topic_alias.value());
7256  }
7257  }
7258  }
7259  if (ep_.on_v5_publish(
7260  packet_id_,
7261  publish_options(ep_.fixed_header_),
7262  force_move(topic_name_),
7263  force_move(variant_get<buffer>(var)),
7264  force_move(props_)
7265  )
7266  ) {
7267  ep_.on_mqtt_message_processed(
7268  force_move(
7269  std::get<0>(
7270  any_cast<
7271  std::tuple<any, process_type_sp>
7272  >(session_life_keeper)
7273  )
7274  )
7275  );
7276  return true;
7277  }
7278  break;
7279  default:
7280  BOOST_ASSERT(false);
7281  }
7282  return false;
7283  };
7284  switch (qos_value_) {
7285  case qos::at_most_once:
7286  handler_call();
7287  break;
7288  case qos::at_least_once:
7289  if (handler_call()) {
7290  ep_.auto_pub_response(
7291  [this] {
7292  if (ep_.connected_) {
7293  ep_.send_puback(
7294  *packet_id_,
7295  v5::puback_reason_code::success,
7296  v5::properties{}
7297  );
7298  }
7299  },
7300  [this] {
7301  if (ep_.connected_) {
7302  ep_.async_send_puback(
7303  *packet_id_,
7305  v5::properties{},
7306  [](auto){}
7307  );
7308  }
7309  }
7310  );
7311  }
7312  break;
7313  case qos::exactly_once:
7314  if (handler_call()) {
7315  ep_.qos2_publish_handled_.emplace(*packet_id_);
7316  ep_.auto_pub_response(
7317  [this] {
7318  if (ep_.connected_) {
7319  ep_.send_pubrec(
7320  *packet_id_,
7322  v5::properties{}
7323  );
7324  }
7325  },
7326  [this] {
7327  if (ep_.connected_) {
7328  ep_.async_send_pubrec(
7329  *packet_id_,
7331  v5::properties{},
7332  [](auto){}
7333  );
7334  }
7335  }
7336  );
7337  }
7338  break;
7339  }
7340  }
7341  }
7342  }
7343 
7344  private:
7345  static constexpr std::size_t min_len_ = 2; // topic name length
7346 
7347  ep_t& ep_;
7348  bool all_read_;
7349 
7350  buffer topic_name_;
7351  qos qos_value_;
7352  optional<packet_id_t> packet_id_;
7353  v5::properties props_;
7354  buffer payload_;
7355  };
7356  friend struct process_publish;
7357 
7358  // process puback
7359 
7360  struct process_puback : as::coroutine, std::enable_shared_from_this<process_puback> {
7361  using ep_t = this_type;
7362  using ep_t_sp = this_type_sp;
7363  using process_type = process_puback;
7364  using process_type_sp = std::shared_ptr<process_type>;
7365 
7366  process_puback(
7367  ep_t& ep,
7368  bool all_read
7369  ):ep_{ep},
7370  all_read_{all_read} {
7371  }
7372  void operator()(
7373  ep_t_sp spep,
7374  any&& session_life_keeper,
7375  parse_handler_variant var = std::size_t(0),
7376  buffer remain_buf = buffer()
7377  ) {
7378  reenter(this) {
7379  if (ep_.remaining_length_ < header_len_) {
7380  ep_.call_protocol_error_handlers();
7381  return;
7382  }
7383  // header
7384  yield ep_.process_header(
7385  force_move(spep),
7386  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
7387  all_read_,
7388  header_len_,
7389  [this]
7390  (auto&&... args ) {
7391  (*this)(std::forward<decltype(args)>(args)...);
7392  }
7393  );
7394 
7395  // packet_id
7396  yield ep_.process_packet_id(
7397  force_move(spep),
7398  force_move(session_life_keeper),
7399  force_move(variant_get<buffer>(var)),
7400  [this]
7401  (auto&&... args ) {
7402  (*this)(std::forward<decltype(args)>(args)...);
7403  }
7404  );
7405  packet_id_ = force_move(variant_get<packet_id_t>(var));
7406 
7407  if (ep_.remaining_length_ == 0) {
7408  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
7409  // If the Remaining Length is 0, there is no reason code & property length
7410  // the value of success is used for reason code, the value of 0 is used for property length
7411  reason_code_ = v5::puback_reason_code::success;
7412  }
7413  else {
7414  // reason_code
7415  yield ep_.process_nbytes(
7416  force_move(spep),
7417  force_move(session_life_keeper),
7418  force_move(remain_buf),
7419  1,
7420  [this]
7421  (auto&&... args ) {
7422  (*this)(std::forward<decltype(args)>(args)...);
7423  }
7424  );
7425  reason_code_ = static_cast<v5::puback_reason_code>(variant_get<buffer>(var)[0]);
7426 
7427  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126
7428  // If the Remaining Length is 0, there is no property length and the value of 0 is used
7429 
7430  if (ep_.remaining_length_ > 0) {
7431  // properties
7432  yield ep_.process_properties(
7433  force_move(spep),
7434  force_move(session_life_keeper),
7435  force_move(remain_buf),
7436  [this]
7437  (auto&&... args ) {
7438  (*this)(std::forward<decltype(args)>(args)...);
7439  }
7440  );
7441  props_ = force_move(variant_get<v5::properties>(var));
7442  }
7443  }
7444  {
7445  LockGuard<Mutex> lck (ep_.store_mtx_);
7446  auto& idx = ep_.store_.template get<tag_packet_id_type>();
7447  auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::puback));
7448  idx.erase(std::get<0>(r), std::get<1>(r));
7449  ep_.pid_man_.release_id(packet_id_);
7450  }
7451  ep_.on_serialize_remove(packet_id_);
7452  switch (ep_.version_) {
7454  if (ep_.on_puback(packet_id_)) {
7455  ep_.on_mqtt_message_processed(
7456  force_move(
7457  std::get<0>(
7458  any_cast<
7459  std::tuple<any, process_type_sp>
7460  >(session_life_keeper)
7461  )
7462  )
7463  );
7464  }
7465  break;
7466  case protocol_version::v5:
7467  if (ep_.on_v5_puback(packet_id_, reason_code_, force_move(props_))) {
7468  ep_.on_mqtt_message_processed(
7469  force_move(
7470  std::get<0>(
7471  any_cast<
7472  std::tuple<any, process_type_sp>
7473  >(session_life_keeper)
7474  )
7475  )
7476  );
7477  }
7478  break;
7479  default:
7480  BOOST_ASSERT(false);
7481  }
7482 
7483 
7484  }
7485  }
7486 
7487  private:
7488  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
7489 
7490  ep_t& ep_;
7491  bool all_read_;
7492 
7493  packet_id_t packet_id_;
7494  v5::puback_reason_code reason_code_;
7495  v5::properties props_;
7496  };
7497  friend struct process_puback;
7498 
7499  // process pubrec
7500 
7501  struct process_pubrec : as::coroutine, std::enable_shared_from_this<process_pubrec> {
7502  using ep_t = this_type;
7503  using ep_t_sp = this_type_sp;
7504  using process_type = process_pubrec;
7505  using process_type_sp = std::shared_ptr<process_type>;
7506 
7507  process_pubrec(
7508  ep_t& ep,
7509  bool all_read
7510  ):ep_{ep},
7511  all_read_{all_read} {
7512  }
7513  void operator()(
7514  ep_t_sp spep,
7515  any&& session_life_keeper,
7516  parse_handler_variant var = std::size_t(0),
7517  buffer remain_buf = buffer()
7518  ) {
7519  reenter(this) {
7520  if (ep_.remaining_length_ < header_len_) {
7521  ep_.call_protocol_error_handlers();
7522  return;
7523  }
7524  // header
7525  yield ep_.process_header(
7526  force_move(spep),
7527  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
7528  all_read_,
7529  header_len_,
7530  [this]
7531  (auto&&... args ) {
7532  (*this)(std::forward<decltype(args)>(args)...);
7533  }
7534  );
7535 
7536  // packet_id
7537  yield ep_.process_packet_id(
7538  force_move(spep),
7539  force_move(session_life_keeper),
7540  force_move(variant_get<buffer>(var)),
7541  [this]
7542  (auto&&... args ) {
7543  (*this)(std::forward<decltype(args)>(args)...);
7544  }
7545  );
7546  packet_id_ = force_move(variant_get<packet_id_t>(var));
7547 
7548  if (ep_.remaining_length_ == 0) {
7549  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
7550  // If the Remaining Length is 0, there is no reason code & property length
7551  // the value of success is used for reason code, the value of 0 is used for property length
7552  reason_code_ = v5::pubrec_reason_code::success;
7553  }
7554  else {
7555  // reason_code
7556  yield ep_.process_nbytes(
7557  force_move(spep),
7558  force_move(session_life_keeper),
7559  force_move(remain_buf),
7560  1,
7561  [this]
7562  (auto&&... args ) {
7563  (*this)(std::forward<decltype(args)>(args)...);
7564  }
7565  );
7566  reason_code_ = static_cast<v5::pubrec_reason_code>(variant_get<buffer>(var)[0]);
7567 
7568  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136
7569  // If the Remaining Length is 0, there is no property length and the value of 0 is used
7570 
7571  if (ep_.remaining_length_ > 0) {
7572  // properties
7573  yield ep_.process_properties(
7574  force_move(spep),
7575  force_move(session_life_keeper),
7576  force_move(remain_buf),
7577  [this]
7578  (auto&&... args ) {
7579  (*this)(std::forward<decltype(args)>(args)...);
7580  }
7581  );
7582  props_ = force_move(variant_get<v5::properties>(var));
7583  }
7584  }
7585  {
7586  LockGuard<Mutex> lck (ep_.store_mtx_);
7587  auto& idx = ep_.store_.template get<tag_packet_id_type>();
7588  auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::pubrec));
7589  idx.erase(std::get<0>(r), std::get<1>(r));
7590  // packet_id shouldn't be erased here.
7591  // It is reused for pubrel/pubcomp.
7592  }
7593  {
7594  auto res =
7595  [&] {
7596  ep_.auto_pub_response(
7597  [&] {
7598  if (ep_.connected_) {
7599  ep_.send_pubrel(
7600  packet_id_,
7601  v5::pubrel_reason_code::success,
7602  v5::properties{},
7603  any{}
7604  );
7605  }
7606  else {
7607  ep_.store_pubrel(
7608  packet_id_,
7610  v5::properties{},
7611  any{}
7612  );
7613  }
7614  },
7615  [&] {
7616  if (ep_.connected_) {
7617  ep_.async_send_pubrel(
7618  packet_id_,
7620  v5::properties{},
7621  any{},
7622  [](auto){}
7623  );
7624  }
7625  else {
7626  ep_.store_pubrel(
7627  packet_id_,
7629  v5::properties{},
7630  any{}
7631  );
7632  }
7633  }
7634  );
7635  };
7636  switch (ep_.version_) {
7638  if (ep_.on_pubrec(packet_id_)) {
7639  res();
7640  ep_.on_mqtt_message_processed(
7641  force_move(
7642  std::get<0>(
7643  any_cast<
7644  std::tuple<any, process_type_sp>
7645  >(session_life_keeper)
7646  )
7647  )
7648  );
7649  }
7650  break;
7651  case protocol_version::v5:
7652  if (ep_.on_v5_pubrec(packet_id_, reason_code_, force_move(props_))) {
7653  res();
7654  ep_.on_mqtt_message_processed(
7655  force_move(
7656  std::get<0>(
7657  any_cast<
7658  std::tuple<any, process_type_sp>
7659  >(session_life_keeper)
7660  )
7661  )
7662  );
7663  }
7664  break;
7665  default:
7666  BOOST_ASSERT(false);
7667  }
7668  }
7669  }
7670  }
7671 
7672  private:
7673  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
7674 
7675  ep_t& ep_;
7676  bool all_read_;
7677 
7678  packet_id_t packet_id_;
7679  v5::pubrec_reason_code reason_code_;
7680  v5::properties props_;
7681  };
7682  friend struct process_pubrec;
7683 
7684  struct process_pubrel : as::coroutine, std::enable_shared_from_this<process_pubrel> {
7685  using ep_t = this_type;
7686  using ep_t_sp = this_type_sp;
7687  using process_type = process_pubrel;
7688  using process_type_sp = std::shared_ptr<process_type>;
7689 
7690  process_pubrel(
7691  ep_t& ep,
7692  bool all_read
7693  ):ep_{ep},
7694  all_read_{all_read} {
7695  }
7696  void operator()(
7697  ep_t_sp spep,
7698  any&& session_life_keeper,
7699  parse_handler_variant var = std::size_t(0),
7700  buffer remain_buf = buffer()
7701  ) {
7702  reenter(this) {
7703  if (ep_.remaining_length_ < header_len_) {
7704  ep_.call_protocol_error_handlers();
7705  return;
7706  }
7707  // header
7708  yield ep_.process_header(
7709  force_move(spep),
7710  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
7711  all_read_,
7712  header_len_,
7713  [this]
7714  (auto&&... args ) {
7715  (*this)(std::forward<decltype(args)>(args)...);
7716  }
7717  );
7718 
7719  // packet_id
7720  yield ep_.process_packet_id(
7721  force_move(spep),
7722  force_move(session_life_keeper),
7723  force_move(variant_get<buffer>(var)),
7724  [this]
7725  (auto&&... args ) {
7726  (*this)(std::forward<decltype(args)>(args)...);
7727  }
7728  );
7729  packet_id_ = force_move(variant_get<packet_id_t>(var));
7730 
7731  if (ep_.remaining_length_ == 0) {
7732  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
7733  // If the Remaining Length is 0, there is no reason code & property length
7734  // the value of success is used for reason code, the value of 0 is used for property length
7735  reason_code_ = v5::pubrel_reason_code::success;
7736  }
7737  else {
7738  // reason_code
7739  yield ep_.process_nbytes(
7740  force_move(spep),
7741  force_move(session_life_keeper),
7742  force_move(remain_buf),
7743  1,
7744  [this]
7745  (auto&&... args ) {
7746  (*this)(std::forward<decltype(args)>(args)...);
7747  }
7748  );
7749  reason_code_ = static_cast<v5::pubrel_reason_code>(variant_get<buffer>(var)[0]);
7750 
7751  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146
7752  // If the Remaining Length is 0, there is no property length and the value of 0 is used
7753 
7754  if (ep_.remaining_length_ > 0) {
7755  // properties
7756  yield ep_.process_properties(
7757  force_move(spep),
7758  force_move(session_life_keeper),
7759  force_move(remain_buf),
7760  [this]
7761  (auto&&... args ) {
7762  (*this)(std::forward<decltype(args)>(args)...);
7763  }
7764  );
7765  props_ = force_move(variant_get<v5::properties>(var));
7766  }
7767  }
7768 
7769  {
7770  auto res =
7771  [&] {
7772  ep_.auto_pub_response(
7773  [&] {
7774  if (ep_.connected_) {
7775  ep_.send_pubcomp(
7776  packet_id_,
7777  v5::pubcomp_reason_code::success,
7778  v5::properties{}
7779  );
7780  }
7781  },
7782  [&] {
7783  if (ep_.connected_) {
7784  ep_.async_send_pubcomp(
7785  packet_id_,
7786  v5::pubcomp_reason_code::success,
7787  v5::properties{},
7788  [](auto){}
7789  );
7790  }
7791  }
7792  );
7793  };
7794  ep_.qos2_publish_handled_.erase(packet_id_);
7795  switch (ep_.version_) {
7796  case protocol_version::v3_1_1:
7797  if (ep_.on_pubrel(packet_id_)) {
7798  res();
7799  ep_.on_mqtt_message_processed(
7800  force_move(
7801  std::get<0>(
7802  any_cast<
7803  std::tuple<any, process_type_sp>
7804  >(session_life_keeper)
7805  )
7806  )
7807  );
7808  }
7809  break;
7810  case protocol_version::v5:
7811  if (ep_.on_v5_pubrel(packet_id_, reason_code_, force_move(props_))) {
7812  res();
7813  ep_.on_mqtt_message_processed(
7814  force_move(
7815  std::get<0>(
7816  any_cast<
7817  std::tuple<any, process_type_sp>
7818  >(session_life_keeper)
7819  )
7820  )
7821  );
7822  }
7823  break;
7824  default:
7825  BOOST_ASSERT(false);
7826  }
7827  }
7828  }
7829  }
7830 
7831  private:
7832  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
7833 
7834  ep_t& ep_;
7835  bool all_read_;
7836 
7837  packet_id_t packet_id_;
7838  v5::pubrel_reason_code reason_code_;
7839  v5::properties props_;
7840  };
7841  friend struct process_pubrel;
7842 
7843  // process pubcomp
7844 
7845  struct process_pubcomp : as::coroutine, std::enable_shared_from_this<process_pubcomp> {
7846  using ep_t = this_type;
7847  using ep_t_sp = this_type_sp;
7848  using process_type = process_pubcomp;
7849  using process_type_sp = std::shared_ptr<process_type>;
7850 
7851  process_pubcomp(
7852  ep_t& ep,
7853  bool all_read
7854  ):ep_{ep},
7855  all_read_{all_read} {
7856  }
7857  void operator()(
7858  ep_t_sp spep,
7859  any&& session_life_keeper,
7860  parse_handler_variant var = std::size_t(0),
7861  buffer remain_buf = buffer()
7862  ) {
7863  reenter(this) {
7864  if (ep_.remaining_length_ < header_len_) {
7865  ep_.call_protocol_error_handlers();
7866  return;
7867  }
7868  // header
7869  yield ep_.process_header(
7870  force_move(spep),
7871  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
7872  all_read_,
7873  header_len_,
7874  [this]
7875  (auto&&... args ) {
7876  (*this)(std::forward<decltype(args)>(args)...);
7877  }
7878  );
7879 
7880  // packet_id
7881  yield ep_.process_packet_id(
7882  force_move(spep),
7883  force_move(session_life_keeper),
7884  force_move(variant_get<buffer>(var)),
7885  [this]
7886  (auto&&... args ) {
7887  (*this)(std::forward<decltype(args)>(args)...);
7888  }
7889  );
7890  packet_id_ = force_move(variant_get<packet_id_t>(var));
7891 
7892  if (ep_.remaining_length_ == 0) {
7893  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
7894  // If the Remaining Length is 0, there is no reason code & property length
7895  // the value of success is used for reason code, the value of 0 is used for property length
7896  reason_code_ = v5::pubcomp_reason_code::success;
7897  }
7898  else {
7899  // reason_code
7900  yield ep_.process_nbytes(
7901  force_move(spep),
7902  force_move(session_life_keeper),
7903  force_move(remain_buf),
7904  1,
7905  [this]
7906  (auto&&... args ) {
7907  (*this)(std::forward<decltype(args)>(args)...);
7908  }
7909  );
7910  reason_code_ = static_cast<v5::pubcomp_reason_code>(variant_get<buffer>(var)[0]);
7911 
7912  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156
7913  // If the Remaining Length is 0, there is no property length and the value of 0 is used
7914 
7915  if (ep_.remaining_length_ > 0) {
7916  // properties
7917  yield ep_.process_properties(
7918  force_move(spep),
7919  force_move(session_life_keeper),
7920  force_move(remain_buf),
7921  [this]
7922  (auto&&... args ) {
7923  (*this)(std::forward<decltype(args)>(args)...);
7924  }
7925  );
7926  props_ = force_move(variant_get<v5::properties>(var));
7927  }
7928  }
7929  {
7930  LockGuard<Mutex> lck (ep_.store_mtx_);
7931  auto& idx = ep_.store_.template get<tag_packet_id_type>();
7932  auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::pubcomp));
7933  idx.erase(std::get<0>(r), std::get<1>(r));
7934  ep_.pid_man_.release_id(packet_id_);
7935  }
7936  ep_.on_serialize_remove(packet_id_);
7937  switch (ep_.version_) {
7938  case protocol_version::v3_1_1:
7939  if (ep_.on_pubcomp(packet_id_)) {
7940  ep_.on_mqtt_message_processed(
7941  force_move(
7942  std::get<0>(
7943  any_cast<
7944  std::tuple<any, process_type_sp>
7945  >(session_life_keeper)
7946  )
7947  )
7948  );
7949  }
7950  break;
7951  case protocol_version::v5:
7952  if (ep_.on_v5_pubcomp(packet_id_, reason_code_, force_move(props_))) {
7953  ep_.on_mqtt_message_processed(
7954  force_move(
7955  std::get<0>(
7956  any_cast<
7957  std::tuple<any, process_type_sp>
7958  >(session_life_keeper)
7959  )
7960  )
7961  );
7962  }
7963  break;
7964  default:
7965  BOOST_ASSERT(false);
7966  }
7967 
7968 
7969  }
7970  }
7971 
7972  private:
7973  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
7974 
7975  ep_t& ep_;
7976  bool all_read_;
7977 
7978  packet_id_t packet_id_;
7979  v5::pubcomp_reason_code reason_code_;
7980  v5::properties props_;
7981  };
7982  friend struct process_pubcomp;
7983 
7984  // process subscribe
7985 
7986  struct process_subscribe : as::coroutine, std::enable_shared_from_this<process_subscribe> {
7987  using ep_t = this_type;
7988  using ep_t_sp = this_type_sp;
7989  using process_type = process_subscribe;
7990  using process_type_sp = std::shared_ptr<process_type>;
7991 
7992  process_subscribe(
7993  ep_t& ep,
7994  bool all_read
7995  ):ep_{ep},
7996  all_read_{all_read} {
7997  }
7998  void operator()(
7999  ep_t_sp spep,
8000  any&& session_life_keeper,
8001  parse_handler_variant var = std::size_t(0),
8002  buffer remain_buf = buffer()
8003  ) {
8004  reenter(this) {
8005  if (ep_.remaining_length_ < header_len_) {
8006  ep_.call_protocol_error_handlers();
8007  return;
8008  }
8009  // header
8010  yield ep_.process_header(
8011  force_move(spep),
8012  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8013  all_read_,
8014  header_len_,
8015  [this]
8016  (auto&&... args ) {
8017  (*this)(std::forward<decltype(args)>(args)...);
8018  }
8019  );
8020 
8021  // packet_id
8022  yield ep_.process_packet_id(
8023  force_move(spep),
8024  force_move(session_life_keeper),
8025  force_move(variant_get<buffer>(var)),
8026  [this]
8027  (auto&&... args ) {
8028  (*this)(std::forward<decltype(args)>(args)...);
8029  }
8030  );
8031  packet_id_ = force_move(variant_get<packet_id_t>(var));
8032 
8033  if (ep_.version_ == protocol_version::v5) {
8034  // properties
8035  yield ep_.process_properties(
8036  force_move(spep),
8037  force_move(session_life_keeper),
8038  force_move(remain_buf),
8039  [this]
8040  (auto&&... args ) {
8041  (*this)(std::forward<decltype(args)>(args)...);
8042  }
8043  );
8044  props_ = force_move(variant_get<v5::properties>(var));
8045  }
8046 
8047  while (true) {
8048  // topic_filter including share_name
8049  yield ep_.process_string(
8050  force_move(spep),
8051  force_move(session_life_keeper),
8052  force_move(remain_buf),
8053  [this]
8054  (auto&&... args ) {
8055  (*this)(std::forward<decltype(args)>(args)...);
8056  }
8057  );
8058  sn_tf_opt_ = parse_shared_subscription(variant_get<buffer>(var));
8059  if (!sn_tf_opt_) {
8060  MQTT_LOG("mqtt_impl", error)
8061  << MQTT_ADD_VALUE(address, &ep_)
8062  << "topic_filter parse error"
8063  << " whole_topic_filter: "
8064  << variant_get<buffer>(var);
8065  ep_.call_protocol_error_handlers();
8066  return;
8067  }
8068 
8069  // subscribe options
8070  yield ep_.process_nbytes(
8071  force_move(spep),
8072  force_move(session_life_keeper),
8073  force_move(remain_buf),
8074  1,
8075  [this]
8076  (auto&&... args ) {
8077  (*this)(std::forward<decltype(args)>(args)...);
8078  }
8079  );
8080  sub_opts_opt_.emplace(static_cast<std::uint8_t>(variant_get<buffer>(var)[0]));
8081  if (sub_opts_opt_.value().get_qos() != qos::at_most_once &&
8082  sub_opts_opt_.value().get_qos() != qos::at_least_once &&
8083  sub_opts_opt_.value().get_qos() != qos::exactly_once) {
8084  ep_.call_bad_message_error_handlers();
8085  return;
8086  }
8087 
8088  entries_.emplace_back(
8089  force_move(sn_tf_opt_.value().share_name),
8090  force_move(sn_tf_opt_.value().topic_filter),
8091  sub_opts_opt_.value()
8092  );
8093 
8094  if (ep_.remaining_length_ == 0) {
8095  switch (ep_.version_) {
8096  case protocol_version::v3_1_1:
8097  if (ep_.on_subscribe(packet_id_, force_move(entries_))) {
8098  ep_.on_mqtt_message_processed(
8099  force_move(
8100  std::get<0>(
8101  any_cast<
8102  std::tuple<any, process_type_sp>
8103  >(session_life_keeper)
8104  )
8105  )
8106  );
8107  }
8108  break;
8109  case protocol_version::v5:
8110  if (ep_.on_v5_subscribe(packet_id_, force_move(entries_), force_move(props_))) {
8111  ep_.on_mqtt_message_processed(
8112  force_move(
8113  std::get<0>(
8114  any_cast<
8115  std::tuple<any, process_type_sp>
8116  >(session_life_keeper)
8117  )
8118  )
8119  );
8120  }
8121  break;
8122  default:
8123  BOOST_ASSERT(false);
8124  }
8125  return;
8126  }
8127  }
8128  }
8129  }
8130 
8131  private:
8132  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8133 
8134  ep_t& ep_;
8135  bool all_read_;
8136 
8137  packet_id_t packet_id_;
8138  v5::properties props_;
8139  optional<share_name_topic_filter> sn_tf_opt_;
8140  optional<subscribe_options> sub_opts_opt_;
8141  std::vector<subscribe_entry> entries_;
8142  };
8143  friend struct process_subscribe;
8144 
8145  // process suback
8146 
8147  struct process_suback : as::coroutine, std::enable_shared_from_this<process_suback> {
8148  using ep_t = this_type;
8149  using ep_t_sp = this_type_sp;
8150  using process_type = process_suback;
8151  using process_type_sp = std::shared_ptr<process_type>;
8152 
8153  process_suback(
8154  ep_t& ep,
8155  bool all_read
8156  ):ep_{ep},
8157  all_read_{all_read} {
8158  }
8159  void operator()(
8160  ep_t_sp spep,
8161  any&& session_life_keeper,
8162  parse_handler_variant var = std::size_t(0),
8163  buffer remain_buf = buffer()
8164  ) {
8165  reenter(this) {
8166  if (ep_.remaining_length_ < header_len_) {
8167  ep_.call_protocol_error_handlers();
8168  return;
8169  }
8170  // header
8171  yield ep_.process_header(
8172  force_move(spep),
8173  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8174  all_read_,
8175  header_len_,
8176  [this]
8177  (auto&&... args ) {
8178  (*this)(std::forward<decltype(args)>(args)...);
8179  }
8180  );
8181 
8182  // packet_id
8183  yield ep_.process_packet_id(
8184  force_move(spep),
8185  force_move(session_life_keeper),
8186  force_move(variant_get<buffer>(var)),
8187  [this]
8188  (auto&&... args ) {
8189  (*this)(std::forward<decltype(args)>(args)...);
8190  }
8191  );
8192  packet_id_ = force_move(variant_get<packet_id_t>(var));
8193 
8194  if (ep_.version_ == protocol_version::v5) {
8195  // properties
8196  yield ep_.process_properties(
8197  force_move(spep),
8198  force_move(session_life_keeper),
8199  force_move(remain_buf),
8200  [this]
8201  (auto&&... args ) {
8202  (*this)(std::forward<decltype(args)>(args)...);
8203  }
8204  );
8205  props_ = force_move(variant_get<v5::properties>(var));
8206  }
8207 
8208  // suback reason codes
8209  yield ep_.process_nbytes(
8210  force_move(spep),
8211  force_move(session_life_keeper),
8212  force_move(remain_buf),
8213  ep_.remaining_length_,
8214  [this]
8215  (auto&&... args ) {
8216  (*this)(std::forward<decltype(args)>(args)...);
8217  }
8218  );
8219  {
8220  LockGuard<Mutex> lck_store (ep_.store_mtx_);
8221  LockGuard<Mutex> lck_sub_unsub (ep_.sub_unsub_inflight_mtx_);
8222  ep_.pid_man_.release_id(packet_id_);
8223  ep_.sub_unsub_inflight_.erase(packet_id_);
8224  }
8225  switch (ep_.version_) {
8226  case protocol_version::v3_1_1:
8227  {
8228  // TODO: We can avoid an allocation by casting the raw bytes of the
8229  // MQTT_NS::buffer that is being parsed, and instead call the suback
8230  // handler with an std::span and the MQTT_NS::buffer (as lifekeeper)
8231  std::vector<suback_return_code> results;
8232  auto& body = variant_get<buffer>(var);
8233  results.resize(body.size());
8234  std::transform(
8235  body.begin(),
8236  body.end(),
8237  results.begin(),
8238  // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180880
8239  // The SUBACK Packet sent by the Server to the Client MUST
8240  // contain a return code for each Topic Filter/QoS pair.
8241  // This return code MUST either show the maximum QoS that
8242  // was granted for that Subscription or indicate that the
8243  // subscription failed [MQTT-3.8.4-5].
8244  [&](auto const& e) -> suback_return_code {
8245  return static_cast<suback_return_code>(e);
8246  }
8247  );
8248  if (ep_.on_suback(packet_id_, force_move(results))) {
8249  ep_.on_mqtt_message_processed(
8250  force_move(
8251  std::get<0>(
8252  any_cast<
8253  std::tuple<any, process_type_sp>
8254  >(session_life_keeper)
8255  )
8256  )
8257  );
8258  }
8259  break;
8260  }
8261  case protocol_version::v5:
8262  {
8263  // TODO: We can avoid an allocation by casting the raw bytes of the
8264  // MQTT_NS::buffer that is being parsed, and instead call the suback
8265  // handler with an std::span and the MQTT_NS::buffer (as lifekeeper)
8266  std::vector<v5::suback_reason_code> reasons;
8267  auto& body = variant_get<buffer>(var);
8268  reasons.resize(body.size());
8269  std::transform(
8270  body.begin(),
8271  body.end(),
8272  reasons.begin(),
8273  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901170
8274  // The SUBACK packet sent by the Server to the Client MUST
8275  // contain a Reason Code for each Topic Filter/Subscription
8276  // Option pair [MQTT-3.8.4-6].
8277  // This Reason Code MUST either show the maximum QoS that
8278  // was granted for that Subscription or indicate that the
8279  // subscription failed [MQTT-3.8.4-7].
8280  [&](auto const& e) {
8281  return static_cast<v5::suback_reason_code>(e);
8282  }
8283  );
8284  if (ep_.on_v5_suback(packet_id_, force_move(reasons), force_move(props_))) {
8285  ep_.on_mqtt_message_processed(
8286  force_move(
8287  std::get<0>(
8288  any_cast<
8289  std::tuple<any, process_type_sp>
8290  >(session_life_keeper)
8291  )
8292  )
8293  );
8294  }
8295  break;
8296  }
8297  default:
8298  BOOST_ASSERT(false);
8299  }
8300  }
8301  }
8302 
8303  private:
8304  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8305 
8306  ep_t& ep_;
8307  bool all_read_;
8308 
8309  packet_id_t packet_id_;
8310  v5::properties props_;
8311  };
8312  friend struct process_suback;
8313 
8314  // process unsubscribe
8315 
8316  struct process_unsubscribe : as::coroutine, std::enable_shared_from_this<process_unsubscribe> {
8317  using ep_t = this_type;
8318  using ep_t_sp = this_type_sp;
8319  using process_type = process_unsubscribe;
8320  using process_type_sp = std::shared_ptr<process_type>;
8321 
8322  process_unsubscribe(
8323  ep_t& ep,
8324  bool all_read
8325  ):ep_{ep},
8326  all_read_{all_read} {
8327  }
8328  void operator()(
8329  ep_t_sp spep,
8330  any&& session_life_keeper,
8331  parse_handler_variant var = std::size_t(0),
8332  buffer remain_buf = buffer()
8333  ) {
8334  reenter(this) {
8335  if (ep_.remaining_length_ < header_len_) {
8336  ep_.call_protocol_error_handlers();
8337  return;
8338  }
8339  // header
8340  yield ep_.process_header(
8341  force_move(spep),
8342  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8343  all_read_,
8344  header_len_,
8345  [this]
8346  (auto&&... args ) {
8347  (*this)(std::forward<decltype(args)>(args)...);
8348  }
8349  );
8350 
8351  // packet_id
8352  yield ep_.process_packet_id(
8353  force_move(spep),
8354  force_move(session_life_keeper),
8355  force_move(variant_get<buffer>(var)),
8356  [this]
8357  (auto&&... args ) {
8358  (*this)(std::forward<decltype(args)>(args)...);
8359  }
8360  );
8361  packet_id_ = force_move(variant_get<packet_id_t>(var));
8362 
8363  if (ep_.version_ == protocol_version::v5) {
8364  // properties
8365  yield ep_.process_properties(
8366  force_move(spep),
8367  force_move(session_life_keeper),
8368  force_move(remain_buf),
8369  [this]
8370  (auto&&... args ) {
8371  (*this)(std::forward<decltype(args)>(args)...);
8372  }
8373  );
8374  props_ = force_move(variant_get<v5::properties>(var));
8375  }
8376 
8377  while (true) {
8378  // topic_filter including share_name
8379  yield ep_.process_string(
8380  force_move(spep),
8381  force_move(session_life_keeper),
8382  force_move(remain_buf),
8383  [this]
8384  (auto&&... args ) {
8385  (*this)(std::forward<decltype(args)>(args)...);
8386  }
8387  );
8388  sn_tf_opt_ = parse_shared_subscription(variant_get<buffer>(var));
8389  if (!sn_tf_opt_) {
8390  MQTT_LOG("mqtt_impl", error)
8391  << MQTT_ADD_VALUE(address, &ep_)
8392  << "topic_filter parse error"
8393  << " whole_topic_filter: "
8394  << variant_get<buffer>(var);
8395  ep_.call_protocol_error_handlers();
8396  return;
8397  }
8398 
8399  entries_.emplace_back(
8400  force_move(sn_tf_opt_.value().share_name),
8401  force_move(sn_tf_opt_.value().topic_filter)
8402  );
8403 
8404  if (ep_.remaining_length_ == 0) {
8405  switch (ep_.version_) {
8406  case protocol_version::v3_1_1:
8407  if (ep_.on_unsubscribe(packet_id_, force_move(entries_))) {
8408  ep_.on_mqtt_message_processed(
8409  force_move(
8410  std::get<0>(
8411  any_cast<
8412  std::tuple<any, process_type_sp>
8413  >(session_life_keeper)
8414  )
8415  )
8416  );
8417  }
8418  break;
8419  case protocol_version::v5:
8420  if (ep_.on_v5_unsubscribe(packet_id_, force_move(entries_), force_move(props_))) {
8421  ep_.on_mqtt_message_processed(
8422  force_move(
8423  std::get<0>(
8424  any_cast<
8425  std::tuple<any, process_type_sp>
8426  >(session_life_keeper)
8427  )
8428  )
8429  );
8430  }
8431  break;
8432  default:
8433  BOOST_ASSERT(false);
8434  }
8435  return;
8436  }
8437  }
8438  }
8439  }
8440 
8441  private:
8442  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8443 
8444  ep_t& ep_;
8445  bool all_read_;
8446 
8447  packet_id_t packet_id_;
8448  v5::properties props_;
8449  optional<share_name_topic_filter> sn_tf_opt_;
8450  std::vector<unsubscribe_entry> entries_;
8451  };
8452  friend struct process_unsubscribe;
8453 
8454  // process unsuback
8455 
8456  struct process_unsuback : as::coroutine, std::enable_shared_from_this<process_unsuback> {
8457  using ep_t = this_type;
8458  using ep_t_sp = this_type_sp;
8459  using process_type = process_unsuback;
8460  using process_type_sp = std::shared_ptr<process_type>;
8461 
8462  process_unsuback(
8463  ep_t& ep,
8464  bool all_read
8465  ):ep_{ep},
8466  all_read_{all_read} {
8467  }
8468  void operator()(
8469  ep_t_sp spep,
8470  any&& session_life_keeper,
8471  parse_handler_variant var = std::size_t(0),
8472  buffer remain_buf = buffer()
8473  ) {
8474  reenter(this) {
8475  if (ep_.remaining_length_ < header_len_) {
8476  ep_.call_protocol_error_handlers();
8477  return;
8478  }
8479  // header
8480  yield ep_.process_header(
8481  force_move(spep),
8482  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8483  all_read_,
8484  header_len_,
8485  [this]
8486  (auto&&... args ) {
8487  (*this)(std::forward<decltype(args)>(args)...);
8488  }
8489  );
8490 
8491  // packet_id
8492  yield ep_.process_packet_id(
8493  force_move(spep),
8494  force_move(session_life_keeper),
8495  force_move(variant_get<buffer>(var)),
8496  [this]
8497  (auto&&... args ) {
8498  (*this)(std::forward<decltype(args)>(args)...);
8499  }
8500  );
8501  packet_id_ = force_move(variant_get<packet_id_t>(var));
8502 
8503  if (ep_.version_ == protocol_version::v5) {
8504  // properties
8505  yield ep_.process_properties(
8506  force_move(spep),
8507  force_move(session_life_keeper),
8508  force_move(remain_buf),
8509  [this]
8510  (auto&&... args ) {
8511  (*this)(std::forward<decltype(args)>(args)...);
8512  }
8513  );
8514  props_ = force_move(variant_get<v5::properties>(var));
8515 
8516  // unsuback reason codes
8517  yield ep_.process_nbytes(
8518  force_move(spep),
8519  force_move(session_life_keeper),
8520  force_move(remain_buf),
8521  ep_.remaining_length_,
8522  [this]
8523  (auto&&... args ) {
8524  (*this)(std::forward<decltype(args)>(args)...);
8525  }
8526  );
8527  auto body = variant_get<buffer>(var);
8528  reasons_.resize(body.size());
8529  std::transform(
8530  body.begin(),
8531  body.end(),
8532  reasons_.begin(),
8533  [&](auto const& e) {
8534  return static_cast<v5::unsuback_reason_code>(e);
8535  }
8536  );
8537  }
8538  {
8539  LockGuard<Mutex> lck_store (ep_.store_mtx_);
8540  LockGuard<Mutex> lck_sub_unsub (ep_.sub_unsub_inflight_mtx_);
8541  ep_.pid_man_.release_id(packet_id_);
8542  ep_.sub_unsub_inflight_.erase(packet_id_);
8543  }
8544  switch (ep_.version_) {
8545  case protocol_version::v3_1_1:
8546  if (ep_.on_unsuback(packet_id_)) {
8547  ep_.on_mqtt_message_processed(
8548  force_move(
8549  std::get<0>(
8550  any_cast<
8551  std::tuple<any, process_type_sp>
8552  >(session_life_keeper)
8553  )
8554  )
8555  );
8556  }
8557  break;
8558  case protocol_version::v5:
8559  if (ep_.on_v5_unsuback(packet_id_, force_move(reasons_), force_move(props_))) {
8560  ep_.on_mqtt_message_processed(
8561  force_move(
8562  std::get<0>(
8563  any_cast<
8564  std::tuple<any, process_type_sp>
8565  >(session_life_keeper)
8566  )
8567  )
8568  );
8569  }
8570  break;
8571  default:
8572  BOOST_ASSERT(false);
8573  }
8574  }
8575  }
8576 
8577  private:
8578  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8579 
8580  ep_t& ep_;
8581  bool all_read_;
8582 
8583  packet_id_t packet_id_;
8584  v5::properties props_;
8585  std::vector<v5::unsuback_reason_code> reasons_;
8586  };
8587  friend struct process_unsuback;
8588 
8589  // process pingreq
8590 
8591  void process_pingreq(
8592  any session_life_keeper
8593  ) {
8594  static constexpr std::size_t header_len = 0;
8595 
8596  if (remaining_length_ != header_len) {
8597  call_protocol_error_handlers();
8598  return;
8599  }
8600  if (on_pingreq()) {
8601  on_mqtt_message_processed(force_move(session_life_keeper));
8602  }
8603  }
8604 
8605  // process pingresp
8606 
8607  void process_pingresp(
8608  any session_life_keeper
8609  ) {
8610  static constexpr std::size_t header_len = 0;
8611 
8612  if (remaining_length_ != header_len) {
8613  call_protocol_error_handlers();
8614  return;
8615  }
8616  if (on_pingresp()) {
8617  on_mqtt_message_processed(force_move(session_life_keeper));
8618  }
8619  if (pingresp_timeout_ != std::chrono::steady_clock::duration::zero()) tim_pingresp_.cancel();
8620  }
8621 
8622  // process disconnect
8623 
8624  struct process_disconnect : as::coroutine, std::enable_shared_from_this<process_disconnect> {
8625  using ep_t = this_type;
8626  using ep_t_sp = this_type_sp;
8627  using process_type = process_disconnect;
8628  using process_type_sp = std::shared_ptr<process_type>;
8629 
8630  process_disconnect(
8631  ep_t& ep,
8632  bool all_read
8633  ):ep_{ep},
8634  all_read_{all_read} {
8635  }
8636  void operator()(
8637  ep_t_sp spep,
8638  any&& session_life_keeper,
8639  parse_handler_variant var = std::size_t(0),
8640  buffer remain_buf = buffer()
8641  ) {
8642  reenter(this) {
8643  if (ep_.remaining_length_ > 0) {
8644  if (ep_.version_ != protocol_version::v5) {
8645  ep_.call_protocol_error_handlers();
8646  return;
8647  }
8648 
8649  // header
8650  yield ep_.process_header(
8651  force_move(spep),
8652  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8653  all_read_,
8654  header_len_,
8655  [this]
8656  (auto&&... args ) {
8657  (*this)(std::forward<decltype(args)>(args)...);
8658  }
8659  );
8660 
8661  // reason_code
8662  yield ep_.process_nbytes(
8663  force_move(spep),
8664  force_move(session_life_keeper),
8665  force_move(variant_get<buffer>(var)),
8666  1,
8667  [this]
8668  (auto&&... args ) {
8669  (*this)(std::forward<decltype(args)>(args)...);
8670  }
8671  );
8672  reason_code_ = static_cast<v5::disconnect_reason_code>(variant_get<buffer>(var)[0]);
8673 
8674  // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901210
8675  // If the Remaining Length is 0, there is no property length and the value of 0 is used
8676  if (ep_.remaining_length_ > 0) {
8677  yield ep_.process_properties(
8678  force_move(spep),
8679  force_move(session_life_keeper),
8680  force_move(remain_buf),
8681  [this]
8682  (auto&&... args ) {
8683  (*this)(std::forward<decltype(args)>(args)...);
8684  }
8685  );
8686  props_ = force_move(variant_get<v5::properties>(var));
8687  }
8688  switch (ep_.version_) {
8689  case protocol_version::v3_1_1:
8690  ep_.on_disconnect();
8691  break;
8692  case protocol_version::v5:
8693  ep_.on_v5_disconnect(reason_code_, force_move(props_));
8694  break;
8695  default:
8696  BOOST_ASSERT(false);
8697  }
8698  ep_.shutdown(*ep_.socket_);
8699  ep_.on_mqtt_message_processed(
8700  force_move(
8701  std::get<0>(
8702  any_cast<
8703  std::tuple<any, process_type_sp>
8704  >(session_life_keeper)
8705  )
8706  )
8707  );
8708  return;
8709  }
8710  switch (ep_.version_) {
8711  case protocol_version::v3_1_1:
8712  ep_.on_disconnect();
8713  break;
8714  case protocol_version::v5:
8715  ep_.on_v5_disconnect(reason_code_, force_move(props_));
8716  break;
8717  default:
8718  BOOST_ASSERT(false);
8719  }
8720  ep_.shutdown(*ep_.socket_);
8721  ep_.on_mqtt_message_processed(
8722  force_move(
8723  session_life_keeper
8724  )
8725  );
8726  }
8727  }
8728 
8729  private:
8730  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8731 
8732  ep_t& ep_;
8733  bool all_read_;
8734 
8735  v5::disconnect_reason_code reason_code_;
8736  v5::properties props_;
8737  };
8738  friend struct process_disconnect;
8739 
8740  // process auth
8741 
8742  struct process_auth : as::coroutine, std::enable_shared_from_this<process_auth> {
8743  using ep_t = this_type;
8744  using ep_t_sp = this_type_sp;
8745  using process_type = process_auth;
8746  using process_type_sp = std::shared_ptr<process_type>;
8747 
8748  process_auth(
8749  ep_t& ep,
8750  bool all_read
8751  ):ep_{ep},
8752  all_read_{all_read} {
8753  }
8754  void operator()(
8755  ep_t_sp spep,
8756  any&& session_life_keeper,
8757  parse_handler_variant var = std::size_t(0),
8758  buffer remain_buf = buffer()
8759  ) {
8760  reenter(this) {
8761  if (ep_.version_ != protocol_version::v5) {
8762  ep_.call_protocol_error_handlers();
8763  return;
8764  }
8765  if (ep_.remaining_length_ > 0) {
8766  // header
8767  yield ep_.process_header(
8768  force_move(spep),
8769  std::make_tuple(force_move(session_life_keeper), this->shared_from_this()),
8770  all_read_,
8771  header_len_,
8772  [this]
8773  (auto&&... args ) {
8774  (*this)(std::forward<decltype(args)>(args)...);
8775  }
8776  );
8777 
8778  // reason_code
8779  yield ep_.process_nbytes(
8780  force_move(spep),
8781  force_move(session_life_keeper),
8782  force_move(variant_get<buffer>(var)),
8783  1,
8784  [this]
8785  (auto&&... args ) {
8786  (*this)(std::forward<decltype(args)>(args)...);
8787  }
8788  );
8789  reason_code_ = static_cast<v5::auth_reason_code>(variant_get<buffer>(var)[0]);
8790 
8791  yield ep_.process_properties(
8792  force_move(spep),
8793  force_move(session_life_keeper),
8794  force_move(remain_buf),
8795  [this]
8796  (auto&&... args ) {
8797  (*this)(std::forward<decltype(args)>(args)...);
8798  }
8799  );
8800  props_ = force_move(variant_get<v5::properties>(var));
8801  BOOST_ASSERT(ep_.version_ == protocol_version::v5);
8802  if (ep_.on_v5_auth(reason_code_, force_move(props_))) {
8803  ep_.on_mqtt_message_processed(
8804  force_move(
8805  std::get<0>(
8806  any_cast<
8807  std::tuple<any, process_type_sp>
8808  >(session_life_keeper)
8809  )
8810  )
8811  );
8812  }
8813  return;
8814  }
8815  BOOST_ASSERT(ep_.version_ == protocol_version::v5);
8816  if (ep_.on_v5_auth(reason_code_, force_move(props_))) {
8817  ep_.on_mqtt_message_processed(
8818  force_move(
8819  session_life_keeper
8820  )
8821  );
8822  }
8823  }
8824  }
8825 
8826  private:
8827  static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id
8828 
8829  this_type& ep_;
8830  bool all_read_;
8831 
8832  v5::auth_reason_code reason_code_;
8833  v5::properties props_;
8834  };
8835  friend struct process_auth;
8836 
8837  template <typename F, typename AF>
8838  void auto_pub_response(F const& f, AF const& af) {
8839  if (auto_pub_response_) {
8840  if (auto_pub_response_async_) af();
8841  else f();
8842  }
8843  }
8844 
8845  // Blocking senders.
8846  void send_connect(
8847  buffer client_id,
8848  optional<buffer> user_name,
8849  optional<buffer> password,
8850  optional<will> w,
8851  std::uint16_t keep_alive_sec,
8852  v5::properties props
8853  ) {
8854  switch (version_) {
8855  case protocol_version::v3_1_1:
8856  do_sync_write(
8857  v3_1_1::connect_message(
8858  keep_alive_sec,
8859  force_move(client_id),
8860  clean_session(),
8861  force_move(w),
8862  force_move(user_name),
8863  force_move(password)
8864  )
8865  );
8866  break;
8867  case protocol_version::v5:
8868  update_topic_alias_maximum_recv(props);
8869  do_sync_write(
8870  v5::connect_message(
8871  keep_alive_sec,
8872  force_move(client_id),
8873  clean_start(),
8874  force_move(w),
8875  force_move(user_name),
8876  force_move(password),
8877  force_move(props)
8878  )
8879  );
8880  break;
8881  default:
8882  BOOST_ASSERT(false);
8883  break;
8884  }
8885  }
8886 
8887  void send_connack(
8888  bool session_present,
8889  variant<connect_return_code, v5::connect_reason_code> reason_code,
8890  v5::properties props
8891  ) {
8892  switch (version_) {
8893  case protocol_version::v3_1_1:
8894  do_sync_write(
8895  v3_1_1::connack_message(
8896  session_present,
8897  variant_get<connect_return_code>(reason_code)
8898  )
8899  );
8900  break;
8901  case protocol_version::v5:
8902  update_topic_alias_maximum_recv(props);
8903  do_sync_write(
8904  v5::connack_message(
8905  session_present,
8906  variant_get<v5::connect_reason_code>(reason_code),
8907  force_move(props)
8908  )
8909  );
8910  break;
8911  default:
8912  BOOST_ASSERT(false);
8913  break;
8914  }
8915  }
8916 
8917  template <typename PublishMessage>
8918  std::enable_if_t<
8919  std::is_same<
8920  PublishMessage,
8921  v5::basic_publish_message<PacketIdBytes>
8922  >::value
8923  >
8924  store_topic_alias(
8925  PublishMessage& msg,
8926  any& life_keeper
8927  ) {
8928  if (msg.topic().empty()) {
8929  // Recover topic alias for store
8930  if (auto ta_opt = get_topic_alias_from_props(msg.props())) {
8931  LockGuard<Mutex> lck (topic_alias_send_mtx_);
8932  std::string t;
8933  if (topic_alias_send_) t = topic_alias_send_.value().find(ta_opt.value());
8934  if (t.empty()) {
8935  MQTT_LOG("mqtt_impl", error)
8936  << MQTT_ADD_VALUE(address, this)
8937  << "publish topic_name is empty, topic alias " << ta_opt.value()
8938  << " is not registered." ;
8939  throw protocol_error();
8940  }
8941  else {
8942  MQTT_LOG("mqtt_impl", trace)
8943  << MQTT_ADD_VALUE(address, this)
8944  << "topia alias : " << t << " - " << ta_opt.value() << " is recovered for store." ;
8945  auto topic_name_buf = allocate_buffer(t);
8946  msg.set_topic_name(as::buffer(topic_name_buf));
8947  life_keeper = std::make_tuple(force_move(life_keeper), force_move(topic_name_buf));
8948  }
8949  }
8950  else {
8951  MQTT_LOG("mqtt_impl", error)
8952  << MQTT_ADD_VALUE(address, this)
8953  << "publish topic_name is empty, no topic alias set.";
8954  throw protocol_error();
8955  }
8956  }
8957  msg.remove_prop(v5::property::id::topic_alias);
8958  }
8959 
8960  template <typename PublishMessage>
8961  std::enable_if_t<
8962  !std::is_same<
8963  PublishMessage,
8964  v5::basic_publish_message<PacketIdBytes>
8965  >::value
8966  >
8967  store_topic_alias(PublishMessage&, any&) {}
8968 
8969  template <typename PublishMessage>
8970  std::enable_if_t<
8971  std::is_same<
8972  PublishMessage,
8973  v5::basic_publish_message<PacketIdBytes>
8974  >::value
8975  >
8976  apply_topic_alias(PublishMessage& msg, any& life_keeper, bool checked) {
8977  auto clear_topic_name_and_add_topic_alias =
8978  [&](topic_alias_t ta) {
8979  auto topic_name_buf = buffer();
8980  msg.set_topic_name(as::buffer(topic_name_buf));
8981  life_keeper = std::make_tuple(force_move(life_keeper), force_move(topic_name_buf));
8982  msg.add_prop(v5::property::topic_alias(ta));
8983  };
8984 
8985  if (msg.topic().empty()) {
8986  if (checked) return;
8987 
8988  // Recover topic alias for store
8989  if (auto ta_opt = get_topic_alias_from_props(msg.props())) {
8990  LockGuard<Mutex> lck (topic_alias_send_mtx_);
8991  std::string t;
8992  if (topic_alias_send_) t = topic_alias_send_.value().find(ta_opt.value());
8993  if (t.empty()) {
8994  MQTT_LOG("mqtt_impl", error)
8995  << MQTT_ADD_VALUE(address, this)
8996  << "publish topic_name is empty, topic alias " << ta_opt.value()
8997  << " is not registered." ;
8998  throw protocol_error();
8999  }
9000  }
9001  else {
9002  MQTT_LOG("mqtt_impl", error)
9003  << MQTT_ADD_VALUE(address, this)
9004  << "publish topic_name is empty, no topic alias set.";
9005  throw protocol_error();
9006  }
9007  }
9008  else {
9009  if (auto ta_opt = get_topic_alias_from_props(msg.props())) {
9010  MQTT_LOG("mqtt_impl", trace)
9011  << MQTT_ADD_VALUE(address, this)
9012  << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is registered." ;
9013  LockGuard<Mutex> lck (topic_alias_send_mtx_);
9014  if (topic_alias_send_) {
9015  topic_alias_send_.value().insert_or_update(
9016  msg.topic(),
9017  ta_opt.value()
9018  );
9019  }
9020  }
9021  else if (auto_map_topic_alias_send_) {
9022  LockGuard<Mutex> lck (topic_alias_send_mtx_);
9023  if (topic_alias_send_) {
9024  auto lru_ta = topic_alias_send_.value().get_lru_alias();
9025  if (auto ta_opt = topic_alias_send_.value().find(msg.topic())) {
9026  MQTT_LOG("mqtt_impl", trace)
9027  << MQTT_ADD_VALUE(address, this)
9028  << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is found." ;
9029  topic_alias_send_.value().insert_or_update(msg.topic(), ta_opt.value()); // update ts
9030  clear_topic_name_and_add_topic_alias(ta_opt.value());
9031  }
9032  else {
9033  topic_alias_send_.value().insert_or_update(msg.topic(), lru_ta); // remap topic alias
9034  msg.add_prop(v5::property::topic_alias(lru_ta));
9035  }
9036  }
9037  }
9038  else if (auto_replace_topic_alias_send_) {
9039  LockGuard<Mutex> lck (topic_alias_send_mtx_);
9040  if (topic_alias_send_) {
9041  if (auto ta_opt = topic_alias_send_.value().find(msg.topic())) {
9042  MQTT_LOG("mqtt_impl", trace)
9043  << MQTT_ADD_VALUE(address, this)
9044  << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is found." ;
9045  topic_alias_send_.value().insert_or_update(msg.topic(), ta_opt.value()); // update ts
9046  clear_topic_name_and_add_topic_alias(ta_opt.value());
9047  }
9048  }
9049  }
9050  }
9051  }
9052 
9053  template <typename PublishMessage>
9054  std::enable_if_t<
9055  !std::is_same<
9056  PublishMessage,
9057  v5::basic_publish_message<PacketIdBytes>
9058  >::value
9059  >
9060  apply_topic_alias(PublishMessage&, any&, bool) {}
9061 
9062  template <typename PublishMessage, typename SerializePublish>
9063  void preprocess_publish_message(
9064  PublishMessage& msg,
9065  any life_keeper,
9066  SerializePublish const& serialize_publish,
9067  bool register_pid = false
9068  ) {
9069  auto qos_value = msg.get_qos();
9070  bool checked = false;
9071  if (qos_value == qos::at_least_once || qos_value == qos::exactly_once) {
9072  auto store_msg = msg;
9073  store_topic_alias(store_msg, life_keeper);
9074  checked = true;
9075  store_msg.set_dup(true);
9076  auto packet_id = store_msg.packet_id();
9077 
9078  LockGuard<Mutex> lck (store_mtx_);
9079  if (register_pid) {
9080  auto ret = pid_man_.register_id(packet_id);
9081  (void)ret;
9082  BOOST_ASSERT(ret);
9083  }
9084  store_.emplace(
9085  packet_id,
9086  qos_value == qos::at_least_once
9087  ? control_packet_type::puback
9088  : control_packet_type::pubrec,
9089  store_msg,
9090  force_move(life_keeper)
9091  );
9092  (this->*serialize_publish)(force_move(store_msg));
9093  }
9094  apply_topic_alias(msg, life_keeper, checked);
9095  }
9096 
9097  template <typename ConstBufferSequence>
9098  typename std::enable_if<
9099  as::is_const_buffer_sequence<ConstBufferSequence>::value
9100  >::type
9101  send_publish(
9102  packet_id_t packet_id,
9103  as::const_buffer topic_name,
9104  ConstBufferSequence payloads,
9105  publish_options pubopts,
9106  v5::properties props,
9107  any life_keeper) {
9108 
9109  auto do_send_publish =
9110  [&](auto msg, auto const& serialize_publish) {
9111  preprocess_publish_message(
9112  msg,
9113  life_keeper,
9114  serialize_publish
9115  );
9116  do_sync_write(force_move(msg));
9117  };
9118 
9119  switch (version_) {
9120  case protocol_version::v3_1_1:
9121  do_send_publish(
9122  v3_1_1::basic_publish_message<PacketIdBytes>(
9123  packet_id,
9124  topic_name,
9125  force_move(payloads),
9126  pubopts
9127  ),
9128  &endpoint::on_serialize_publish_message
9129  );
9130  break;
9131  case protocol_version::v5:
9132  do_send_publish(
9133  v5::basic_publish_message<PacketIdBytes>(
9134  packet_id,
9135  topic_name,
9136  force_move(payloads),
9137  pubopts,
9138  force_move(props)
9139  ),
9140  &endpoint::on_serialize_v5_publish_message
9141  );
9142  break;
9143  default:
9144  BOOST_ASSERT(false);
9145  break;
9146  }
9147  }
9148 
9149  void send_puback(
9150  packet_id_t packet_id,
9151  v5::puback_reason_code reason,
9152  v5::properties props
9153  ) {
9154  switch (version_) {
9155  case protocol_version::v3_1_1:
9156  do_sync_write(v3_1_1::basic_puback_message<PacketIdBytes>(packet_id));
9157  break;
9158  case protocol_version::v5:
9159  do_sync_write(v5::basic_puback_message<PacketIdBytes>(packet_id, reason, force_move(props)));
9160  break;
9161  default:
9162  BOOST_ASSERT(false);
9163  break;
9164  }
9165 
9166  on_pub_res_sent(packet_id);
9167  }
9168 
9169  void send_pubrec(
9170  packet_id_t packet_id,
9171  v5::pubrec_reason_code reason,
9172  v5::properties props
9173  ) {
9174  switch (version_) {
9175  case protocol_version::v3_1_1:
9176  do_sync_write(v3_1_1::basic_pubrec_message<PacketIdBytes>(packet_id));
9177  break;
9178  case protocol_version::v5:
9179  do_sync_write(v5::basic_pubrec_message<PacketIdBytes>(packet_id, reason, force_move(props)));
9180  break;
9181  default:
9182  BOOST_ASSERT(false);
9183  break;
9184  }
9185  }
9186 
9187  void send_pubrel(
9188  packet_id_t packet_id,
9189  v5::pubrel_reason_code reason,
9190  v5::properties props,
9191  any life_keeper
9192  ) {
9193 
9194  auto impl =
9195  [&](auto msg, auto const& serialize) {
9196  {
9197  LockGuard<Mutex> lck (store_mtx_);
9198 
9199  // insert if not registerd (start from pubrel sending case)
9200  pid_man_.register_id(packet_id);
9201 
9202  auto ret = store_.emplace(
9203  packet_id,
9204  control_packet_type::pubcomp,
9205  msg,
9206  force_move(life_keeper)
9207  );
9208  // publish store is erased when pubrec is received.
9209  // pubrel store is erased when pubcomp is received.
9210  // If invalid client send pubrec twice with the same packet id,
9211  // then send corresponding pubrel twice is a possible client/server
9212  // implementation.
9213  // In this case, overwrite store_.
9214  if (!ret.second) {
9215  MQTT_LOG("mqtt_impl", warning)
9216  << MQTT_ADD_VALUE(address, this)
9217  << "overwrite pubrel"
9218  << " packet_id:" << packet_id;
9219  store_.modify(
9220  ret.first,
9221  [&] (auto& e) {
9222  e = store(
9223  packet_id,
9224  control_packet_type::pubcomp,
9225  msg,
9226  life_keeper
9227  );
9228  }
9229  );
9230  }
9231  }
9232 
9233  (this->*serialize)(msg);
9234  do_sync_write(force_move(msg));
9235  };
9236 
9237  switch (version_) {
9238  case protocol_version::v3_1_1:
9239  impl(
9240  v3_1_1::basic_pubrel_message<PacketIdBytes>(packet_id),
9241  &endpoint::on_serialize_pubrel_message
9242  );
9243  break;
9244  case protocol_version::v5:
9245  impl(
9246  v5::basic_pubrel_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9247  &endpoint::on_serialize_v5_pubrel_message
9248  );
9249  break;
9250  default:
9251  BOOST_ASSERT(false);
9252  break;
9253  }
9254  }
9255 
9256  void store_pubrel(
9257  packet_id_t packet_id,
9258  v5::pubrel_reason_code reason,
9259  v5::properties props,
9260  any life_keeper
9261  ) {
9262 
9263  auto impl =
9264  [&](auto msg, auto const& serialize) {
9265  {
9266  LockGuard<Mutex> lck (store_mtx_);
9267 
9268  // insert if not registerd (start from pubrel sending case)
9269  pid_man_.register_id(packet_id);
9270 
9271  auto ret = store_.emplace(
9272  packet_id,
9273  control_packet_type::pubcomp,
9274  msg,
9275  force_move(life_keeper)
9276  );
9277  (void)ret;
9278  BOOST_ASSERT(ret.second);
9279  }
9280 
9281  (this->*serialize)(msg);
9282  };
9283 
9284  switch (version_) {
9285  case protocol_version::v3_1_1:
9286  impl(
9287  v3_1_1::basic_pubrel_message<PacketIdBytes>(packet_id),
9288  &endpoint::on_serialize_pubrel_message
9289  );
9290  break;
9291  case protocol_version::v5:
9292  impl(
9293  v5::basic_pubrel_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9294  &endpoint::on_serialize_v5_pubrel_message
9295  );
9296  break;
9297  default:
9298  BOOST_ASSERT(false);
9299  break;
9300  }
9301  }
9302 
9303  void send_pubcomp(
9304  packet_id_t packet_id,
9305  v5::pubcomp_reason_code reason,
9306  v5::properties props
9307  ) {
9308  switch (version_) {
9309  case protocol_version::v3_1_1:
9310  do_sync_write(v3_1_1::basic_pubcomp_message<PacketIdBytes>(packet_id));
9311  break;
9312  case protocol_version::v5:
9313  do_sync_write(v5::basic_pubcomp_message<PacketIdBytes>(packet_id, reason, force_move(props)));
9314  break;
9315  default:
9316  BOOST_ASSERT(false);
9317  break;
9318  }
9319 
9320  on_pub_res_sent(packet_id);
9321  }
9322 
9323  void send_subscribe(
9324  std::vector<std::tuple<as::const_buffer, subscribe_options>> params,
9325  packet_id_t packet_id,
9326  v5::properties props
9327  ) {
9328  {
9329  LockGuard<Mutex> lck (sub_unsub_inflight_mtx_);
9330  sub_unsub_inflight_.insert(packet_id);
9331  }
9332  for(auto const& p : params)
9333  {
9334  (void)p;
9335  BOOST_ASSERT(
9336  std::get<1>(p).get_qos() == qos::at_most_once ||
9337  std::get<1>(p).get_qos() == qos::at_least_once ||
9338  std::get<1>(p).get_qos() == qos::exactly_once
9339  );
9340  }
9341  switch (version_) {
9342  case protocol_version::v3_1_1:
9343  do_sync_write(v3_1_1::basic_subscribe_message<PacketIdBytes>(force_move(params), packet_id));
9344  break;
9345  case protocol_version::v5:
9346  do_sync_write(v5::basic_subscribe_message<PacketIdBytes>(force_move(params), packet_id, force_move(props)));
9347  break;
9348  default:
9349  BOOST_ASSERT(false);
9350  break;
9351  }
9352  }
9353 
9354  void send_suback(
9355  variant<std::vector<suback_return_code>, std::vector<v5::suback_reason_code>> params,
9356  packet_id_t packet_id,
9357  v5::properties props
9358  ) {
9359  switch (version_) {
9360  case protocol_version::v3_1_1:
9361  do_sync_write(v3_1_1::basic_suback_message<PacketIdBytes>(force_move(variant_get<std::vector<suback_return_code>>(params)), packet_id));
9362  break;
9363  case protocol_version::v5:
9364  do_sync_write(v5::basic_suback_message<PacketIdBytes>(force_move(variant_get<std::vector<v5::suback_reason_code>>(params)), packet_id, force_move(props)));
9365  break;
9366  default:
9367  BOOST_ASSERT(false);
9368  break;
9369  }
9370  }
9371 
9372  void send_unsubscribe(
9373  std::vector<as::const_buffer> params,
9374  packet_id_t packet_id,
9375  v5::properties props
9376  ) {
9377  {
9378  LockGuard<Mutex> lck (sub_unsub_inflight_mtx_);
9379  sub_unsub_inflight_.insert(packet_id);
9380  }
9381  switch (version_) {
9382  case protocol_version::v3_1_1:
9383  do_sync_write(v3_1_1::basic_unsubscribe_message<PacketIdBytes>(force_move(params), packet_id));
9384  break;
9385  case protocol_version::v5:
9386  do_sync_write(v5::basic_unsubscribe_message<PacketIdBytes>(force_move(params), packet_id, force_move(props)));
9387  break;
9388  default:
9389  BOOST_ASSERT(false);
9390  break;
9391  }
9392  }
9393 
9394  void send_unsuback(
9395  packet_id_t packet_id
9396  ) {
9397  switch (version_) {
9398  case protocol_version::v3_1_1:
9399  do_sync_write(v3_1_1::basic_unsuback_message<PacketIdBytes>(packet_id));
9400  break;
9401  case protocol_version::v5:
9402  BOOST_ASSERT(false);
9403  break;
9404  default:
9405  BOOST_ASSERT(false);
9406  break;
9407  }
9408  }
9409 
9410  void send_unsuback(
9411  std::vector<v5::unsuback_reason_code> params,
9412  packet_id_t packet_id,
9413  v5::properties props
9414  ) {
9415  switch (version_) {
9416  case protocol_version::v3_1_1:
9417  BOOST_ASSERT(false);
9418  break;
9419  case protocol_version::v5:
9420  do_sync_write(v5::basic_unsuback_message<PacketIdBytes>(force_move(params), packet_id, force_move(props)));
9421  break;
9422  default:
9423  BOOST_ASSERT(false);
9424  break;
9425  }
9426  }
9427 
9428  void send_pingreq() {
9429  switch (version_) {
9430  case protocol_version::v3_1_1:
9431  do_sync_write(v3_1_1::pingreq_message());
9432  set_pingresp_timer();
9433  break;
9434  case protocol_version::v5:
9435  do_sync_write(v5::pingreq_message());
9436  set_pingresp_timer();
9437  break;
9438  default:
9439  BOOST_ASSERT(false);
9440  break;
9441  }
9442  }
9443 
9444  void send_pingresp() {
9445  switch (version_) {
9446  case protocol_version::v3_1_1:
9447  do_sync_write(v3_1_1::pingresp_message());
9448  break;
9449  case protocol_version::v5:
9450  do_sync_write(v5::pingresp_message());
9451  break;
9452  default:
9453  BOOST_ASSERT(false);
9454  break;
9455  }
9456  }
9457 
9458  void send_auth(
9459  v5::auth_reason_code reason,
9460  v5::properties props
9461  ) {
9462  switch (version_) {
9463  case protocol_version::v3_1_1:
9464  BOOST_ASSERT(false);
9465  break;
9466  case protocol_version::v5:
9467  do_sync_write(v5::auth_message(reason, force_move(props)));
9468  break;
9469  default:
9470  BOOST_ASSERT(false);
9471  break;
9472  }
9473  }
9474 
9475  void send_disconnect(
9477  v5::properties props
9478  ) {
9479  switch (version_) {
9480  case protocol_version::v3_1_1:
9481  do_sync_write(v3_1_1::disconnect_message());
9482  break;
9483  case protocol_version::v5:
9484  do_sync_write(v5::disconnect_message(reason, force_move(props)));
9485  break;
9486  default:
9487  BOOST_ASSERT(false);
9488  break;
9489  }
9490  }
9491 
9492  void send_store() {
9493  LockGuard<Mutex> lck (store_mtx_);
9494  auto const& idx = store_.template get<tag_seq>();
9495  for (auto const& e : idx) {
9496  do_sync_write(get_basic_message_variant<PacketIdBytes>(e.message()));
9497  }
9498  }
9499 
9500  // Blocking write
9501  template <typename MessageVariant>
9502  void do_sync_write(MessageVariant&& mv) {
9504  if (!connected_) return;
9505  on_pre_send();
9506  total_bytes_sent_ += socket_->write(const_buffer_sequence<PacketIdBytes>(mv), ec);
9507  // If ec is set as error, the error will be handled by async_read.
9508  // If `handle_error(ec);` is called here, error_handler would be called twice.
9509  }
9510 
9511  // Non blocking (async) senders
9512  void async_send_connect(
9513  buffer client_id,
9514  optional<buffer> user_name,
9515  optional<buffer> password,
9516  optional<will> const& w,
9517  std::uint16_t keep_alive_sec,
9518  v5::properties props,
9519  async_handler_t func
9520  ) {
9521 
9522  switch (version_) {
9523  case protocol_version::v3_1_1:
9524  do_async_write(
9525  v3_1_1::connect_message(
9526  keep_alive_sec,
9527  force_move(client_id),
9528  clean_session(),
9529  w,
9530  force_move(user_name),
9531  force_move(password)
9532  ),
9533  force_move(func)
9534  );
9535  break;
9536  case protocol_version::v5:
9537  update_topic_alias_maximum_recv(props);
9538  do_async_write(
9539  v5::connect_message(
9540  keep_alive_sec,
9541  force_move(client_id),
9542  clean_start(),
9543  w,
9544  force_move(user_name),
9545  force_move(password),
9546  force_move(props)
9547  ),
9548  force_move(func)
9549  );
9550  break;
9551  default:
9552  BOOST_ASSERT(false);
9553  break;
9554  }
9555  }
9556 
9557  void async_send_connack(
9558  bool session_present,
9559  variant<connect_return_code, v5::connect_reason_code> reason_code,
9560  v5::properties props,
9561  async_handler_t func
9562  ) {
9563  switch (version_) {
9564  case protocol_version::v3_1_1:
9565  do_async_write(
9566  v3_1_1::connack_message(
9567  session_present,
9568  variant_get<connect_return_code>(reason_code)
9569  ),
9570  force_move(func)
9571  );
9572  break;
9573  case protocol_version::v5:
9574  update_topic_alias_maximum_recv(props);
9575  do_async_write(
9576  v5::connack_message(
9577  session_present,
9578  variant_get<v5::connect_reason_code>(reason_code),
9579  force_move(props)
9580  ),
9581  force_move(func)
9582  );
9583  break;
9584  default:
9585  BOOST_ASSERT(false);
9586  break;
9587  }
9588  }
9589 
9590  template <typename ConstBufferSequence>
9591  typename std::enable_if<
9592  as::is_const_buffer_sequence<ConstBufferSequence>::value
9593  >::type
9594  async_send_publish(
9595  packet_id_t packet_id,
9596  as::const_buffer topic_name,
9597  ConstBufferSequence payloads,
9598  publish_options pubopts,
9599  v5::properties props,
9600  any life_keeper,
9601  async_handler_t func
9602  ) {
9603  auto do_async_send_publish =
9604  [&](auto msg, auto const& serialize_publish) {
9605  preprocess_publish_message(
9606  msg,
9607  life_keeper,
9608  serialize_publish
9609  );
9610  do_async_write(
9611  force_move(msg),
9612  [life_keeper = force_move(life_keeper), func = force_move(func)](error_code ec) {
9613  if (func) func(ec);
9614  }
9615  );
9616  };
9617 
9618  switch (version_) {
9619  case protocol_version::v3_1_1:
9620  do_async_send_publish(
9621  v3_1_1::basic_publish_message<PacketIdBytes>(
9622  packet_id,
9623  topic_name,
9624  force_move(payloads),
9625  pubopts
9626  ),
9627  &endpoint::on_serialize_publish_message
9628  );
9629  break;
9630  case protocol_version::v5:
9631  do_async_send_publish(
9632  v5::basic_publish_message<PacketIdBytes>(
9633  packet_id,
9634  topic_name,
9635  force_move(payloads),
9636  pubopts,
9637  force_move(props)
9638  ),
9639  &endpoint::on_serialize_v5_publish_message
9640  );
9641  break;
9642  default:
9643  BOOST_ASSERT(false);
9644  break;
9645  }
9646  }
9647 
9648  void async_send_puback(
9649  packet_id_t packet_id,
9650  v5::puback_reason_code reason,
9651  v5::properties props,
9652  async_handler_t func
9653  ) {
9654  switch (version_) {
9655  case protocol_version::v3_1_1:
9656  do_async_write(
9657  v3_1_1::basic_puback_message<PacketIdBytes>(packet_id),
9658  [this, self = this->shared_from_this(), packet_id, func = force_move(func)]
9659  (error_code ec) {
9660  if (func) func(ec);
9661  on_pub_res_sent(packet_id);
9662  }
9663  );
9664  break;
9665  case protocol_version::v5:
9666  do_async_write(
9667  v5::basic_puback_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9668  [this, self = this->shared_from_this(), packet_id, func = force_move(func)]
9669  (error_code ec) {
9670  if (func) func(ec);
9671  on_pub_res_sent(packet_id);
9672  }
9673  );
9674  break;
9675  default:
9676  BOOST_ASSERT(false);
9677  break;
9678  }
9679  }
9680 
9681  void async_send_pubrec(
9682  packet_id_t packet_id,
9683  v5::pubrec_reason_code reason,
9684  v5::properties props,
9685  async_handler_t func
9686  ) {
9687  switch (version_) {
9688  case protocol_version::v3_1_1:
9689  do_async_write(
9690  v3_1_1::basic_pubrec_message<PacketIdBytes>(packet_id),
9691  force_move(func)
9692  );
9693  break;
9694  case protocol_version::v5:
9695  do_async_write(
9696  v5::basic_pubrec_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9697  force_move(func)
9698  );
9699  break;
9700  default:
9701  BOOST_ASSERT(false);
9702  break;
9703  }
9704  }
9705 
9706  void async_send_pubrel(
9707  packet_id_t packet_id,
9708  v5::pubrel_reason_code reason,
9709  v5::properties props,
9710  any life_keeper,
9711  async_handler_t func
9712  ) {
9713 
9714  auto msg = basic_pubrel_message<PacketIdBytes>(packet_id);
9715 
9716  auto impl =
9717  [&](auto msg, auto const& serialize) {
9718  {
9719  LockGuard<Mutex> lck (store_mtx_);
9720 
9721  // insert if not registerd (start from pubrel sending case)
9722  pid_man_.register_id(packet_id);
9723 
9724  auto ret = store_.emplace(
9725  packet_id,
9726  control_packet_type::pubcomp,
9727  msg,
9728  life_keeper
9729  );
9730  // publish store is erased when pubrec is received.
9731  // pubrel store is erased when pubcomp is received.
9732  // If invalid client send pubrec twice with the same packet id,
9733  // then send corresponding pubrel twice is a possible client/server
9734  // implementation.
9735  // In this case, overwrite store_.
9736  if (!ret.second) {
9737  MQTT_LOG("mqtt_impl", warning)
9738  << MQTT_ADD_VALUE(address, this)
9739  << "overwrite pubrel"
9740  << " packet_id:" << packet_id;
9741  store_.modify(
9742  ret.first,
9743  [&] (auto& e) {
9744  e = store(
9745  packet_id,
9746  control_packet_type::pubcomp,
9747  msg,
9748  life_keeper
9749  );
9750  }
9751  );
9752  }
9753  }
9754 
9755  (this->*serialize)(msg);
9756 
9757  do_async_write(
9758  force_move(msg),
9759  [life_keeper = force_move(life_keeper), func = force_move(func)](error_code ec) {
9760  if(func) func(ec);
9761  }
9762  );
9763  };
9764 
9765  switch (version_) {
9766  case protocol_version::v3_1_1:
9767  impl(
9768  v3_1_1::basic_pubrel_message<PacketIdBytes>(packet_id),
9769  &endpoint::on_serialize_pubrel_message
9770  );
9771  break;
9772  case protocol_version::v5:
9773  impl(
9774  v5::basic_pubrel_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9775  &endpoint::on_serialize_v5_pubrel_message
9776  );
9777  break;
9778  default:
9779  BOOST_ASSERT(false);
9780  break;
9781  }
9782  }
9783 
9784  void async_send_pubcomp(
9785  packet_id_t packet_id,
9786  v5::pubcomp_reason_code reason,
9787  v5::properties props,
9788  async_handler_t func
9789  ) {
9790  switch (version_) {
9791  case protocol_version::v3_1_1:
9792  do_async_write(
9793  v3_1_1::basic_pubcomp_message<PacketIdBytes>(packet_id),
9794  [this, self = this->shared_from_this(), packet_id, func = force_move(func)]
9795  (error_code ec) {
9796  if (func) func(ec);
9797  on_pub_res_sent(packet_id);
9798  }
9799  );
9800  break;
9801  case protocol_version::v5:
9802  do_async_write(
9803  v5::basic_pubcomp_message<PacketIdBytes>(packet_id, reason, force_move(props)),
9804  [this, self = this->shared_from_this(), packet_id, func = force_move(func)]
9805  (error_code ec) {
9806  if (func) func(ec);
9807  on_pub_res_sent(packet_id);
9808  }
9809  );
9810  break;
9811  default:
9812  BOOST_ASSERT(false);
9813  break;
9814  }
9815  }
9816 
9817  void async_send_subscribe(
9818  std::vector<std::tuple<as::const_buffer, subscribe_options>> params,
9819  packet_id_t packet_id,
9820  v5::properties props,
9821  async_handler_t func
9822  ) {
9823  {
9824  LockGuard<Mutex> lck (sub_unsub_inflight_mtx_);
9825  sub_unsub_inflight_.insert(packet_id);
9826  }
9827  switch (version_) {
9828  case protocol_version::v3_1_1:
9829  do_async_write(
9830  v3_1_1::basic_subscribe_message<PacketIdBytes>(
9831  force_move(params),
9832  packet_id),
9833  force_move(func)
9834  );
9835  break;
9836  case protocol_version::v5:
9837  do_async_write(
9838  v5::basic_subscribe_message<PacketIdBytes>(
9839  force_move(params),
9840  packet_id,
9841  force_move(props)),
9842  force_move(func)
9843  );
9844  break;
9845  default:
9846  BOOST_ASSERT(false);
9847  break;
9848  }
9849  }
9850 
9851  void async_send_suback(
9852  variant<std::vector<suback_return_code>, std::vector<v5::suback_reason_code>> params,
9853  packet_id_t packet_id,
9854  v5::properties props,
9855  async_handler_t func
9856  ) {
9857  switch (version_) {
9858  case protocol_version::v3_1_1:
9859  do_async_write(
9860  v3_1_1::basic_suback_message<PacketIdBytes>(
9861  force_move(variant_get<std::vector<suback_return_code>>(params)),
9862  packet_id),
9863  force_move(func)
9864  );
9865  break;
9866  case protocol_version::v5:
9867  do_async_write(
9868  v5::basic_suback_message<PacketIdBytes>(
9869  force_move(variant_get<std::vector<v5::suback_reason_code>>(params)),
9870  packet_id,
9871  force_move(props)),
9872  force_move(func)
9873  );
9874  break;
9875  default:
9876  BOOST_ASSERT(false);
9877  break;
9878  }
9879  }
9880 
9881  void async_send_unsubscribe(
9882  std::vector<as::const_buffer> params,
9883  packet_id_t packet_id,
9884  v5::properties props,
9885  async_handler_t func
9886  ) {
9887  {
9888  LockGuard<Mutex> lck (sub_unsub_inflight_mtx_);
9889  sub_unsub_inflight_.insert(packet_id);
9890  }
9891  switch (version_) {
9892  case protocol_version::v3_1_1:
9893  do_async_write(
9894  v3_1_1::basic_unsubscribe_message<PacketIdBytes>(
9895  force_move(params),
9896  packet_id
9897  ),
9898  force_move(func)
9899  );
9900  break;
9901  case protocol_version::v5:
9902  do_async_write(
9903  v5::basic_unsubscribe_message<PacketIdBytes>(
9904  force_move(params),
9905  packet_id,
9906  force_move(props)
9907  ),
9908  force_move(func)
9909  );
9910  break;
9911  default:
9912  BOOST_ASSERT(false);
9913  break;
9914  }
9915  }
9916 
9917  void async_send_unsuback(
9918  packet_id_t packet_id,
9919  async_handler_t func
9920  ) {
9921  switch (version_) {
9922  case protocol_version::v3_1_1:
9923  do_async_write(
9924  v3_1_1::basic_unsuback_message<PacketIdBytes>(packet_id), force_move(func)
9925  );
9926  break;
9927  case protocol_version::v5:
9928  BOOST_ASSERT(false);
9929  break;
9930  default:
9931  BOOST_ASSERT(false);
9932  break;
9933  }
9934  }
9935 
9936  void async_send_unsuback(
9937  std::vector<v5::unsuback_reason_code> params,
9938  packet_id_t packet_id,
9939  v5::properties props,
9940  async_handler_t func
9941  ) {
9942  switch (version_) {
9943  case protocol_version::v3_1_1:
9944  BOOST_ASSERT(false);
9945  break;
9946  case protocol_version::v5:
9947  do_async_write(
9948  v5::basic_unsuback_message<PacketIdBytes>(
9949  force_move(params),
9950  packet_id,
9951  force_move(props)
9952  ),
9953  force_move(func)
9954  );
9955  break;
9956  default:
9957  BOOST_ASSERT(false);
9958  break;
9959  }
9960  }
9961 
9962  void async_send_pingreq(async_handler_t func) {
9963  switch (version_) {
9964  case protocol_version::v3_1_1:
9965  do_async_write(v3_1_1::pingreq_message(), force_move(func));
9966  set_pingresp_timer();
9967  break;
9968  case protocol_version::v5:
9969  do_async_write(v5::pingreq_message(), force_move(func));
9970  set_pingresp_timer();
9971  break;
9972  default:
9973  BOOST_ASSERT(false);
9974  break;
9975  }
9976  }
9977 
9978  void async_send_pingresp(async_handler_t func) {
9979  switch (version_) {
9980  case protocol_version::v3_1_1:
9981  do_async_write(v3_1_1::pingresp_message(), force_move(func));
9982  break;
9983  case protocol_version::v5:
9984  do_async_write(v5::pingresp_message(), force_move(func));
9985  break;
9986  default:
9987  BOOST_ASSERT(false);
9988  break;
9989  }
9990  }
9991 
9992  void async_send_auth(
9993  v5::auth_reason_code reason,
9994  v5::properties props,
9995  async_handler_t func
9996  ) {
9997  switch (version_) {
9998  case protocol_version::v3_1_1:
9999  BOOST_ASSERT(false);
10000  break;
10001  case protocol_version::v5:
10002  do_async_write(v5::auth_message(reason, force_move(props)), force_move(func));
10003  break;
10004  default:
10005  BOOST_ASSERT(false);
10006  break;
10007  }
10008  }
10009 
10010  void async_send_disconnect(
10012  v5::properties props,
10013  async_handler_t func
10014  ) {
10015  switch (version_) {
10016  case protocol_version::v3_1_1:
10017  do_async_write(v3_1_1::disconnect_message(), force_move(func));
10018  break;
10019  case protocol_version::v5:
10020  do_async_write(v5::disconnect_message(reason, force_move(props)), force_move(func));
10021  break;
10022  default:
10023  BOOST_ASSERT(false);
10024  break;
10025  }
10026  }
10027 
10028  void async_send_store(std::function<void()> func) {
10029  auto g = shared_scope_guard(
10030  [func = force_move(func)] {
10031  func();
10032  }
10033  );
10034  LockGuard<Mutex> lck (store_mtx_);
10035  auto const& idx = store_.template get<tag_seq>();
10036  for (auto const& e : idx) {
10037  do_async_write(
10038  get_basic_message_variant<PacketIdBytes>(e.message()),
10039  [g]
10040  (error_code /*ec*/) {
10041  }
10042  );
10043  }
10044  }
10045 
10046  // Non blocking (async) write
10047 
10048  class async_packet {
10049  public:
10050  async_packet(
10051  basic_message_variant<PacketIdBytes> mv,
10052  async_handler_t h = {})
10053  : mv_(force_move(mv))
10054  , handler_(force_move(h)) {}
10055  basic_message_variant<PacketIdBytes> const& message() const {
10056  return mv_;
10057  }
10058  basic_message_variant<PacketIdBytes>& message() {
10059  return mv_;
10060  }
10061  async_handler_t const& handler() const { return handler_; }
10062  async_handler_t& handler() { return handler_; }
10063  private:
10064  basic_message_variant<PacketIdBytes> mv_;
10065  async_handler_t handler_;
10066  };
10067 
10068  struct write_completion_handler {
10069  write_completion_handler(
10070  std::shared_ptr<this_type> self,
10071  async_handler_t func,
10072  std::size_t num_of_messages,
10073  std::size_t expected)
10074  :self_(force_move(self)),
10075  func_(force_move(func)),
10076  num_of_messages_(num_of_messages),
10077  bytes_to_transfer_(expected)
10078  {
10079  // write_completion_handler is only constructed in one place
10080  // and a handler is provided in that location.
10081  // Since we don't check that the handler is valid before calling it
10082  // it's a bug if the handler is invalid when constructed.
10083  BOOST_ASSERT(func_);
10084  }
10085  void operator()(error_code ec) const {
10086  func_(ec);
10087  for (std::size_t i = 0; i != num_of_messages_; ++i) {
10088  self_->queue_.pop_front();
10089  }
10090  if (ec || // Error is handled by async_read.
10091  !self_->connected_) {
10092  self_->connected_ = false;
10093  while (!self_->queue_.empty()) {
10094  // Handlers for outgoing packets need not be valid.
10095  if(auto&& h = self_->queue_.front().handler()) h(ec);
10096  self_->queue_.pop_front();
10097  }
10098  return;
10099  }
10100  if (!self_->queue_.empty()) {
10101  self_->do_async_write();
10102  }
10103  }
10104  void operator()(
10105  error_code ec,
10106  std::size_t bytes_transferred) const {
10107  func_(ec);
10108  self_->total_bytes_sent_ += bytes_transferred;
10109  for (std::size_t i = 0; i != num_of_messages_; ++i) {
10110  self_->queue_.pop_front();
10111  }
10112  if (ec || // Error is handled by async_read.
10113  !self_->connected_) {
10114  self_->connected_ = false;
10115  while (!self_->queue_.empty()) {
10116  // Handlers for outgoing packets need not be valid.
10117  if(auto&& h = self_->queue_.front().handler()) h(ec);
10118  self_->queue_.pop_front();
10119  }
10120  return;
10121  }
10122  if (bytes_to_transfer_ != bytes_transferred) {
10123  self_->connected_ = false;
10124  while (!self_->queue_.empty()) {
10125  // Handlers for outgoing packets need not be valid.
10126  if(auto&& h = self_->queue_.front().handler()) h(ec);
10127  self_->queue_.pop_front();
10128  }
10129  throw write_bytes_transferred_error(bytes_to_transfer_, bytes_transferred);
10130  }
10131  if (!self_->queue_.empty()) {
10132  self_->do_async_write();
10133  }
10134  }
10135  std::shared_ptr<this_type> self_;
10136  async_handler_t func_;
10137  std::size_t num_of_messages_;
10138  std::size_t bytes_to_transfer_;
10139  };
10140 
10141  void do_async_write() {
10142  // Only attempt to send up to the user specified maximum items
10143  using difference_t = typename decltype(queue_)::difference_type;
10144  std::size_t iterator_count = (max_queue_send_count_ == 0)
10145  ? queue_.size()
10146  : std::min(max_queue_send_count_, queue_.size());
10147  auto const& start = queue_.cbegin();
10148  auto end = std::next(start, boost::numeric_cast<difference_t>(iterator_count));
10149 
10150  // And further, only up to the specified maximum bytes
10151  std::size_t total_bytes = 0;
10152  std::size_t total_const_buffer_sequence = 0;
10153  for (auto it = start; it != end; ++it) {
10154  auto const& elem = *it;
10155  auto const& mv = elem.message();
10156  std::size_t const size = MQTT_NS::size<PacketIdBytes>(mv);
10157 
10158  // If we hit the byte limit, we don't include this buffer for this send.
10159  if (max_queue_send_size_ != 0 && max_queue_send_size_ < total_bytes + size) {
10160  end = it;
10161  iterator_count = boost::numeric_cast<std::size_t>(std::distance(start, end));
10162  break;
10163  }
10164  total_bytes += size;
10165  total_const_buffer_sequence += num_of_const_buffer_sequence(mv);
10166  }
10167 
10168  std::vector<as::const_buffer> buf;
10169  std::vector<async_handler_t> handlers;
10170 
10171  buf.reserve(total_const_buffer_sequence);
10172  handlers.reserve(iterator_count);
10173 
10174  for (auto it = start; it != end; ++it) {
10175  auto const& elem = *it;
10176  auto const& mv = elem.message();
10177  auto const& cbs = const_buffer_sequence(mv);
10178  std::copy(cbs.begin(), cbs.end(), std::back_inserter(buf));
10179  handlers.emplace_back(elem.handler());
10180  }
10181 
10182  on_pre_send();
10183 
10184  socket_->async_write(
10185  force_move(buf),
10186  write_completion_handler(
10187  this->shared_from_this(),
10188  [handlers = force_move(handlers)]
10189  (error_code ec) {
10190  for (auto const& h : handlers) {
10191  if (h) h(ec);
10192  }
10193  },
10194  iterator_count,
10195  total_bytes
10196  )
10197  );
10198  }
10199 
10200  void do_async_write(basic_message_variant<PacketIdBytes> mv, async_handler_t func) {
10201  // Move this job to the socket's strand so that it can be queued without mutexes.
10202  socket_->post(
10203  [this, self = this->shared_from_this(), mv = force_move(mv), func = force_move(func)]
10204  () mutable {
10205  if (!connected_) {
10206  // offline async publish is successfully finished, because there's nothing to do.
10207  if (func) func(boost::system::errc::make_error_code(boost::system::errc::success));
10208  return;
10209  }
10210  queue_.emplace_back(force_move(mv), force_move(func));
10211  // Only need to start async writes if there was nothing in the queue before the above item.
10212  if (queue_.size() > 1) return;
10213  do_async_write();
10214  }
10215  );
10216  }
10217 
10218  static constexpr std::uint16_t make_uint16_t(char b1, char b2) {
10219  return
10220  static_cast<std::uint16_t>(
10221  ((static_cast<std::uint16_t>(b1) & 0xff)) << 8 |
10222  (static_cast<std::uint16_t>(b2) & 0xff)
10223  );
10224  }
10225 
10226  void clean_sub_unsub_inflight() {
10227  LockGuard<Mutex> lck_store (store_mtx_);
10228  LockGuard<Mutex> lck_sub_unsub (sub_unsub_inflight_mtx_);
10229  for (auto packet_id : sub_unsub_inflight_) {
10230  pid_man_.release_id(packet_id);
10231  }
10232  }
10233 
10234  void clean_sub_unsub_inflight_on_error(error_code ec) {
10235  clean_sub_unsub_inflight();
10236  on_error(ec);
10237  }
10238 
10239  void set_pingresp_timer() {
10240  if (pingresp_timeout_ == std::chrono::steady_clock::duration::zero()) return;
10241  if (tim_pingresp_set_) return;
10242  tim_pingresp_set_ = true;
10243  tim_pingresp_.expires_after(pingresp_timeout_);
10244  std::weak_ptr<this_type> wp(std::static_pointer_cast<this_type>(this->shared_from_this()));
10245  tim_pingresp_.async_wait(
10246  [wp = force_move(wp)](error_code ec) {
10247  if (auto sp = wp.lock()) {
10248  sp->tim_pingresp_set_ = false;
10249  if (!ec) {
10250  sp->socket().post(
10251  [sp] {
10252  sp->force_disconnect();
10253  }
10254  );
10255  }
10256  }
10257  }
10258  );
10259  }
10260 
10261  void update_topic_alias_maximum_recv(v5::properties& props) {
10262  if (auto ta_max = get_topic_alias_maximum_from_props(props)) {
10263  if (ta_max.value() == 0) {
10264  topic_alias_recv_ = nullopt;
10265  }
10266  else {
10267  topic_alias_recv_.emplace(ta_max.value());
10268  }
10269  }
10270  else {
10271  if (topic_alias_recv_&& topic_alias_recv_.value().max() != 0) {
10272  props.emplace_back(
10273  MQTT_NS::v5::property::topic_alias_maximum(topic_alias_recv_.value().max())
10274  );
10275  }
10276  }
10277  }
10278 
10279  static optional<topic_alias_t> get_topic_alias_maximum_from_prop(v5::property_variant const& prop) {
10280  optional<topic_alias_t> val;
10283  [&val](v5::property::topic_alias_maximum const& p) {
10284  val = p.val();
10285  },
10286  [](auto&&) {
10287  }
10288  ), prop
10289  );
10290  return val;
10291  }
10292 
10293  static optional<topic_alias_t> get_topic_alias_maximum_from_props(v5::properties const& props) {
10294  for (auto const& prop : props) {
10295  if (auto val = get_topic_alias_maximum_from_prop(prop)) {
10296  return val;
10297  }
10298  }
10299  return nullopt;
10300  }
10301 
10302  static optional<topic_alias_t> get_topic_alias_from_prop(v5::property_variant const& prop) {
10303  optional<topic_alias_t> val;
10306  [&val](v5::property::topic_alias const& p) {
10307  val = p.val();
10308  },
10309  [](auto&&) {
10310  }
10311  ), prop
10312  );
10313  return val;
10314  }
10315 
10316  static optional<topic_alias_t> get_topic_alias_from_props(v5::properties const& props) {
10317  for (auto const& prop : props) {
10318  if (auto val = get_topic_alias_from_prop(prop)) {
10319  return val;
10320  }
10321  }
10322  return nullopt;
10323  }
10324 
10325 protected:
10326  // Ensure that only code that knows the *exact* type of an object
10327  // inheriting from this abstract base class can destruct it.
10328  // This avoids issues of the destructor not triggering destruction
10329  // of derived classes, and any member variables contained in them.
10330  // Note: Not virtual to avoid need for a vtable when possible.
10331  ~endpoint() = default;
10332 
10333 protected:
10334  bool clean_start_{false};
10335 
10336 private:
10337  std::shared_ptr<MQTT_NS::socket> socket_;
10338  std::atomic<bool> connected_{false};
10339  std::atomic<bool> mqtt_connected_{false};
10340 
10341  std::array<char, 10> buf_;
10342  std::uint8_t fixed_header_;
10343  std::size_t remaining_length_multiplier_;
10344  std::size_t remaining_length_;
10345  std::vector<char> payload_;
10346 
10347  Mutex store_mtx_;
10348  mi_store store_;
10349  std::set<packet_id_t> qos2_publish_handled_;
10350  std::deque<async_packet> queue_;
10351 
10352  packet_id_manager<packet_id_t> pid_man_;
10353 
10354  Mutex sub_unsub_inflight_mtx_;
10355  std::set<packet_id_t> sub_unsub_inflight_;
10356  bool auto_pub_response_{true};
10357  bool auto_pub_response_async_{false};
10358  bool async_send_store_ { false };
10359  bool async_read_on_message_processed_ { true };
10360  bool disconnect_requested_{false};
10361  bool connect_requested_{false};
10362  std::size_t max_queue_send_count_{1};
10363  std::size_t max_queue_send_size_{0};
10364  protocol_version version_{protocol_version::undetermined};
10365  std::size_t packet_bulk_read_limit_ = 256;
10366  std::size_t props_bulk_read_limit_ = packet_bulk_read_limit_;
10367  std::size_t total_bytes_sent_ = 0;
10368  std::size_t total_bytes_received_ = 0;
10369  static constexpr std::uint8_t variable_length_continue_flag = 0b10000000;
10370 
10371  std::chrono::steady_clock::duration pingresp_timeout_ = std::chrono::steady_clock::duration::zero();
10372  as::steady_timer tim_pingresp_;
10373  bool tim_pingresp_set_ = false;
10374 
10375  bool auto_map_topic_alias_send_ = false;
10376  bool auto_replace_topic_alias_send_ = false;
10377  mutable Mutex topic_alias_send_mtx_;
10378  optional<topic_alias_send> topic_alias_send_;
10379 
10380  mutable Mutex topic_alias_recv_mtx_;
10381  optional<topic_alias_recv> topic_alias_recv_;
10382 };
10383 
10384 } // namespace MQTT_NS
10385 
10386 #include <boost/asio/unyield.hpp>
10387 
10388 #if defined(__GNUC__)
10389 #pragma GCC diagnostic pop
10390 #endif // defined(__GNUC__)
10391 
10392 #endif // MQTT_ENDPOINT_HPP
#define MQTT_ALWAYS_INLINE
Definition: attributes.hpp:18
buffer that has string_view interface This class provides string_view interface. This class hold stri...
Definition: buffer.hpp:30
Definition: endpoint.hpp:171
void async_unsuback(packet_id_t packet_id, async_handler_t func={})
Send ununsuback packet. This function is for broker.
Definition: endpoint.hpp:4173
void async_send_store_message(basic_store_message_variant< PacketIdBytes > msg, any life_keeper, async_handler_t func)
Definition: endpoint.hpp:4645
protocol_version get_protocol_version() const
Definition: endpoint.hpp:4763
void async_subscribe(packet_id_t packet_id, buffer topic_filter, subscribe_options option, v5::properties props, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2878
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< buffer, subscribe_options >> params, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:3080
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< std::string, subscribe_options >> params, v5::properties props, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2972
void async_pingresp(async_handler_t func={})
Send pingresp packet. This function is for broker.
Definition: endpoint.hpp:3555
void async_subscribe(packet_id_t packet_id, std::string topic_filter, subscribe_options option, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2646
void pubrel(packet_id_t packet_id, v5::pubrel_reason_code reason_code=v5::pubrel_reason_code::success, v5::properties props={}, any life_keeper={})
Send pubrel packet.
Definition: endpoint.hpp:1954
void unsubscribe(packet_id_t packet_id, std::vector< as::const_buffer > params, v5::properties props={})
Unsubscribe with already acquired packet identifier.
Definition: endpoint.hpp:1632
void async_publish(packet_id_t packet_id, std::string topic_name, std::string contents, publish_options pubopts={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2264
void unsuback(packet_id_t packet_id)
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:2055
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value, packet_id_t > publish(T &&t, Params &&... params)
Publish.
Definition: endpoint.hpp:941
void connect(std::string const &client_id, optional< std::string > const &user_name, optional< std::string > const &password, optional< will > w, std::uint16_t keep_alive_sec, v5::properties props={})
Send connect packet.
Definition: endpoint.hpp:1763
void unsubscribe(packet_id_t packet_id, std::vector< buffer > params, v5::properties props={})
Unsubscribe with already acquired packet identifier.
Definition: endpoint.hpp:1664
endpoint(as::io_context &ioc, protocol_version version=protocol_version::undetermined, bool async_send_store=false)
Constructor for client.
Definition: endpoint.hpp:182
void async_unsubscribe(packet_id_t packet_id, std::vector< as::const_buffer > params, v5::properties props, async_handler_t func)
Unsubscribe.
Definition: endpoint.hpp:3433
void async_unsuback(packet_id_t packet_id, v5::unsuback_reason_code reason, v5::properties props, async_handler_t func={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:4097
void async_connect(buffer client_id, optional< buffer > user_name, optional< buffer > password, optional< will > w, std::uint16_t keep_alive_sec, v5::properties props, async_handler_t func={})
Send connect packet.
Definition: endpoint.hpp:3658
void async_auth(v5::auth_reason_code reason_code=v5::auth_reason_code::success, v5::properties props={}, async_handler_t func={})
Send auth packet.
Definition: endpoint.hpp:3577
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< buffer, subscribe_options >> params, v5::properties props, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:3125
virtual void on_close() noexcept=0
Close handler.
void restore_serialized_message(basic_store_message_variant< PacketIdBytes > msg, any life_keeper={})
Definition: endpoint.hpp:4579
void async_unsubscribe(packet_id_t packet_id, as::const_buffer topic_filter, async_handler_t func)
Unsubscribe.
Definition: endpoint.hpp:3204
void force_disconnect()
Disconnect by endpoint Force disconnect. It is not a clean disconnect sequence. When the endpoint di...
Definition: endpoint.hpp:1034
bool connected() const
Check connection status.
Definition: endpoint.hpp:4710
friend struct process_connack
Definition: endpoint.hpp:7112
void suback(packet_id_t packet_id, variant< suback_return_code, v5::suback_reason_code > reason, v5::properties props={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:2007
void async_pubcomp(packet_id_t packet_id, async_handler_t func={})
Send pubcomp packet.
Definition: endpoint.hpp:3897
void for_each_store(std::function< void(char const *, std::size_t)> const &f)
Apply f to stored messages.
Definition: endpoint.hpp:4201
void async_suback(packet_id_t packet_id, variant< suback_return_code, v5::suback_reason_code > reason, async_handler_t func={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:3950
void set_max_queue_send_count(std::size_t count)
Set maximum number of queued message sending. When async message sending function called during async...
Definition: endpoint.hpp:4743
void async_publish(packet_id_t packet_id, std::string topic_name, std::string contents, publish_options pubopts, v5::properties props, any life_keeper={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2325
std::size_t get_total_bytes_received() const
get_total_bytes_received
Definition: endpoint.hpp:836
void async_unsubscribe(packet_id_t packet_id, std::vector< as::const_buffer > params, async_handler_t func)
Unsubscribe.
Definition: endpoint.hpp:3398
std::function< void(error_code ec)> async_handler_t
Definition: endpoint.hpp:176
void async_connect(buffer client_id, optional< buffer > user_name, optional< buffer > password, optional< will > w, std::uint16_t keep_alive_sec, async_handler_t func={})
Send connect packet.
Definition: endpoint.hpp:3613
~endpoint()=default
void start_session(any session_life_keeper=any())
start session with a connected endpoint.
Definition: endpoint.hpp:907
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value > async_unsubscribe(T &&t, Params &&... params)
Unsubscribe.
Definition: endpoint.hpp:2244
void set_topic_alias_maximum(topic_alias_t max)
set topic alias maximum for receiving
Definition: endpoint.hpp:897
virtual MQTT_ALWAYS_INLINE void on_mqtt_message_processed(any session_life_keeper)
next read handler This handler is called when the current mqtt message has been processed.
Definition: endpoint.hpp:796
void set_auto_map_topic_alias_send(bool b=true)
Set topic alias send auto mapping enable flag.
Definition: endpoint.hpp:868
bool underlying_connected() const
Check underlying layer connection status.
Definition: endpoint.hpp:4718
void async_suback(packet_id_t packet_id, variant< std::vector< suback_return_code >, std::vector< v5::suback_reason_code >> reasons, async_handler_t func={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:4015
void async_unsubscribe(packet_id_t packet_id, buffer topic_filter, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3229
bool handle_close_or_error(error_code ec)
Definition: endpoint.hpp:4816
void subscribe(packet_id_t packet_id, std::vector< std::tuple< string_view, subscribe_options >> params, v5::properties props={})
Subscribe with already acquired packet identifier.
Definition: endpoint.hpp:1476
void async_connack(bool session_present, variant< connect_return_code, v5::connect_reason_code > reason_code, async_handler_t func={})
Send connack packet. This function is for broker.
Definition: endpoint.hpp:3693
void disconnect(v5::disconnect_reason_code reason=v5::disconnect_reason_code::normal_disconnection, v5::properties props={})
Disconnect Send a disconnect packet to the connected broker. It is a clean disconnecting sequence....
Definition: endpoint.hpp:1014
void async_subscribe(packet_id_t packet_id, std::string topic_filter, subscribe_options option, v5::properties props, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2696
void unsubscribe(packet_id_t packet_id, as::const_buffer topic_filter, v5::properties props={})
Unsubscribe with already acquired packet identifier.
Definition: endpoint.hpp:1573
void set_max_queue_send_size(std::size_t size)
Set maximum size of queued message sending. When async message sending function called during asynchr...
Definition: endpoint.hpp:4759
void release_packet_id(packet_id_t packet_id)
Release packet_id.
Definition: endpoint.hpp:4291
void async_puback(packet_id_t packet_id, v5::puback_reason_code reason_code, v5::properties props, async_handler_t func={})
Send puback packet.
Definition: endpoint.hpp:3768
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< as::const_buffer, subscribe_options >> params, v5::properties props, async_handler_t func)
Subscribe.
Definition: endpoint.hpp:3050
void async_subscribe(packet_id_t packet_id, buffer topic_filter, subscribe_options option, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2830
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< as::const_buffer, subscribe_options >> params, async_handler_t func)
Subscribe.
Definition: endpoint.hpp:3017
void async_unsuback(packet_id_t packet_id, std::vector< v5::unsuback_reason_code > reasons, async_handler_t func={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:4123
void set_props_bulk_read_limit(std::size_t size)
Definition: endpoint.hpp:888
MQTT_NS::socket & socket()
Definition: endpoint.hpp:4771
void suback(packet_id_t packet_id, variant< std::vector< suback_return_code >, std::vector< v5::suback_reason_code >> reasons, v5::properties props={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:2038
void unsuback(packet_id_t packet_id, v5::unsuback_reason_code reason, v5::properties props={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:2078
auto get_executor()
Definition: endpoint.hpp:4775
void async_suback(packet_id_t packet_id, variant< suback_return_code, v5::suback_reason_code > reason, v5::properties props, async_handler_t func={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:3984
void puback(packet_id_t packet_id, v5::puback_reason_code reason_code=v5::puback_reason_code::success, v5::properties props={})
Send puback packet.
Definition: endpoint.hpp:1895
void async_disconnect(v5::disconnect_reason_code reason, v5::properties props, async_handler_t func={})
Disconnect.
Definition: endpoint.hpp:2193
std::enable_if< as::is_const_buffer_sequence< ConstBufferSequence >::value >::type publish(packet_id_t packet_id, as::const_buffer topic_name, ConstBufferSequence contents, publish_options pubopts, any life_keeper)
Publish with already acquired packet identifier.
Definition: endpoint.hpp:1206
bool clean_session() const
Get clean session.
Definition: endpoint.hpp:816
std::enable_if< as::is_const_buffer_sequence< ConstBufferSequence >::value >::type async_publish(packet_id_t packet_id, as::const_buffer topic_name, ConstBufferSequence contents, publish_options pubopts={}, any life_keeper={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2392
MQTT_NS::socket const & socket() const
Definition: endpoint.hpp:4767
optional< packet_id_t > acquire_unique_packet_id_no_except()
Acquire the new unique packet id. If all packet ids are already in use, then returns nullopt After ac...
Definition: endpoint.hpp:4268
endpoint(as::io_context &ioc, std::shared_ptr< MQTT_NS::socket > socket, protocol_version version=protocol_version::undetermined, bool async_send_store=false)
Constructor for server. socket should have already been connected with another endpoint.
Definition: endpoint.hpp:198
void set_pingresp_timeout(std::chrono::steady_clock::duration tim)
Set pingresp timeout.
Definition: endpoint.hpp:4789
void pingresp()
Send pingresp packet. This function is for broker. See https://docs.oasis-open.org/mqtt/mqtt/v5....
Definition: endpoint.hpp:1700
endpoint(this_type const &)=delete
void async_unsubscribe(packet_id_t packet_id, std::vector< buffer > params, v5::properties props, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3507
typename packet_id_type< PacketIdBytes >::type packet_id_t
Definition: endpoint.hpp:177
std::enable_if< is_buffer_sequence< BufferSequence >::value >::type publish(packet_id_t packet_id, buffer topic_name, BufferSequence contents, publish_options pubopts={}, any life_keeper={})
Publish with already acquired packet identifier.
Definition: endpoint.hpp:1261
virtual void on_pre_send() noexcept=0
Pre-send handler This handler is called when any mqtt control packet is decided to send.
void async_subscribe(packet_id_t packet_id, std::vector< std::tuple< std::string, subscribe_options >> params, async_handler_t func={})
Subscribe.
Definition: endpoint.hpp:2921
void auth(v5::auth_reason_code reason_code=v5::auth_reason_code::success, v5::properties props={})
Send auth packet. See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718086.
Definition: endpoint.hpp:1721
std::enable_if< as::is_const_buffer_sequence< ConstBufferSequence >::value >::type publish(packet_id_t packet_id, as::const_buffer topic_name, ConstBufferSequence contents, publish_options pubopts, v5::properties props, any life_keeper)
Publish with already acquired packet identifier.
Definition: endpoint.hpp:1152
void async_unsubscribe(packet_id_t packet_id, std::string topic_filter, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3168
void async_subscribe(packet_id_t packet_id, as::const_buffer topic_filter, subscribe_options option, v5::properties props, async_handler_t func)
Subscribe.
Definition: endpoint.hpp:2789
endpoint & operator=(this_type &&)=delete
void restore_serialized_message(basic_pubrel_message< PacketIdBytes > msg, any life_keeper={})
Restore serialized pubrel message. This function should be called before connect.
Definition: endpoint.hpp:4403
endpoint & operator=(this_type const &)=delete
packet_id_t acquire_unique_packet_id()
Acquire the new unique packet id. If all packet ids are already in use, then throw packet_id_exhauste...
Definition: endpoint.hpp:4255
void unsuback(packet_id_t packet_id, std::vector< v5::unsuback_reason_code > reasons, v5::properties props={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:2104
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value > async_publish(T &&t, Params &&... params)
Publish.
Definition: endpoint.hpp:2143
void clear_session_data()
Definition: endpoint.hpp:4856
void subscribe(packet_id_t packet_id, std::vector< std::tuple< buffer, subscribe_options >> params, v5::properties props={})
Subscribe with already acquired packet identifier.
Definition: endpoint.hpp:1507
void async_unsubscribe(packet_id_t packet_id, buffer topic_filter, v5::properties props, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3265
std::enable_if_t< std::is_convertible< typename Iterator::value_type, char >::value > restore_serialized_message(Iterator b, Iterator e)
Restore serialized publish and pubrel messages. This function should be called before connect.
Definition: endpoint.hpp:4304
void async_pubrec(packet_id_t packet_id, v5::pubrec_reason_code reason_code, v5::properties props, async_handler_t func={})
Send pubrec packet.
Definition: endpoint.hpp:3817
void async_puback(packet_id_t packet_id, async_handler_t func={})
Send puback packet.
Definition: endpoint.hpp:3741
virtual void on_error(error_code ec) noexcept=0
Error handler.
void async_read_next_message(any session_life_keeper)
Trigger next mqtt message manually. If you call this function, you need to set manual receive mode us...
Definition: endpoint.hpp:4727
void async_unsuback(packet_id_t packet_id, std::vector< v5::unsuback_reason_code > reasons, v5::properties props, async_handler_t func={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:4151
void pubrec(packet_id_t packet_id, v5::pubrec_reason_code reason_code=v5::pubrec_reason_code::success, v5::properties props={})
Send packet.
Definition: endpoint.hpp:1921
void set_packet_bulk_read_limit(std::size_t size)
Definition: endpoint.hpp:884
void set_protocol_version(protocol_version version)
Definition: endpoint.hpp:4852
void set_auto_replace_topic_alias_send(bool b=true)
Set topic alias send auto replacing enable flag.
Definition: endpoint.hpp:880
friend struct process_connect
Definition: endpoint.hpp:6904
std::shared_ptr< MQTT_NS::socket > & socket_sp_ref()
Get shared_ptr of socket.
Definition: endpoint.hpp:4799
void async_pubrel(packet_id_t packet_id, async_handler_t func={})
Send pubrel packet.
Definition: endpoint.hpp:3839
void async_connack(bool session_present, variant< connect_return_code, v5::connect_reason_code > reason_code, v5::properties props, async_handler_t func={})
Send connack packet. This function is for broker.
Definition: endpoint.hpp:3719
std::enable_if< as::is_const_buffer_sequence< ConstBufferSequence >::value >::type async_publish(packet_id_t packet_id, as::const_buffer topic_name, ConstBufferSequence contents, publish_options pubopts, v5::properties props, any life_keeper={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2449
void async_unsubscribe(packet_id_t packet_id, std::vector< buffer > params, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3464
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value, packet_id_t > subscribe(T &&t, Params &&... params)
Subscribe.
Definition: endpoint.hpp:972
void connect(buffer client_id, optional< buffer > user_name, optional< buffer > password, optional< will > w, std::uint16_t keep_alive_sec, v5::properties props={})
Send connect packet.
Definition: endpoint.hpp:1833
void restore_serialized_message(basic_publish_message< PacketIdBytes > msg, any life_keeper={})
Restore serialized publish message. This function should be called before connect.
Definition: endpoint.hpp:4366
std::enable_if< is_buffer_sequence< BufferSequence >::value >::type async_publish(packet_id_t packet_id, buffer topic_name, BufferSequence contents, publish_options pubopts, v5::properties props, any life_keeper={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2580
void for_each_store(std::function< void(basic_store_message_variant< PacketIdBytes >)> const &f)
Apply f to stored messages.
Definition: endpoint.hpp:4218
void async_disconnect(async_handler_t func={})
Disconnect.
Definition: endpoint.hpp:2161
void set_auto_pub_response(bool b=true, bool async=true)
Set auto publish response mode.
Definition: endpoint.hpp:855
std::enable_if_t< std::is_convertible< typename Iterator::value_type, char >::value > restore_v5_serialized_message(Iterator b, Iterator e)
Restore serialized publish and pubrel messages. This function shouold be called before connect.
Definition: endpoint.hpp:4441
void async_pingreq(async_handler_t func={})
Send pingreq packet.
Definition: endpoint.hpp:3541
void clear_stored_publish(packet_id_t packet_id)
Clear stored publish message that has packet_id.
Definition: endpoint.hpp:4189
void async_unsubscribe(packet_id_t packet_id, std::vector< std::string > params, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3299
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value, packet_id_t > unsubscribe(T &&t, Params &&... params)
Unsubscribe.
Definition: endpoint.hpp:993
bool register_packet_id(packet_id_t packet_id)
Register packet_id to the library. After registering the packet_id, you can call acquired_* functions...
Definition: endpoint.hpp:4280
void subscribe(packet_id_t packet_id, as::const_buffer topic_filter, subscribe_options option, v5::properties props={})
Subscribe with already acquired packet identifier.
Definition: endpoint.hpp:1440
void async_pubrec(packet_id_t packet_id, async_handler_t func={})
Send pubrec packet.
Definition: endpoint.hpp:3790
std::enable_if_t< ! std::is_convertible< std::decay_t< T >, packet_id_t >::value > async_subscribe(T &&t, Params &&... params)
Subscribe.
Definition: endpoint.hpp:2227
bool clean_start_
Definition: endpoint.hpp:10334
void subscribe(packet_id_t packet_id, string_view topic_filter, subscribe_options option, v5::properties props={})
Subscribe with already acquired packet identifier.
Definition: endpoint.hpp:1397
std::enable_if< is_buffer_sequence< BufferSequence >::value >::type publish(packet_id_t packet_id, buffer topic_name, BufferSequence contents, publish_options pubopts, v5::properties props, any life_keeper={})
Publish with already acquired packet identifier.
Definition: endpoint.hpp:1334
void async_unsubscribe(packet_id_t packet_id, std::vector< std::string > params, v5::properties props, async_handler_t func={})
Unsubscribe.
Definition: endpoint.hpp:3347
void for_each_store_with_life_keeper(std::function< void(basic_store_message_variant< PacketIdBytes >, any)> const &f)
Apply f to stored messages.
Definition: endpoint.hpp:4233
void set_connect()
Definition: endpoint.hpp:4848
friend struct process_publish
Definition: endpoint.hpp:7356
void publish(packet_id_t packet_id, std::string topic_name, std::string contents, publish_options pubopts={}, v5::properties props={}, any life_keeper={})
Publish with already acquired packet identifier.
Definition: endpoint.hpp:1076
void restore_v5_serialized_message(v5::basic_publish_message< PacketIdBytes > msg, any life_keeper={})
Restore serialized publish message. This function shouold be called before connect.
Definition: endpoint.hpp:4485
void async_pubcomp(packet_id_t packet_id, v5::pubcomp_reason_code reason_code, v5::properties props, async_handler_t func={})
Send pubcomp packet.
Definition: endpoint.hpp:3924
std::size_t get_total_bytes_sent() const
get_total_bytes_sent
Definition: endpoint.hpp:844
void async_read_control_packet_type(any session_life_keeper)
Definition: endpoint.hpp:4803
void send_store_message(basic_store_message_variant< PacketIdBytes > msg, any life_keeper)
Definition: endpoint.hpp:4584
bool clean_start() const
Get clean start.
Definition: endpoint.hpp:828
void async_subscribe(packet_id_t packet_id, as::const_buffer topic_filter, subscribe_options option, async_handler_t func)
Subscribe.
Definition: endpoint.hpp:2744
void connack(bool session_present, variant< connect_return_code, v5::connect_reason_code > reason_code, v5::properties props={})
Send connack packet. This function is for broker.
Definition: endpoint.hpp:1869
endpoint(this_type &&)=delete
void unsubscribe(packet_id_t packet_id, std::vector< string_view > params, v5::properties props={})
Unsubscribe with already acquired packet identifier.
Definition: endpoint.hpp:1600
void pubcomp(packet_id_t packet_id, v5::pubcomp_reason_code reason_code=v5::pubcomp_reason_code::success, v5::properties props={})
Send pubcomp packet.
Definition: endpoint.hpp:1981
void async_unsuback(packet_id_t packet_id, v5::unsuback_reason_code reason, async_handler_t func={})
Send unsuback packet. This function is for broker.
Definition: endpoint.hpp:4068
std::enable_if< is_buffer_sequence< BufferSequence >::value >::type async_publish(packet_id_t packet_id, buffer topic_name, BufferSequence contents, publish_options pubopts={}, any life_keeper={}, async_handler_t func={})
Publish with a manual set packet identifier.
Definition: endpoint.hpp:2503
void pingreq()
Send pingreq packet. See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os....
Definition: endpoint.hpp:1687
void async_pubrel(packet_id_t packet_id, v5::pubrel_reason_code reason_code, v5::properties props={}, any life_keeper={}, async_handler_t func={})
Send pubrel packet.
Definition: endpoint.hpp:3874
void restore_v5_serialized_message(v5::basic_pubrel_message< PacketIdBytes > msg, any life_keeper={})
Restore serialized pubrel message. This function shouold be called before connect.
Definition: endpoint.hpp:4525
void unsubscribe(packet_id_t packet_id, string_view topic_filter, v5::properties props={})
Unsubscribe with already acquired packet identifier.
Definition: endpoint.hpp:1539
void async_suback(packet_id_t packet_id, variant< std::vector< suback_return_code >, std::vector< v5::suback_reason_code >> reasons, v5::properties props, async_handler_t func={})
Send suback packet. This function is for broker.
Definition: endpoint.hpp:4043
void clear()
Clear all packet ids.
Definition: packet_id_manager.hpp:59
optional< packet_id_t > acquire_unique_id()
Acquire the new unique packet id. If all packet ids are already in use, then returns nullopt After ac...
Definition: packet_id_manager.hpp:31
bool register_id(packet_id_t packet_id)
Register packet_id to the library. After registering the packet_id, you can call acquired_* functions...
Definition: packet_id_manager.hpp:42
void release_id(packet_id_t packet_id)
Release packet_id.
Definition: packet_id_manager.hpp:52
Definition: type_erased_socket.hpp:22
virtual as::ip::tcp::socket::lowest_layer_type & lowest_layer()=0
Definition: message.hpp:505
constexpr qos get_qos() const
Get qos.
Definition: message.hpp:690
packet_id_type< PacketIdBytes >::type packet_id() const
Get packet id.
Definition: message.hpp:674
Definition: v5_message.hpp:544
packet_id_type< PacketIdBytes >::type packet_id() const
Get packet id.
Definition: v5_message.hpp:796
string_view topic() const
Get topic name.
Definition: v5_message.hpp:836
constexpr qos get_qos() const
Get qos.
Definition: v5_message.hpp:812
Definition: property.hpp:462
Definition: will.hpp:21
endpoint_t::packet_id_t packet_id_t
Definition: common_type.hpp:20
#define MQTT_LOG(chan, sev)
Definition: log.hpp:135
#define MQTT_ADD_VALUE(name, val)
Definition: log.hpp:136
constexpr bool has_password_flag(char v)
Definition: connect_flags.hpp:43
constexpr qos will_qos(char v)
Definition: connect_flags.hpp:55
constexpr retain has_will_retain(char v)
Definition: connect_flags.hpp:37
constexpr bool has_user_name_flag(char v)
Definition: connect_flags.hpp:47
constexpr bool has_clean_start(char v)
Definition: connect_flags.hpp:29
constexpr char const clean_start
Definition: connect_flags.hpp:19
constexpr bool has_will_flag(char v)
Definition: connect_flags.hpp:33
constexpr char const clean_session
Definition: connect_flags.hpp:18
constexpr bool should_generate_packet_id(Params const &... params)
Definition: endpoint.hpp:151
constexpr std::enable_if_t< ! std::is_convertible< std::decay_t< T >, publish_options >::value, bool > check_qos_value(T const &)
Definition: endpoint.hpp:142
constexpr qos get_qos(std::uint8_t v)
Definition: publish.hpp:26
@ well_formed
UTF-8 string is well_formed. See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3....
constexpr validation validate_contents(string_view str)
Definition: utf8encoded_strings.hpp:47
id
Definition: property_id.hpp:19
connect_reason_code
Definition: reason_code.hpp:50
unsuback_reason_code
Definition: reason_code.hpp:237
auth_reason_code
Definition: reason_code.hpp:385
suback_reason_code
Definition: reason_code.hpp:191
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
std::vector< property_variant > properties
Definition: property_variant.hpp:51
disconnect_reason_code
Definition: reason_code.hpp:114
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 remaining_bytes(std::size_t size)
Definition: remaining_length.hpp:17
boost::string_ref string_view
Definition: string_view.hpp:64
optional< share_name_topic_filter > parse_shared_subscription(buffer whole_topic_filter)
Definition: shared_subscriptions.hpp:51
constexpr decltype(auto) visit(Visitor &&vis, Variants &&... vars)
Definition: variant.hpp:60
variant< v3_1_1::basic_publish_message< PacketIdBytes >, v3_1_1::basic_pubrel_message< PacketIdBytes >, v5::basic_publish_message< PacketIdBytes >, v5::basic_pubrel_message< PacketIdBytes > > basic_store_message_variant
Definition: message_variant.hpp:117
constexpr std::tuple< std::size_t, std::size_t > remaining_length(string_view bytes)
Definition: remaining_length.hpp:24
suback_return_code
Definition: reason_code.hpp:18
control_packet_type
Definition: control_packet_type.hpp:18
constexpr control_packet_type get_control_packet_type(std::uint8_t v)
Definition: control_packet_type.hpp:39
boost::system::error_code error_code
Definition: error_code.hpp:16
constexpr std::remove_reference_t< T > && force_move(T &&t)
Definition: move.hpp:20
std::uint16_t topic_alias_t
Definition: type.hpp:17
buffer allocate_buffer(Iterator b, Iterator e)
create buffer from the pair of iterators It copies string that from b to e into shared_ptr_array....
Definition: buffer.hpp:130
decltype(auto) variant_get(U &&arg)
Definition: variant.hpp:48
std::size_t num_of_const_buffer_sequence(basic_message_variant< PacketIdBytes > const &mv)
Definition: message_variant.hpp:98
auto shared_scope_guard(Proc &&proc)
Definition: shared_scope_guard.hpp:17
std::vector< as::const_buffer > const_buffer_sequence(basic_message_variant< PacketIdBytes > const &mv)
Definition: message_variant.hpp:87
char const * get_pointer(as::const_buffer const &cb)
Definition: const_buffer_util.hpp:17
connect_return_code
Definition: connect_return_code.hpp:17
buffer const * buffer_sequence_end(buffer const &buf)
Definition: buffer.hpp:155
std::string continuous_buffer(basic_message_variant< PacketIdBytes > const &mv)
Definition: message_variant.hpp:104
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
protocol_version
Definition: protocol_version.hpp:17
qos
Definition: subscribe_options.hpp:34
constexpr bool is_session_present(char v)
Definition: session_present.hpp:14
constexpr std::uint16_t make_uint16_t(It b, It e)
Definition: two_byte_util.hpp:34
decltype(auto) variant_idx(T const &arg)
Definition: variant.hpp:54
optional< control_packet_type > get_control_packet_type_with_check(std::uint8_t v)
Definition: control_packet_type.hpp:90
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
std::shared_ptr< char[]> shared_ptr_array
Type alias of shared_ptr char array. You can choose the target type.
Definition: shared_ptr_array.hpp:20
shared_ptr_array make_shared_ptr_array(std::size_t size)
shared_ptr_array creating function. You can choose the target type.
Definition: buffer.hpp:231
Definition: exception.hpp:27
Definition: exception.hpp:103
Definition: exception.hpp:21
Definition: publish.hpp:53
constexpr qos get_qos() const
Definition: publish.hpp:84
constexpr retain get_retain() const
Definition: publish.hpp:80
constexpr dup get_dup() const
Definition: publish.hpp:82
Definition: subscribe_entry.hpp:18
Definition: subscribe_options.hpp:40
constexpr rap get_rap() const
Definition: subscribe_options.hpp:69
constexpr nl get_nl() const
Definition: subscribe_options.hpp:71
constexpr retain_handling get_retain_handling() const
Definition: subscribe_options.hpp:67
constexpr qos get_qos() const
Definition: subscribe_options.hpp:73
Definition: subscribe_entry.hpp:46
Definition: message.hpp:189
packet_id_type< PacketIdBytes >::type packet_id() const
Get packet id.
Definition: message.hpp:205
Definition: v5_message.hpp:1422
decltype(auto) packet_id() const
Get packet id.
Definition: v5_message.hpp:1711
Definition: tags.hpp:16