sdbus-c++: include/sdbus-c++/Message.h Source File

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