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