1 /**
2  * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
3  * (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
4  *
5  * @file Message.h
6  *
7  * Created on: Nov 9, 2016
8  * Project: sdbus-c++
9  * Description: High-level D-Bus IPC C++ library based on sd-bus
10  *
11  * This file is part of sdbus-c++.
12  *
13  * sdbus-c++ is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU Lesser General Public License as published by
15  * the Free Software Foundation, either version 2.1 of the License, or
16  * (at your option) any later version.
17  *
18  * sdbus-c++ is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
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 <map>
35 #include <memory>
36 #include <utility>
37 #include <cstdint>
38 #include <cassert>
39 #include <functional>
40 #include <sys/types.h>
41 
42 // Forward declarations
43 namespace sdbus {
44     class Variant;
45     class ObjectPath;
46     class Signature;
47     template <typename... _ValueTypes> class Struct;
48     class UnixFd;
49     class MethodReply;
50     namespace internal {
51         class ISdBus;
52         class IConnection;
53     }
54 }
55 
56 namespace sdbus {
57 
58     // Assume the caller has already obtained message ownership
59     struct adopt_message_t { explicit adopt_message_t() = default; };
60     inline constexpr adopt_message_t adopt_message{};
61 
62     /********************************************//**
63      * @class Message
64      *
65      * Message represents a D-Bus message, which can be either method call message,
66      * method reply message, signal message, or a plain message serving as a storage
67      * for serialized data.
68      *
69      * Serialization and deserialization functions are provided for types supported
70      * by D-Bus.
71      *
72      * You don't need to work with this class directly if you use high-level APIs
73      * of @c IObject and @c IProxy.
74      *
75      ***********************************************/
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         Message& operator>>(bool& item);
96         Message& operator>>(int16_t& item);
97         Message& operator>>(int32_t& item);
98         Message& operator>>(int64_t& item);
99         Message& operator>>(uint8_t& item);
100         Message& operator>>(uint16_t& item);
101         Message& operator>>(uint32_t& item);
102         Message& operator>>(uint64_t& item);
103         Message& operator>>(double& item);
104         Message& operator>>(char*& item);
105         Message& operator>>(std::string &item);
106         Message& operator>>(Variant &item);
107         Message& operator>>(ObjectPath &item);
108         Message& operator>>(Signature &item);
109         Message& operator>>(UnixFd &item);
110 
111         Message& openContainer(const std::string& signature);
112         Message& closeContainer();
113         Message& openDictEntry(const std::string& signature);
114         Message& closeDictEntry();
115         Message& openVariant(const std::string& signature);
116         Message& closeVariant();
117         Message& openStruct(const std::string& signature);
118         Message& closeStruct();
119 
120         Message& enterContainer(const std::string& signature);
121         Message& exitContainer();
122         Message& enterDictEntry(const std::string& signature);
123         Message& exitDictEntry();
124         Message& enterVariant(const std::string& signature);
125         Message& exitVariant();
126         Message& enterStruct(const std::string& signature);
127         Message& exitStruct();
128 
129         explicit operator bool() const;
130         void clearFlags();
131 
132         std::string getInterfaceName() const;
133         std::string getMemberName() const;
134         std::string getSender() const;
135         std::string getPath() const;
136         std::string getDestination() const;
137         void peekType(std::string& type, std::string& contents) const;
138         bool isValid() const;
139         bool isEmpty() const;
140 
141         void copyTo(Message& destination, bool complete) const;
142         void seal();
143         void rewind(bool complete);
144 
145         pid_t getCredsPid() const;
146         uid_t getCredsUid() const;
147         uid_t getCredsEuid() const;
148         gid_t getCredsGid() const;
149         gid_t getCredsEgid() const;
150         std::vector<gid_t> getCredsSupplementaryGids() const;
151         std::string getSELinuxContext() const;
152 
153         class Factory;
154 
155     protected:
156         Message() = default;
157         explicit Message(internal::ISdBus* sdbus) noexcept;
158         Message(void *msg, internal::ISdBus* sdbus) noexcept;
159         Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept;
160 
161         Message(const Message&) noexcept;
162         Message& operator=(const Message&) noexcept;
163         Message(Message&& other) noexcept;
164         Message& operator=(Message&& other) noexcept;
165 
166         ~Message();
167 
168         friend Factory;
169 
170     protected:
171         void* msg_{};
172         internal::ISdBus* sdbus_{};
173         mutable bool ok_{true};
174     };
175 
176     struct dont_request_slot_t { explicit dont_request_slot_t() = default; };
177     inline constexpr dont_request_slot_t dont_request_slot{};
178 
179     class MethodCall : public Message
180     {
181         using Message::Message;
182         friend Factory;
183 
184     public:
185         using Slot = std::unique_ptr<void, std::function<void(void*)>>;
186 
187         MethodCall() = default;
188 
189         MethodReply send(uint64_t timeout) const;
190         void send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const;
191         [[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const;
192 
193         MethodReply createReply() const;
194         MethodReply createErrorReply(const sdbus::Error& error) const;
195 
196         void dontExpectReply();
197         bool doesntExpectReply() const;
198 
199     protected:
200         MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept;
201 
202     private:
203         MethodReply sendWithReply(uint64_t timeout = 0) const;
204         MethodReply sendWithNoReply() const;
205         const internal::IConnection* connection_{};
206     };
207 
208     class MethodReply : public Message
209     {
210         using Message::Message;
211         friend Factory;
212 
213     public:
214         MethodReply() = default;
215         void send() const;
216     };
217 
218     class Signal : public Message
219     {
220         using Message::Message;
221         friend Factory;
222 
223     public:
224         Signal() = default;
225         void setDestination(const std::string& destination);
226         void send() const;
227     };
228 
229     class PropertySetCall : public Message
230     {
231         using Message::Message;
232         friend Factory;
233 
234     public:
235         PropertySetCall() = default;
236     };
237 
238     class PropertyGetReply : public Message
239     {
240         using Message::Message;
241         friend Factory;
242 
243     public:
244         PropertyGetReply() = default;
245     };
246 
247     class PlainMessage : public Message
248     {
249         using Message::Message;
250         friend Factory;
251 
252     public:
253         PlainMessage() = default;
254     };
255 
256     template <typename _Element>
257     inline Message& operator<<(Message& msg, const std::vector<_Element>& items)
258     {
259         msg.openContainer(signature_of<_Element>::str());
260 
261         for (const auto& item : items)
262             msg << item;
263 
264         msg.closeContainer();
265 
266         return msg;
267     }
268 
269     template <typename _Key, typename _Value>
270     inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items)
271     {
272         const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
273         const std::string arraySignature = "{" + dictEntrySignature + "}";
274 
275         msg.openContainer(arraySignature);
276 
277         for (const auto& item : items)
278         {
279             msg.openDictEntry(dictEntrySignature);
280             msg << item.first;
281             msg << item.second;
282             msg.closeDictEntry();
283         }
284 
285         msg.closeContainer();
286 
287         return msg;
288     }
289 
290     namespace detail
291     {
292         template <typename... _Args>
serialize_pack(Message & msg,_Args &&...args)293         void serialize_pack(Message& msg, _Args&&... args)
294         {
295             (void)(msg << ... << args);
296         }
297 
298         template <class _Tuple, std::size_t... _Is>
serialize_tuple(Message & msg,const _Tuple & t,std::index_sequence<_Is...>)299         void serialize_tuple( Message& msg
300                             , const _Tuple& t
301                             , std::index_sequence<_Is...>)
302         {
303             serialize_pack(msg, std::get<_Is>(t)...);
304         }
305     }
306 
307     template <typename... _ValueTypes>
308     inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item)
309     {
310         auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
311         assert(structSignature.size() > 2);
312         // Remove opening and closing parenthesis from the struct signature to get contents signature
313         auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
314 
315         msg.openStruct(structContentSignature);
316         detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
317         msg.closeStruct();
318 
319         return msg;
320     }
321 
322     template <typename... _ValueTypes>
323     inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item)
324     {
325         detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
326         return msg;
327     }
328 
329 
330     template <typename _Element>
331     inline Message& operator>>(Message& msg, std::vector<_Element>& items)
332     {
333         if(!msg.enterContainer(signature_of<_Element>::str()))
334             return msg;
335 
336         while (true)
337         {
338             _Element elem;
339             if (msg >> elem)
340                 items.emplace_back(std::move(elem));
341             else
342                 break;
343         }
344 
345         msg.clearFlags();
346 
347         msg.exitContainer();
348 
349         return msg;
350     }
351 
352     template <typename _Key, typename _Value>
353     inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items)
354     {
355         const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
356         const std::string arraySignature = "{" + dictEntrySignature + "}";
357 
358         if (!msg.enterContainer(arraySignature))
359             return msg;
360 
361         while (true)
362         {
363             if (!msg.enterDictEntry(dictEntrySignature))
364                 break;
365 
366             _Key key;
367             _Value value;
368             msg >> key >> value;
369 
370             items.emplace(std::move(key), std::move(value));
371 
372             msg.exitDictEntry();
373         }
374 
375         msg.clearFlags();
376 
377         msg.exitContainer();
378 
379         return msg;
380     }
381 
382     namespace detail
383     {
384         template <typename... _Args>
deserialize_pack(Message & msg,_Args &...args)385         void deserialize_pack(Message& msg, _Args&... args)
386         {
387             (void)(msg >> ... >> args);
388         }
389 
390         template <class _Tuple, std::size_t... _Is>
deserialize_tuple(Message & msg,_Tuple & t,std::index_sequence<_Is...>)391         void deserialize_tuple( Message& msg
392                               , _Tuple& t
393                               , std::index_sequence<_Is...> )
394         {
395             deserialize_pack(msg, std::get<_Is>(t)...);
396         }
397     }
398 
399     template <typename... _ValueTypes>
400     inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item)
401     {
402         auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
403         // Remove opening and closing parenthesis from the struct signature to get contents signature
404         auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
405 
406         if (!msg.enterStruct(structContentSignature))
407             return msg;
408 
409         detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
410 
411         msg.exitStruct();
412 
413         return msg;
414     }
415 
416     template <typename... _ValueTypes>
417     inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item)
418     {
419         detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
420         return msg;
421     }
422 
423 }
424 
425 #endif /* SDBUS_CXX_MESSAGE_H_ */
426