sdbus-c++  1.6.0
High-level C++ D-Bus library based on systemd D-Bus implementation
Message.h
Go to the documentation of this file.
1 
27 #ifndef SDBUS_CXX_MESSAGE_H_
28 #define SDBUS_CXX_MESSAGE_H_
29 
30 #include <sdbus-c++/TypeTraits.h>
31 #include <sdbus-c++/Error.h>
32 #include <array>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 #if __cplusplus >= 202002L
37 #include <span>
38 #endif
39 #include <map>
40 #include <unordered_map>
41 #include <utility>
42 #include <cstdint>
43 #include <cassert>
44 #include <functional>
45 #include <sys/types.h>
46 #include <algorithm>
47 #include <variant>
48 
49 // Forward declarations
50 namespace sdbus {
51  class Variant;
52  class ObjectPath;
53  class Signature;
54  template <typename... _ValueTypes> class Struct;
55  class UnixFd;
56  class MethodReply;
57  namespace internal {
58  class ISdBus;
59  class IConnection;
60  }
61 }
62 
63 namespace sdbus {
64 
65  /********************************************/
78  class [[nodiscard]] Message
79  {
80  public:
81  Message& operator<<(bool item);
82  Message& operator<<(int16_t item);
83  Message& operator<<(int32_t item);
84  Message& operator<<(int64_t item);
85  Message& operator<<(uint8_t item);
86  Message& operator<<(uint16_t item);
87  Message& operator<<(uint32_t item);
88  Message& operator<<(uint64_t item);
89  Message& operator<<(double item);
90  Message& operator<<(const char *item);
91  Message& operator<<(const std::string &item);
92  Message& operator<<(const Variant &item);
93  template <typename ...Elements>
94  Message& operator<<(const std::variant<Elements...>& value);
95  Message& operator<<(const ObjectPath &item);
96  Message& operator<<(const Signature &item);
97  Message& operator<<(const UnixFd &item);
98  template <typename _Element, typename _Allocator>
99  Message& operator<<(const std::vector<_Element, _Allocator>& items);
100  template <typename _Element, std::size_t _Size>
101  Message& operator<<(const std::array<_Element, _Size>& items);
102 #if __cplusplus >= 202002L
103  template <typename _Element, std::size_t _Extent>
104  Message& operator<<(const std::span<_Element, _Extent>& items);
105 #endif
106  template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
107  Message& operator<<(const _Enum& item);
108  template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
109  Message& operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items);
110  template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
111  Message& operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
112  template <typename... _ValueTypes>
113  Message& operator<<(const Struct<_ValueTypes...>& item);
114  template <typename... _ValueTypes>
115  Message& operator<<(const std::tuple<_ValueTypes...>& item);
116 
117  Message& operator>>(bool& item);
118  Message& operator>>(int16_t& item);
119  Message& operator>>(int32_t& item);
120  Message& operator>>(int64_t& item);
121  Message& operator>>(uint8_t& item);
122  Message& operator>>(uint16_t& item);
123  Message& operator>>(uint32_t& item);
124  Message& operator>>(uint64_t& item);
125  Message& operator>>(double& item);
126  Message& operator>>(char*& item);
127  Message& operator>>(std::string &item);
128  Message& operator>>(Variant &item);
129  template <typename ...Elements>
130  Message& operator>>(std::variant<Elements...>& value);
131  Message& operator>>(ObjectPath &item);
132  Message& operator>>(Signature &item);
133  Message& operator>>(UnixFd &item);
134  template <typename _Element, typename _Allocator>
135  Message& operator>>(std::vector<_Element, _Allocator>& items);
136  template <typename _Element, std::size_t _Size>
137  Message& operator>>(std::array<_Element, _Size>& items);
138 #if __cplusplus >= 202002L
139  template <typename _Element, std::size_t _Extent>
140  Message& operator>>(std::span<_Element, _Extent>& items);
141 #endif
142  template <typename _Enum, typename = std::enable_if_t<std::is_enum_v<_Enum>>>
143  Message& operator>>(_Enum& item);
144  template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
145  Message& operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items);
146  template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
147  Message& operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items);
148  template <typename... _ValueTypes>
149  Message& operator>>(Struct<_ValueTypes...>& item);
150  template <typename... _ValueTypes>
151  Message& operator>>(std::tuple<_ValueTypes...>& item);
152 
153  Message& openContainer(const std::string& signature);
154  Message& closeContainer();
155  Message& openDictEntry(const std::string& signature);
156  Message& closeDictEntry();
157  Message& openVariant(const std::string& signature);
158  Message& closeVariant();
159  Message& openStruct(const std::string& signature);
160  Message& closeStruct();
161 
162  Message& enterContainer(const std::string& signature);
163  Message& exitContainer();
164  Message& enterDictEntry(const std::string& signature);
165  Message& exitDictEntry();
166  Message& enterVariant(const std::string& signature);
167  Message& exitVariant();
168  Message& enterStruct(const std::string& signature);
169  Message& exitStruct();
170 
171  Message& appendArray(char type, const void *ptr, size_t size);
172  Message& readArray(char type, const void **ptr, size_t *size);
173 
174  explicit operator bool() const;
175  void clearFlags();
176 
177  std::string getInterfaceName() const;
178  std::string getMemberName() const;
179  std::string getSender() const;
180  std::string getPath() const;
181  std::string getDestination() const;
182  void peekType(std::string& type, std::string& contents) const;
183  bool isValid() const;
184  bool isEmpty() const;
185  bool isAtEnd(bool complete) const;
186 
187  void copyTo(Message& destination, bool complete) const;
188  void seal();
189  void rewind(bool complete);
190 
191  pid_t getCredsPid() const;
192  uid_t getCredsUid() const;
193  uid_t getCredsEuid() const;
194  gid_t getCredsGid() const;
195  gid_t getCredsEgid() const;
196  std::vector<gid_t> getCredsSupplementaryGids() const;
197  std::string getSELinuxContext() const;
198 
199  class Factory;
200 
201  private:
202  template <typename _Array>
203  void serializeArray(const _Array& items);
204  template <typename _Array>
205  void deserializeArray(_Array& items);
206  template <typename _Array>
207  void deserializeArrayFast(_Array& items);
208  template <typename _Element, typename _Allocator>
209  void deserializeArrayFast(std::vector<_Element, _Allocator>& items);
210  template <typename _Array>
211  void deserializeArraySlow(_Array& items);
212  template <typename _Element, typename _Allocator>
213  void deserializeArraySlow(std::vector<_Element, _Allocator>& items);
214 
215  template <typename _Dictionary>
216  void serializeDictionary(const _Dictionary& items);
217  template <typename _Dictionary>
218  void deserializeDictionary(_Dictionary& items);
219 
220  protected:
221  Message() = default;
222  explicit Message(internal::ISdBus* sdbus) noexcept;
223  Message(void *msg, internal::ISdBus* sdbus) noexcept;
224  Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
225 
226  Message(const Message&) noexcept;
227  Message& operator=(const Message&) noexcept;
228  Message(Message&& other) noexcept;
229  Message& operator=(Message&& other) noexcept;
230 
231  ~Message();
232 
233  friend Factory;
234 
235  protected:
236  void* msg_{};
237  internal::ISdBus* sdbus_{};
238  mutable bool ok_{true};
239  };
240 
241  class MethodCall : public Message
242  {
243  using Message::Message;
244  friend Factory;
245 
246  public:
247  MethodCall() = default;
248 
249  MethodReply send(uint64_t timeout) const;
250  [[deprecated("Use send overload with floating_slot instead")]] void send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const;
251  void send(void* callback, void* userData, uint64_t timeout, floating_slot_t) const;
252  [[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const;
253 
254  MethodReply createReply() const;
255  MethodReply createErrorReply(const sdbus::Error& error) const;
256 
257  void dontExpectReply();
258  bool doesntExpectReply() const;
259 
260  protected:
261  MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept;
262 
263  private:
264  MethodReply sendWithReply(uint64_t timeout = 0) const;
265  MethodReply sendWithNoReply() const;
266  const internal::IConnection* connection_{};
267  };
268 
269  class MethodReply : public Message
270  {
271  using Message::Message;
272  friend Factory;
273 
274  public:
275  MethodReply() = default;
276  void send() const;
277  };
278 
279  class Signal : public Message
280  {
281  using Message::Message;
282  friend Factory;
283 
284  public:
285  Signal() = default;
286  void setDestination(const std::string& destination);
287  void send() const;
288  };
289 
290  class PropertySetCall : public Message
291  {
292  using Message::Message;
293  friend Factory;
294 
295  public:
296  PropertySetCall() = default;
297  };
298 
299  class PropertyGetReply : public Message
300  {
301  using Message::Message;
302  friend Factory;
303 
304  public:
305  PropertyGetReply() = default;
306  };
307 
308  // Represents any of the above message types, or just a message that serves as a container for data
309  class PlainMessage : public Message
310  {
311  using Message::Message;
312  friend Factory;
313 
314  public:
315  PlainMessage() = default;
316  };
317 
318  template <typename ...Elements>
319  inline Message& Message::operator<<(const std::variant<Elements...>& value)
320  {
321  std::visit([this](const auto& inner){
322  openVariant(signature_of<decltype(inner)>::str());
323  *this << inner;
324  closeVariant();
325  }, value);
326 
327  return *this;
328  }
329 
330  template <typename _Element, typename _Allocator>
331  inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
332  {
333  serializeArray(items);
334 
335  return *this;
336  }
337 
338  template <typename _Element, std::size_t _Size>
339  inline Message& Message::operator<<(const std::array<_Element, _Size>& items)
340  {
341  serializeArray(items);
342 
343  return *this;
344  }
345 
346 #if __cplusplus >= 202002L
347  template <typename _Element, std::size_t _Extent>
348  inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
349  {
350  serializeArray(items);
351 
352  return *this;
353  }
354 #endif
355 
356  template <typename _Enum, typename>
357  inline Message& Message::operator<<(const _Enum &item)
358  {
359  return operator<<(static_cast<std::underlying_type_t<_Enum>>(item));
360  }
361 
362  template <typename _Array>
363  inline void Message::serializeArray(const _Array& items)
364  {
365  using ElementType = typename _Array::value_type;
366 
367  // Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool,
368  // otherwise use step-by-step serialization of individual elements.
369  if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
370  {
371  appendArray(*signature_of<ElementType>::str().c_str(), items.data(), items.size() * sizeof(ElementType));
372  }
373  else
374  {
375  openContainer(signature_of<ElementType>::str());
376 
377  for (const auto& item : items)
378  *this << item;
379 
380  closeContainer();
381  }
382  }
383 
384  template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
385  inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
386  {
387  serializeDictionary(items);
388 
389  return *this;
390  }
391 
392  template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
393  inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
394  {
395  serializeDictionary(items);
396 
397  return *this;
398  }
399 
400  template <typename _Dictionary>
401  inline void Message::serializeDictionary(const _Dictionary& items)
402  {
403  using KeyType = typename _Dictionary::key_type;
404  using ValueType = typename _Dictionary::mapped_type;
405 
406  const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
407  const std::string arraySignature = "{" + dictEntrySignature + "}";
408 
409  openContainer(arraySignature);
410 
411  for (const auto& item : items)
412  {
413  openDictEntry(dictEntrySignature);
414  *this << item.first;
415  *this << item.second;
416  closeDictEntry();
417  }
418 
419  closeContainer();
420  }
421 
422  namespace detail
423  {
424  template <typename... _Args>
425  void serialize_pack(Message& msg, _Args&&... args)
426  {
427  (void)(msg << ... << args);
428  }
429 
430  template <class _Tuple, std::size_t... _Is>
431  void serialize_tuple( Message& msg
432  , const _Tuple& t
433  , std::index_sequence<_Is...>)
434  {
435  serialize_pack(msg, std::get<_Is>(t)...);
436  }
437  }
438 
439  template <typename... _ValueTypes>
440  inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
441  {
442  auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
443  assert(structSignature.size() > 2);
444  // Remove opening and closing parenthesis from the struct signature to get contents signature
445  auto structContentSignature = structSignature.substr(1, structSignature.size() - 2);
446 
447  openStruct(structContentSignature);
448  detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
449  closeStruct();
450 
451  return *this;
452  }
453 
454  template <typename... _ValueTypes>
455  inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item)
456  {
457  detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
458  return *this;
459  }
460 
461  namespace detail
462  {
463  template <typename _Element, typename... _Elements>
464  bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const std::string& signature)
465  {
466  if (signature != signature_of<_Element>::str())
467  return false;
468 
469  _Element temp;
470  msg.enterVariant(signature);
471  msg >> temp;
472  msg.exitVariant();
473  value = std::move(temp);
474  return true;
475  }
476  }
477 
478  template <typename... Elements>
479  inline Message& Message::operator>>(std::variant<Elements...>& value)
480  {
481  std::string type;
482  std::string contentType;
483  peekType(type, contentType);
484  bool result = (detail::deserialize_variant<Elements>(*this, value, contentType) || ...);
485  SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
486  return *this;
487  }
488 
489  template <typename _Element, typename _Allocator>
490  inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
491  {
492  deserializeArray(items);
493 
494  return *this;
495  }
496 
497  template <typename _Element, std::size_t _Size>
498  inline Message& Message::operator>>(std::array<_Element, _Size>& items)
499  {
500  deserializeArray(items);
501 
502  return *this;
503  }
504 
505 #if __cplusplus >= 202002L
506  template <typename _Element, std::size_t _Extent>
507  inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
508  {
509  deserializeArray(items);
510 
511  return *this;
512  }
513 #endif
514 
515  template <typename _Enum, typename>
516  inline Message& Message::operator>>(_Enum& item)
517  {
518  std::underlying_type_t<_Enum> val;
519  *this >> val;
520  item = static_cast<_Enum>(val);
521  return *this;
522  }
523 
524  template <typename _Array>
525  inline void Message::deserializeArray(_Array& items)
526  {
527  using ElementType = typename _Array::value_type;
528 
529  // Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool,
530  // otherwise use step-by-step deserialization of individual elements.
531  if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
532  {
533  deserializeArrayFast(items);
534  }
535  else
536  {
537  deserializeArraySlow(items);
538  }
539  }
540 
541  template <typename _Array>
542  inline void Message::deserializeArrayFast(_Array& items)
543  {
544  using ElementType = typename _Array::value_type;
545 
546  size_t arraySize{};
547  const ElementType* arrayPtr{};
548 
549  readArray(*signature_of<ElementType>::str().c_str(), (const void**)&arrayPtr, &arraySize);
550 
551  size_t elementsInMsg = arraySize / sizeof(ElementType);
552  bool notEnoughSpace = items.size() < elementsInMsg;
553  SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL);
554 
555  std::copy_n(arrayPtr, elementsInMsg, items.begin());
556  }
557 
558  template <typename _Element, typename _Allocator>
559  void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items)
560  {
561  size_t arraySize{};
562  const _Element* arrayPtr{};
563 
564  readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize);
565 
566  items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
567  }
568 
569  template <typename _Array>
570  inline void Message::deserializeArraySlow(_Array& items)
571  {
572  using ElementType = typename _Array::value_type;
573 
574  if(!enterContainer(signature_of<ElementType>::str()))
575  return;
576 
577  for (auto& elem : items)
578  if (!(*this >> elem))
579  break; // Keep the rest in the destination sequence untouched
580 
581  SDBUS_THROW_ERROR_IF(!isAtEnd(false), "Failed to deserialize array: not enough space in destination sequence", EINVAL);
582 
583  clearFlags();
584 
585  exitContainer();
586  }
587 
588  template <typename _Element, typename _Allocator>
589  void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
590  {
591  if(!enterContainer(signature_of<_Element>::str()))
592  return;
593 
594  while (true)
595  {
596  _Element elem;
597  if (*this >> elem)
598  items.emplace_back(std::move(elem));
599  else
600  break;
601  }
602 
603  clearFlags();
604 
605  exitContainer();
606  }
607 
608  template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
609  inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
610  {
611  deserializeDictionary(items);
612 
613  return *this;
614  }
615 
616  template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
617  inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
618  {
619  deserializeDictionary(items);
620 
621  return *this;
622  }
623 
624  template <typename _Dictionary>
625  inline void Message::deserializeDictionary(_Dictionary& items)
626  {
627  using KeyType = typename _Dictionary::key_type;
628  using ValueType = typename _Dictionary::mapped_type;
629 
630  const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
631  const std::string arraySignature = "{" + dictEntrySignature + "}";
632 
633  if (!enterContainer(arraySignature))
634  return;
635 
636  while (true)
637  {
638  if (!enterDictEntry(dictEntrySignature))
639  break;
640 
641  KeyType key;
642  ValueType value;
643  *this >> key >> value;
644 
645  items.emplace(std::move(key), std::move(value));
646 
647  exitDictEntry();
648  }
649 
650  clearFlags();
651 
652  exitContainer();
653  }
654 
655  namespace detail
656  {
657  template <typename... _Args>
658  void deserialize_pack(Message& msg, _Args&... args)
659  {
660  (void)(msg >> ... >> args);
661  }
662 
663  template <class _Tuple, std::size_t... _Is>
664  void deserialize_tuple( Message& msg
665  , _Tuple& t
666  , std::index_sequence<_Is...> )
667  {
668  deserialize_pack(msg, std::get<_Is>(t)...);
669  }
670  }
671 
672  template <typename... _ValueTypes>
673  inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
674  {
675  auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
676  // Remove opening and closing parenthesis from the struct signature to get contents signature
677  auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
678 
679  if (!enterStruct(structContentSignature))
680  return *this;
681 
682  detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
683 
684  exitStruct();
685 
686  return *this;
687  }
688 
689  template <typename... _ValueTypes>
690  inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item)
691  {
692  detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
693  return *this;
694  }
695 
696 }
697 
698 #endif /* SDBUS_CXX_MESSAGE_H_ */
Definition: Error.h:44
Definition: Message.h:79
Definition: Message.h:242
Definition: Message.h:270
Definition: Types.h:177
Definition: Message.h:310
Definition: Message.h:300
Definition: Message.h:291
Definition: Message.h:280
Definition: Types.h:198
Definition: Types.h:132
Definition: Types.h:224
Definition: Types.h:54
Definition: TypeTraits.h:85
Definition: TypeTraits.h:82
Definition: TypeTraits.h:79
Definition: TypeTraits.h:107