xref: /openbmc/boost-dbus/include/dbus/message.hpp (revision 82a51ce2)
1 // Copyright (c) Benjamin Kietzman (github.com/bkietz)
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef DBUS_MESSAGE_HPP
7 #define DBUS_MESSAGE_HPP
8 
9 #include <dbus/dbus.h>
10 #include <dbus/element.hpp>
11 #include <dbus/endpoint.hpp>
12 #include <dbus/impl/message_iterator.hpp>
13 #include <iostream>
14 #include <vector>
15 #include <boost/intrusive_ptr.hpp>
16 #include <boost/utility/enable_if.hpp>
17 
18 inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
19 
20 inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
21 
22 namespace dbus {
23 
24 class message {
25   boost::intrusive_ptr<DBusMessage> message_;
26 
27  public:
28   /// Create a method call message
29   static message new_call(const endpoint& destination,
30                           const string& method_name) {
31     return dbus_message_new_method_call(
32         destination.get_process_name().c_str(), destination.get_path().c_str(),
33         destination.get_interface().c_str(), method_name.c_str());
34   }
35 
36   /// Create a method return message
37   static message new_return(message& call) {
38     return dbus_message_new_method_return(call);
39   }
40 
41   /// Create an error message
42   static message new_error(message& call, const string& error_name,
43                            const string& error_message) {
44     return dbus_message_new_error(call, error_name.c_str(),
45                                   error_message.c_str());
46   }
47 
48   /// Create a signal message
49   static message new_signal(const endpoint& origin, const string& signal_name) {
50     return dbus_message_new_signal(origin.get_path().c_str(),
51                                    origin.get_interface().c_str(),
52                                    signal_name.c_str());
53   }
54 
55   message() {}
56 
57   message(DBusMessage* m) : message_(dbus_message_ref(m)) {}
58 
59   operator DBusMessage*() { return message_.get(); }
60 
61   operator const DBusMessage*() const { return message_.get(); }
62 
63   string get_path() const {
64     return sanitize(dbus_message_get_path(message_.get()));
65   }
66 
67   string get_interface() const {
68     return sanitize(dbus_message_get_interface(message_.get()));
69   }
70 
71   string get_member() const {
72     return sanitize(dbus_message_get_member(message_.get()));
73   }
74 
75   string get_type() const {
76     return sanitize(
77         dbus_message_type_to_string(dbus_message_get_type(message_.get())));
78   }
79 
80   string get_sender() const {
81     return sanitize(dbus_message_get_sender(message_.get()));
82   }
83 
84   string get_destination() const {
85     return sanitize(dbus_message_get_destination(message_.get()));
86   }
87 
88   uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
89 
90   message& set_serial(uint32 serial) {
91     dbus_message_set_serial(message_.get(), serial);
92     return *this;
93   }
94 
95   uint32 get_reply_serial() {
96     return dbus_message_get_reply_serial(message_.get());
97   }
98 
99   message& set_reply_serial(uint32 reply_serial) {
100     dbus_message_set_reply_serial(message_.get(), reply_serial);
101     return *this;
102   }
103 
104   struct packer {
105     impl::message_iterator iter_;
106     packer(message& m) { impl::message_iterator::init_append(m, iter_); }
107     packer(){};
108     template <typename Element>
109     packer& pack(const Element& e) {
110       return *this << e;
111     }
112   };
113   struct unpacker {
114     impl::message_iterator iter_;
115     unpacker(message& m) { impl::message_iterator::init(m, iter_); }
116     unpacker() {}
117 
118     template <typename Element>
119     unpacker& unpack(Element& e) {
120       return *this >> e;
121     }
122   };
123 
124   template <typename Element>
125   packer pack(const Element& e) {
126     return packer(*this).pack(e);
127   }
128 
129   template <typename Element>
130   unpacker unpack(Element& e) {
131     return unpacker(*this).unpack(e);
132   }
133 
134  private:
135   static std::string sanitize(const char* str) {
136     return (str == NULL) ? "(null)" : str;
137   }
138 };
139 
140 template <typename Element>
141 message::packer operator<<(message m, const Element& e) {
142   return message::packer(m).pack(e);
143 }
144 
145 template <typename Element>
146 typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type
147 operator<<(message::packer& p, const Element& e) {
148   p.iter_.append_basic(element<Element>::code, &e);
149   return p;
150 }
151 
152 template <typename Key, typename Value>
153 message::packer& operator<<(message::packer& p,
154                             const std::vector<std::pair<Key, Value>>& v) {
155   message::packer sub;
156   char signature[] = {'{', element<Key>::code, element<Value>::code, '}', 0};
157 
158   p.iter_.open_container(DBUS_TYPE_ARRAY, signature, sub.iter_);
159   for (auto& element : v) {
160     sub << element;
161   }
162 
163   p.iter_.close_container(sub.iter_);
164   return p;
165 }
166 
167 template <typename Element>
168 message::packer& operator<<(message::packer& p, const std::vector<Element>& v) {
169   message::packer sub;
170   char signature[] = {element<Element>::code, 0};
171   p.iter_.open_container(element<std::vector<Element>>::code, signature,
172                          sub.iter_);
173   for (auto& element : v) {
174     sub << element;
175   }
176 
177   p.iter_.close_container(sub.iter_);
178   return p;
179 }
180 
181 inline message::packer& operator<<(message::packer& p, const char* c) {
182   p.iter_.append_basic(element<string>::code, &c);
183   return p;
184 }
185 
186 template <typename Key, typename Value>
187 inline message::packer& operator<<(message::packer& p,
188                                    const std::pair<Key, Value> element) {
189   message::packer dict_entry;
190   p.iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_);
191   dict_entry << element.first;
192   dict_entry << element.second;
193   p.iter_.close_container(dict_entry.iter_);
194   return p;
195 }
196 
197 inline message::packer& operator<<(message::packer& p, const string& e) {
198   const char* c = e.c_str();
199   return p << c;
200 }
201 
202 inline message::packer& operator<<(message::packer& p, const dbus_variant& v) {
203   message::packer sub;
204   char type = 0;
205   // TODO(ed) there must be a better (more typesafe) way to do this
206   switch (v.which()) {
207     case 0:
208       type = element<std::string>::code;
209       break;
210     case 1:
211       type = element<bool>::code;
212       break;
213     case 2:
214       type = element<byte>::code;
215       break;
216     case 3:
217       type = element<int16>::code;
218       break;
219     case 4:
220       type = element<uint16>::code;
221       break;
222     case 5:
223       type = element<int32>::code;
224       break;
225     case 6:
226       type = element<uint32>::code;
227       break;
228     case 7:
229       type = element<int64>::code;
230       break;
231     case 8:
232       type = element<uint64>::code;
233       break;
234     case 9:
235       type = element<double>::code;
236       break;
237 
238     default:
239       // TODO(ed) throw exception
240       break;
241   }
242   char signature[] = {type, 0};
243 
244   p.iter_.open_container(element<dbus_variant>::code, signature, sub.iter_);
245   boost::apply_visitor([&](auto val) { sub << val; }, v);
246   // sub << element;
247   p.iter_.close_container(sub.iter_);
248 
249   return p;
250 }
251 
252 template <typename Element>
253 message::unpacker operator>>(message m, Element& e) {
254   return message::unpacker(m).unpack(e);
255 }
256 
257 template <typename Element>
258 typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type
259 operator>>(message::unpacker& u, Element& e) {
260   u.iter_.get_basic(&e);
261   u.iter_.next();
262   return u;
263 }
264 
265 inline message::unpacker& operator>>(message::unpacker& u, string& s) {
266   const char* c;
267   u.iter_.get_basic(&c);
268   s.assign(c);
269   u.iter_.next();
270   return u;
271 }
272 
273 inline message::unpacker& operator>>(message::unpacker& u, dbus_variant& v) {
274   message::unpacker sub;
275   u.iter_.recurse(sub.iter_);
276 
277   auto x = sub.iter_.get_arg_type();
278   //sub.iter_.get_basic(&c);
279 
280   u.iter_.next();
281   return u;
282 }
283 
284 template <typename Key, typename Value>
285 inline message::unpacker& operator>>(message::unpacker& u, std::pair<Key, Value>& v) {
286   message::unpacker sub;
287   u.iter_.recurse(sub.iter_);
288   sub >> v.first;
289   sub >> v.second;
290 
291   u.iter_.next();
292   return u;
293 }
294 
295 template <typename Element>
296 inline message::unpacker& operator>>(message::unpacker& u,
297                                      std::vector<Element>& s) {
298   message::unpacker sub;
299   auto x = u.iter_.get_arg_type();
300   if (x == 115){
301 
302   }
303   u.iter_.recurse(sub.iter_);
304 
305   Element c;
306   while (sub.iter_.has_next()) {
307     s.emplace_back();
308     sub >> s.back();
309   }
310   u.iter_.next();
311   return u;
312 }
313 
314 inline std::ostream& operator<<(std::ostream& os, const message& m) {
315   os << "type='" << m.get_type() << "',"
316      << "sender='" << m.get_sender() << "',"
317      << "interface='" << m.get_interface() << "',"
318      << "member='" << m.get_member() << "',"
319      << "path='" << m.get_path() << "',"
320      << "destination='" << m.get_destination() << "'";
321   return os;
322 }
323 
324 }  // namespace dbus
325 
326 #include <dbus/impl/message_iterator.ipp>
327 
328 #endif  // DBUS_MESSAGE_HPP
329