sdbus-c++ 2.1.0
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
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 // TODO: short docs in whole Message API
219 std::pair<char, const char*> peekType() const;
220 bool isValid() const;
221 bool isEmpty() const;
222 bool isAtEnd(bool complete) const;
223
224 void copyTo(Message& destination, bool complete) const;
225 void seal();
226 void rewind(bool complete);
227
228 pid_t getCredsPid() const;
229 uid_t getCredsUid() const;
230 uid_t getCredsEuid() const;
231 gid_t getCredsGid() const;
232 gid_t getCredsEgid() const;
233 std::vector<gid_t> getCredsSupplementaryGids() const;
234 std::string getSELinuxContext() const;
235
236 class Factory;
237
238 private:
239 template <typename _Array>
240 void serializeArray(const _Array& items);
241 template <typename _Array>
242 void deserializeArray(_Array& items);
243 template <typename _Array>
244 void deserializeArrayFast(_Array& items);
245 template <typename _Element, typename _Allocator>
246 void deserializeArrayFast(std::vector<_Element, _Allocator>& items);
247 template <typename _Array>
248 void deserializeArraySlow(_Array& items);
249 template <typename _Element, typename _Allocator>
250 void deserializeArraySlow(std::vector<_Element, _Allocator>& items);
251
252 protected:
253 Message() = default;
254 explicit Message(internal::IConnection* connection) noexcept;
255 Message(void *msg, internal::IConnection* connection) noexcept;
256 Message(void *msg, internal::IConnection* connection, adopt_message_t) noexcept;
257
258 friend Factory;
259
260 protected:
261 void* msg_{};
262 internal::IConnection* connection_{};
263 mutable bool ok_{true};
264 };
265
266 class MethodCall : public Message
267 {
268 using Message::Message;
269 friend Factory;
270
271 public:
272 MethodCall() = default;
273
274 MethodReply send(uint64_t timeout) const;
275 [[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout, return_slot_t) const;
276
277 MethodReply createReply() const;
278 MethodReply createErrorReply(const sdbus::Error& error) const;
279
280 void dontExpectReply();
281 bool doesntExpectReply() const;
282
283 protected:
284 MethodCall(void *msg, internal::IConnection* connection, adopt_message_t) noexcept;
285
286 private:
287 MethodReply sendWithReply(uint64_t timeout = 0) const;
288 MethodReply sendWithNoReply() const;
289 };
290
291 class MethodReply : public Message
292 {
293 using Message::Message;
294 friend Factory;
295
296 public:
297 MethodReply() = default;
298 void send() const;
299 };
300
301 class Signal : public Message
302 {
303 using Message::Message;
304 friend Factory;
305
306 public:
307 Signal() = default;
308 void setDestination(const std::string& destination);
309 void setDestination(const char* destination);
310 void send() const;
311 };
312
314 {
315 using Message::Message;
316 friend Factory;
317
318 public:
319 PropertySetCall() = default;
320 };
321
323 {
324 using Message::Message;
325 friend Factory;
326
327 public:
328 PropertyGetReply() = default;
329 };
330
331 // Represents any of the above message types, or just a message that serves as a container for data
332 class PlainMessage : public Message
333 {
334 using Message::Message;
335 friend Factory;
336
337 public:
338 PlainMessage() = default;
339 };
340
341 PlainMessage createPlainMessage();
342
343 template <typename ...Elements>
344 inline Message& Message::operator<<(const std::variant<Elements...>& value)
345 {
346 std::visit([this](const auto& inner)
347 {
348 openVariant<decltype(inner)>();
349 *this << inner;
350 closeVariant();
351 }, value);
352
353 return *this;
354 }
355
356 template <typename _Element, typename _Allocator>
357 inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
358 {
359 serializeArray(items);
360
361 return *this;
362 }
363
364 template <typename _Element, std::size_t _Size>
365 inline Message& Message::operator<<(const std::array<_Element, _Size>& items)
366 {
367 serializeArray(items);
368
369 return *this;
370 }
371
372#ifdef __cpp_lib_span
373 template <typename _Element, std::size_t _Extent>
374 inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
375 {
376 serializeArray(items);
377
378 return *this;
379 }
380#endif
381
382 template <typename _Enum, typename>
383 inline Message& Message::operator<<(const _Enum &item)
384 {
385 return operator<<(static_cast<std::underlying_type_t<_Enum>>(item));
386 }
387
388 template <typename _Array>
389 inline void Message::serializeArray(const _Array& items)
390 {
391 using ElementType = typename _Array::value_type;
392
393 // Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool,
394 // otherwise use step-by-step serialization of individual elements.
395 if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
396 {
397 constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
398 appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType));
399 }
400 else
401 {
402 openContainer<ElementType>();
403
404 for (const auto& item : items)
405 *this << item;
406
407 closeContainer();
408 }
409 }
410
411 template <typename _Key, typename _Value>
412 inline Message& Message::operator<<(const DictEntry<_Key, _Value>& value)
413 {
414 openDictEntry<_Key, _Value>();
415 *this << value.first;
416 *this << value.second;
417 closeDictEntry();
418
419 return *this;
420 }
421
422 template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
423 inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
424 {
425 serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
426
427 return *this;
428 }
429
430 template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
431 inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
432 {
433 serializeDictionary<_Key, _Value>([&items](Message& msg){ for (const auto& item : items) msg << item; });
434
435 return *this;
436 }
437
438 template <typename _Key, typename _Value>
439 inline Message& Message::serializeDictionary(const std::initializer_list<DictEntry<_Key, _Value>>& items)
440 {
441 serializeDictionary<_Key, _Value>([&](Message& msg){ for (const auto& item : items) msg << item; });
442
443 return *this;
444 }
445
446 template <typename _Key, typename _Value, typename _Callback>
447 inline Message& Message::serializeDictionary(const _Callback& callback)
448 {
449 openContainer<DictEntry<_Key, _Value>>();
450 callback(*this);
451 closeContainer();
452
453 return *this;
454 }
455
456 namespace detail
457 {
458 template <typename... _Args>
459 void serialize_pack(Message& msg, _Args&&... args)
460 {
461 (void)(msg << ... << args);
462 }
463
464 template <class _Tuple, std::size_t... _Is>
465 void serialize_tuple( Message& msg
466 , const _Tuple& t
467 , std::index_sequence<_Is...>)
468 {
469 serialize_pack(msg, std::get<_Is>(t)...);
470 }
471 }
472
473 template <typename... _ValueTypes>
474 inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
475 {
476 openStruct<_ValueTypes...>();
477 detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
478 closeStruct();
479
480 return *this;
481 }
482
483 template <typename... _ValueTypes>
484 inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item)
485 {
486 detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
487 return *this;
488 }
489
490 namespace detail
491 {
492 template <typename _Element, typename... _Elements>
493 bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const char* signature)
494 {
495 constexpr auto elemSignature = as_null_terminated(sdbus::signature_of_v<_Element>);
496 if (std::strcmp(signature, elemSignature.data()) != 0)
497 return false;
498
499 _Element temp;
500 msg.enterVariant(signature);
501 msg >> temp;
502 msg.exitVariant();
503 value = std::move(temp);
504 return true;
505 }
506 }
507
508 template <typename... Elements>
509 inline Message& Message::operator>>(std::variant<Elements...>& value)
510 {
511 auto [type, contents] = peekType();
512 bool result = (detail::deserialize_variant<Elements>(*this, value, contents) || ...);
513 SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
514 return *this;
515 }
516
517 template <typename _Element, typename _Allocator>
518 inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
519 {
520 deserializeArray(items);
521
522 return *this;
523 }
524
525 template <typename _Element, std::size_t _Size>
526 inline Message& Message::operator>>(std::array<_Element, _Size>& items)
527 {
528 deserializeArray(items);
529
530 return *this;
531 }
532
533#ifdef __cpp_lib_span
534 template <typename _Element, std::size_t _Extent>
535 inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
536 {
537 deserializeArray(items);
538
539 return *this;
540 }
541#endif
542
543 template <typename _Enum, typename>
544 inline Message& Message::operator>>(_Enum& item)
545 {
546 std::underlying_type_t<_Enum> val;
547 *this >> val;
548 item = static_cast<_Enum>(val);
549 return *this;
550 }
551
552 template <typename _Array>
553 inline void Message::deserializeArray(_Array& items)
554 {
555 using ElementType = typename _Array::value_type;
556
557 // Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool,
558 // otherwise use step-by-step deserialization of individual elements.
559 if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
560 {
561 deserializeArrayFast(items);
562 }
563 else
564 {
565 deserializeArraySlow(items);
566 }
567 }
568
569 template <typename _Array>
570 inline void Message::deserializeArrayFast(_Array& items)
571 {
572 using ElementType = typename _Array::value_type;
573
574 size_t arraySize{};
575 const ElementType* arrayPtr{};
576
577 constexpr auto signature = as_null_terminated(sdbus::signature_of_v<ElementType>);
578 readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
579
580 size_t elementsInMsg = arraySize / sizeof(ElementType);
581 bool notEnoughSpace = items.size() < elementsInMsg;
582 SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL);
583
584 std::copy_n(arrayPtr, elementsInMsg, items.begin());
585 }
586
587 template <typename _Element, typename _Allocator>
588 void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items)
589 {
590 size_t arraySize{};
591 const _Element* arrayPtr{};
592
593 constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>);
594 readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
595
596 items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
597 }
598
599 template <typename _Array>
600 inline void Message::deserializeArraySlow(_Array& items)
601 {
602 using ElementType = typename _Array::value_type;
603
604 if(!enterContainer<ElementType>())
605 return;
606
607 for (auto& elem : items)
608 if (!(*this >> elem))
609 break; // Keep the rest in the destination sequence untouched
610
611 SDBUS_THROW_ERROR_IF(!isAtEnd(false), "Failed to deserialize array: not enough space in destination sequence", EINVAL);
612
613 clearFlags();
614
615 exitContainer();
616 }
617
618 template <typename _Element, typename _Allocator>
619 void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
620 {
621 if(!enterContainer<_Element>())
622 return;
623
624 while (true)
625 {
626 _Element elem;
627 if (*this >> elem)
628 items.emplace_back(std::move(elem));
629 else
630 break;
631 }
632
633 clearFlags();
634
635 exitContainer();
636 }
637
638 template <typename _Key, typename _Value>
639 inline Message& Message::operator>>(DictEntry<_Key, _Value>& value)
640 {
641 if (!enterDictEntry<_Key, _Value>())
642 return *this;
643 *this >> value.first >> value.second;
644 exitDictEntry();
645
646 return *this;
647 }
648
649 template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
650 inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
651 {
652 deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
653
654 return *this;
655 }
656
657 template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
658 inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
659 {
660 deserializeDictionary<_Key, _Value>([&items](auto dictEntry){ items.insert(std::move(dictEntry)); });
661
662 return *this;
663 }
664
665 template <typename _Key, typename _Value, typename _Callback>
666 inline Message& Message::deserializeDictionary(const _Callback& callback)
667 {
668 if (!enterContainer<DictEntry<_Key, _Value>>())
669 return *this;
670
671 while (true)
672 {
673 DictEntry<_Key, _Value> dictEntry;
674 *this >> dictEntry;
675 if (!*this)
676 break;
677 callback(std::move(dictEntry));
678 }
679 clearFlags();
680
681 exitContainer();
682
683 return *this;
684 }
685
686 namespace detail
687 {
688 template <typename... _Args>
689 void deserialize_pack(Message& msg, _Args&... args)
690 {
691 (void)(msg >> ... >> args);
692 }
693
694 template <class _Tuple, std::size_t... _Is>
695 void deserialize_tuple( Message& msg
696 , _Tuple& t
697 , std::index_sequence<_Is...> )
698 {
699 deserialize_pack(msg, std::get<_Is>(t)...);
700 }
701 }
702
703 template <typename... _ValueTypes>
704 inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
705 {
706 if (!enterStruct<_ValueTypes...>())
707 return *this;
708
709 detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
710
711 exitStruct();
712
713 return *this;
714 }
715
716 template <typename... _ValueTypes>
717 inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item)
718 {
719 detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
720 return *this;
721 }
722
723 template <typename _ElementType>
724 inline Message& Message::openContainer()
725 {
726 constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
727 return openContainer(signature.data());
728 }
729
730 template <typename _KeyType, typename _ValueType>
731 inline Message& Message::openDictEntry()
732 {
733 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
734 return openDictEntry(signature.data());
735 }
736
737 template <typename _ValueType>
738 inline Message& Message::openVariant()
739 {
740 constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
741 return openVariant(signature.data());
742 }
743
744 template <typename... _ValueTypes>
745 inline Message& Message::openStruct()
746 {
747 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
748 return openStruct(signature.data());
749 }
750
751 template <typename _ElementType>
752 inline Message& Message::enterContainer()
753 {
754 constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
755 return enterContainer(signature.data());
756 }
757
758 template <typename _KeyType, typename _ValueType>
759 inline Message& Message::enterDictEntry()
760 {
761 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
762 return enterDictEntry(signature.data());
763 }
764
765 template <typename _ValueType>
766 inline Message& Message::enterVariant()
767 {
768 constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
769 return enterVariant(signature.data());
770 }
771
772 template <typename... _ValueTypes>
773 inline Message& Message::enterStruct()
774 {
775 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
776 return enterStruct(signature.data());
777 }
778
779}
780
781#endif /* SDBUS_CXX_MESSAGE_H_ */
Definition Error.h:44
Definition Message.h:81
Definition Message.h:267
Definition Message.h:292
Definition Types.h:195
Definition Message.h:333
Definition Message.h:323
Definition Message.h:314
Definition Message.h:302
Definition Types.h:282
Definition Types.h:307
Definition Types.h:57
Definition TypeTraits.h:94
Definition TypeTraits.h:88