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