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