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