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