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