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 ISdBus;
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::ISdBus* sdbus) noexcept;
249 Message(void *msg, internal::ISdBus* sdbus) noexcept;
250 Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
251
252 friend Factory;
253
254 protected:
255 void* msg_{};
256 internal::ISdBus* sdbus_{};
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::ISdBus* sdbus, 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 template <typename ...Elements>
336 inline Message& Message::operator<<(const std::variant<Elements...>& value)
337 {
338 std::visit([this](const auto& inner)
339 {
340 openVariant<decltype(inner)>();
341 *this << inner;
342 closeVariant();
343 }, value);
344
345 return *this;
346 }
347
348 template <typename _Element, typename _Allocator>
349 inline Message& Message::operator<<(const std::vector<_Element, _Allocator>& items)
350 {
351 serializeArray(items);
352
353 return *this;
354 }
355
356 template <typename _Element, std::size_t _Size>
357 inline Message& Message::operator<<(const std::array<_Element, _Size>& items)
358 {
359 serializeArray(items);
360
361 return *this;
362 }
363
364#ifdef __cpp_lib_span
365 template <typename _Element, std::size_t _Extent>
366 inline Message& Message::operator<<(const std::span<_Element, _Extent>& items)
367 {
368 serializeArray(items);
369
370 return *this;
371 }
372#endif
373
374 template <typename _Enum, typename>
375 inline Message& Message::operator<<(const _Enum &item)
376 {
377 return operator<<(static_cast<std::underlying_type_t<_Enum>>(item));
378 }
379
380 template <typename _Array>
381 inline void Message::serializeArray(const _Array& items)
382 {
383 using ElementType = typename _Array::value_type;
384
385 // Use faster, one-step serialization of contiguous array of elements of trivial D-Bus types except bool,
386 // otherwise use step-by-step serialization of individual elements.
387 if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
388 {
389 constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
390 appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType));
391 }
392 else
393 {
394 openContainer<ElementType>();
395
396 for (const auto& item : items)
397 *this << item;
398
399 closeContainer();
400 }
401 }
402
403 template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
404 inline Message& Message::operator<<(const std::map<_Key, _Value, _Compare, _Allocator>& items)
405 {
406 serializeDictionary(items);
407
408 return *this;
409 }
410
411 template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
412 inline Message& Message::operator<<(const std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
413 {
414 serializeDictionary(items);
415
416 return *this;
417 }
418
419 template <typename _Dictionary>
420 inline void Message::serializeDictionary(const _Dictionary& items)
421 {
422 using KeyType = typename _Dictionary::key_type;
423 using MappedType = typename _Dictionary::mapped_type;
424
425 openContainer<DictEntry<KeyType, MappedType>>();
426
427 for (const auto& item : items)
428 {
429 openDictEntry<KeyType, MappedType>();
430 *this << item.first;
431 *this << item.second;
432 closeDictEntry();
433 }
434
435 closeContainer();
436 }
437
438 namespace detail
439 {
440 template <typename... _Args>
441 void serialize_pack(Message& msg, _Args&&... args)
442 {
443 (void)(msg << ... << args);
444 }
445
446 template <class _Tuple, std::size_t... _Is>
447 void serialize_tuple( Message& msg
448 , const _Tuple& t
449 , std::index_sequence<_Is...>)
450 {
451 serialize_pack(msg, std::get<_Is>(t)...);
452 }
453 }
454
455 template <typename... _ValueTypes>
456 inline Message& Message::operator<<(const Struct<_ValueTypes...>& item)
457 {
458 openStruct<_ValueTypes...>();
459 detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
460 closeStruct();
461
462 return *this;
463 }
464
465 template <typename... _ValueTypes>
466 inline Message& Message::operator<<(const std::tuple<_ValueTypes...>& item)
467 {
468 detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
469 return *this;
470 }
471
472 namespace detail
473 {
474 template <typename _Element, typename... _Elements>
475 bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const char* signature)
476 {
477 constexpr auto elemSignature = as_null_terminated(sdbus::signature_of_v<_Element>);
478 if (std::strcmp(signature, elemSignature.data()) != 0)
479 return false;
480
481 _Element temp;
482 msg.enterVariant(signature);
483 msg >> temp;
484 msg.exitVariant();
485 value = std::move(temp);
486 return true;
487 }
488 }
489
490 template <typename... Elements>
491 inline Message& Message::operator>>(std::variant<Elements...>& value)
492 {
493 auto [type, contents] = peekType();
494 bool result = (detail::deserialize_variant<Elements>(*this, value, contents) || ...);
495 SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
496 return *this;
497 }
498
499 template <typename _Element, typename _Allocator>
500 inline Message& Message::operator>>(std::vector<_Element, _Allocator>& items)
501 {
502 deserializeArray(items);
503
504 return *this;
505 }
506
507 template <typename _Element, std::size_t _Size>
508 inline Message& Message::operator>>(std::array<_Element, _Size>& items)
509 {
510 deserializeArray(items);
511
512 return *this;
513 }
514
515#ifdef __cpp_lib_span
516 template <typename _Element, std::size_t _Extent>
517 inline Message& Message::operator>>(std::span<_Element, _Extent>& items)
518 {
519 deserializeArray(items);
520
521 return *this;
522 }
523#endif
524
525 template <typename _Enum, typename>
526 inline Message& Message::operator>>(_Enum& item)
527 {
528 std::underlying_type_t<_Enum> val;
529 *this >> val;
530 item = static_cast<_Enum>(val);
531 return *this;
532 }
533
534 template <typename _Array>
535 inline void Message::deserializeArray(_Array& items)
536 {
537 using ElementType = typename _Array::value_type;
538
539 // Use faster, one-step deserialization of contiguous array of elements of trivial D-Bus types except bool,
540 // otherwise use step-by-step deserialization of individual elements.
541 if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
542 {
543 deserializeArrayFast(items);
544 }
545 else
546 {
547 deserializeArraySlow(items);
548 }
549 }
550
551 template <typename _Array>
552 inline void Message::deserializeArrayFast(_Array& items)
553 {
554 using ElementType = typename _Array::value_type;
555
556 size_t arraySize{};
557 const ElementType* arrayPtr{};
558
559 constexpr auto signature = as_null_terminated(sdbus::signature_of_v<ElementType>);
560 readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
561
562 size_t elementsInMsg = arraySize / sizeof(ElementType);
563 bool notEnoughSpace = items.size() < elementsInMsg;
564 SDBUS_THROW_ERROR_IF(notEnoughSpace, "Failed to deserialize array: not enough space in destination sequence", EINVAL);
565
566 std::copy_n(arrayPtr, elementsInMsg, items.begin());
567 }
568
569 template <typename _Element, typename _Allocator>
570 void Message::deserializeArrayFast(std::vector<_Element, _Allocator>& items)
571 {
572 size_t arraySize{};
573 const _Element* arrayPtr{};
574
575 constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>);
576 readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
577
578 items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
579 }
580
581 template <typename _Array>
582 inline void Message::deserializeArraySlow(_Array& items)
583 {
584 using ElementType = typename _Array::value_type;
585
586 if(!enterContainer<ElementType>())
587 return;
588
589 for (auto& elem : items)
590 if (!(*this >> elem))
591 break; // Keep the rest in the destination sequence untouched
592
593 SDBUS_THROW_ERROR_IF(!isAtEnd(false), "Failed to deserialize array: not enough space in destination sequence", EINVAL);
594
595 clearFlags();
596
597 exitContainer();
598 }
599
600 template <typename _Element, typename _Allocator>
601 void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
602 {
603 if(!enterContainer<_Element>())
604 return;
605
606 while (true)
607 {
608 _Element elem;
609 if (*this >> elem)
610 items.emplace_back(std::move(elem));
611 else
612 break;
613 }
614
615 clearFlags();
616
617 exitContainer();
618 }
619
620 template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
621 inline Message& Message::operator>>(std::map<_Key, _Value, _Compare, _Allocator>& items)
622 {
623 deserializeDictionary(items);
624
625 return *this;
626 }
627
628 template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
629 inline Message& Message::operator>>(std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>& items)
630 {
631 deserializeDictionary(items);
632
633 return *this;
634 }
635
636 template <typename _Dictionary>
637 inline void Message::deserializeDictionary(_Dictionary& items)
638 {
639 using KeyType = typename _Dictionary::key_type;
640 using MappedType = typename _Dictionary::mapped_type;
641
642 if (!enterContainer<DictEntry<KeyType, MappedType>>())
643 return;
644
645 while (true)
646 {
647 if (!enterDictEntry<KeyType, MappedType>())
648 break;
649
650 KeyType key;
651 MappedType value;
652 *this >> key >> value;
653
654 items.emplace(std::move(key), std::move(value));
655
656 exitDictEntry();
657 }
658
659 clearFlags();
660
661 exitContainer();
662 }
663
664 namespace detail
665 {
666 template <typename... _Args>
667 void deserialize_pack(Message& msg, _Args&... args)
668 {
669 (void)(msg >> ... >> args);
670 }
671
672 template <class _Tuple, std::size_t... _Is>
673 void deserialize_tuple( Message& msg
674 , _Tuple& t
675 , std::index_sequence<_Is...> )
676 {
677 deserialize_pack(msg, std::get<_Is>(t)...);
678 }
679 }
680
681 template <typename... _ValueTypes>
682 inline Message& Message::operator>>(Struct<_ValueTypes...>& item)
683 {
684 if (!enterStruct<_ValueTypes...>())
685 return *this;
686
687 detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
688
689 exitStruct();
690
691 return *this;
692 }
693
694 template <typename... _ValueTypes>
695 inline Message& Message::operator>>(std::tuple<_ValueTypes...>& item)
696 {
697 detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
698 return *this;
699 }
700
701 template <typename _ElementType>
702 inline Message& Message::openContainer()
703 {
704 constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
705 return openContainer(signature.data());
706 }
707
708 template <typename _KeyType, typename _ValueType>
709 inline Message& Message::openDictEntry()
710 {
711 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
712 return openDictEntry(signature.data());
713 }
714
715 template <typename _ValueType>
716 inline Message& Message::openVariant()
717 {
718 constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
719 return openVariant(signature.data());
720 }
721
722 template <typename... _ValueTypes>
723 inline Message& Message::openStruct()
724 {
725 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
726 return openStruct(signature.data());
727 }
728
729 template <typename _ElementType>
730 inline Message& Message::enterContainer()
731 {
732 constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
733 return enterContainer(signature.data());
734 }
735
736 template <typename _KeyType, typename _ValueType>
737 inline Message& Message::enterDictEntry()
738 {
739 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
740 return enterDictEntry(signature.data());
741 }
742
743 template <typename _ValueType>
744 inline Message& Message::enterVariant()
745 {
746 constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
747 return enterVariant(signature.data());
748 }
749
750 template <typename... _ValueTypes>
751 inline Message& Message::enterStruct()
752 {
753 constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
754 return enterStruct(signature.data());
755 }
756
757}
758
759#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:289
Definition Types.h:56
Definition TypeTraits.h:94
Definition TypeTraits.h:88