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/mpl/for_each.hpp> 17 #include <boost/utility/enable_if.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 private: 27 boost::intrusive_ptr<DBusMessage> message_; 28 29 public: 30 /// Create a method call message 31 static message new_call(const endpoint& destination) { 32 auto x = message(dbus_message_new_method_call( 33 destination.get_process_name().c_str(), destination.get_path().c_str(), 34 destination.get_interface().c_str(), destination.get_member().c_str())); 35 dbus_message_unref(x.message_.get()); 36 return x; 37 } 38 39 /// Create a method call message 40 static message new_call(const endpoint& destination, 41 const string& method_name) { 42 auto x = message(dbus_message_new_method_call( 43 destination.get_process_name().c_str(), destination.get_path().c_str(), 44 destination.get_interface().c_str(), method_name.c_str())); 45 dbus_message_unref(x.message_.get()); 46 return x; 47 } 48 49 /// Create a method return message 50 static message new_return(message& call) { 51 auto x = message(dbus_message_new_method_return(call)); 52 dbus_message_unref(x.message_.get()); 53 return x; 54 } 55 56 /// Create an error message 57 static message new_error(message& call, const string& error_name, 58 const string& error_message) { 59 auto x = message(dbus_message_new_error(call, error_name.c_str(), 60 error_message.c_str())); 61 dbus_message_unref(x.message_.get()); 62 return x; 63 } 64 65 /// Create a signal message 66 static message new_signal(const endpoint& origin, const string& signal_name) { 67 auto x = message(dbus_message_new_signal(origin.get_path().c_str(), 68 origin.get_interface().c_str(), 69 signal_name.c_str())); 70 dbus_message_unref(x.message_.get()); 71 return x; 72 } 73 74 message() = delete; 75 76 message(DBusMessage* m) : message_(m) {} 77 78 operator DBusMessage*() { return message_.get(); } 79 80 operator const DBusMessage*() const { return message_.get(); } 81 82 string get_path() const { 83 return sanitize(dbus_message_get_path(message_.get())); 84 } 85 86 string get_interface() const { 87 return sanitize(dbus_message_get_interface(message_.get())); 88 } 89 90 string get_member() const { 91 return sanitize(dbus_message_get_member(message_.get())); 92 } 93 94 string get_type() const { 95 return sanitize( 96 dbus_message_type_to_string(dbus_message_get_type(message_.get()))); 97 } 98 99 string get_signature() const { 100 return sanitize(dbus_message_get_signature(message_.get())); 101 } 102 103 string get_sender() const { 104 return sanitize(dbus_message_get_sender(message_.get())); 105 } 106 107 string get_destination() const { 108 return sanitize(dbus_message_get_destination(message_.get())); 109 } 110 111 uint32 get_serial() { return dbus_message_get_serial(message_.get()); } 112 113 message& set_serial(uint32 serial) { 114 dbus_message_set_serial(message_.get(), serial); 115 return *this; 116 } 117 118 uint32 get_reply_serial() { 119 return dbus_message_get_reply_serial(message_.get()); 120 } 121 122 message& set_reply_serial(uint32 reply_serial) { 123 dbus_message_set_reply_serial(message_.get(), reply_serial); 124 return *this; 125 } 126 127 struct packer { 128 impl::message_iterator iter_; 129 packer(message& m) { impl::message_iterator::init_append(m, iter_); } 130 packer(){}; 131 132 template <typename Element, typename... Args> 133 bool pack(const Element& e, const Args&... args) { 134 if (this->pack(e) == false) { 135 return false; 136 } else { 137 return pack(args...); 138 } 139 } 140 141 template <typename Element> 142 typename boost::enable_if<is_fixed_type<Element>, bool>::type pack( 143 const Element& e) { 144 return iter_.append_basic(element<Element>::code, &e); 145 } 146 147 // Specialization used to represent "dict" in dbus. 148 // TODO(ed) generalize for all "map like" types instead of using vector 149 template <typename Key, typename Value> 150 bool pack(const std::vector<std::pair<Key, Value>>& v) { 151 static const constexpr auto sig = 152 element_signature<typename std::decay<decltype(v)>::type>::code; 153 154 static_assert(std::tuple_size<decltype(sig)>::value > 2, 155 "Signature size must be greater than 2 characters long"); 156 // Skip over the array part "a" of the signature to get the element 157 // signature. 158 // Open container expects JUST the portion after the "a" in the second arg 159 message::packer sub; 160 iter_.open_container(sig[0], &sig[1], sub.iter_); 161 for (auto& element : v) { 162 sub.pack(element); 163 } 164 165 return iter_.close_container(sub.iter_); 166 } 167 168 template <typename Element> 169 bool pack(const std::vector<Element>& v) { 170 message::packer sub; 171 static const constexpr auto signature = 172 element_signature<std::vector<Element>>::code; 173 static_assert(std::tuple_size<decltype(signature)>::value > 2, 174 "Signature size must be greater than 2 characters long"); 175 iter_.open_container(signature[0], &signature[1], sub.iter_); 176 for (auto& element : v) { 177 sub.pack(element); 178 } 179 180 return iter_.close_container(sub.iter_); 181 } 182 183 bool pack(const char* c) { 184 return iter_.append_basic(element<string>::code, &c); 185 } 186 187 template <typename Key, typename Value> 188 bool pack(const std::pair<Key, Value> element) { 189 message::packer dict_entry; 190 if (iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_) == 191 false) { 192 return false; 193 } 194 if (dict_entry.pack(element.first) == false) { 195 return false; 196 }; 197 if (dict_entry.pack(element.second) == false) { 198 return false; 199 }; 200 return iter_.close_container(dict_entry.iter_); 201 } 202 203 bool pack(const string& e) { 204 const char* c = e.c_str(); 205 return pack(c); 206 } 207 208 bool pack(const dbus_variant& v) { 209 // Get the dbus typecode of the variant being packed 210 const char* type = boost::apply_visitor( 211 [&](auto val) { 212 static const constexpr auto sig = 213 element_signature<decltype(val)>::code; 214 static_assert( 215 std::tuple_size<decltype(sig)>::value == 2, 216 "Element signature for dbus_variant too long. Expected " 217 "length of 1"); 218 return &sig[0]; 219 }, 220 v); 221 message::packer sub; 222 iter_.open_container(element<dbus_variant>::code, type, sub.iter_); 223 boost::apply_visitor([&](const auto& val) { sub.pack(val); }, v); 224 iter_.close_container(sub.iter_); 225 226 return true; 227 } 228 }; 229 230 template <typename... Args> 231 bool pack(const Args&... args) { 232 return packer(*this).pack(args...); 233 } 234 235 // noop for template functions that have no arguments 236 bool pack() { return true; } 237 238 struct unpacker { 239 impl::message_iterator iter_; 240 unpacker(message& m) { impl::message_iterator::init(m, iter_); } 241 unpacker() {} 242 243 template <typename Element, typename... Args> 244 bool unpack(Element& e, Args&... args) { 245 if (unpack(e) == false) { 246 return false; 247 } 248 return unpack(args...); 249 } 250 251 // Basic type unpack 252 template <typename Element> 253 typename boost::enable_if<is_fixed_type<Element>, bool>::type unpack( 254 Element& e) { 255 if (iter_.get_arg_type() != element<Element>::code) { 256 return false; 257 } 258 iter_.get_basic(&e); 259 // ignoring return code here, as we might hit last element, and don't 260 // really care because get_arg_type will return invalid if we call it 261 // after we're over the struct boundary 262 iter_.next(); 263 return true; 264 } 265 266 // std::string unpack specialization 267 bool unpack(string& s) { 268 if (iter_.get_arg_type() != element<string>::code) { 269 return false; 270 } 271 const char* c; 272 iter_.get_basic(&c); 273 s.assign(c); 274 iter_.next(); 275 return true; 276 } 277 278 // object_path unpack specialization 279 bool unpack(object_path& s) { 280 if (iter_.get_arg_type() != element<object_path>::code) { 281 return false; 282 } 283 const char* c; 284 iter_.get_basic(&c); 285 s.value.assign(c); 286 iter_.next(); 287 return true; 288 } 289 290 // object_path unpack specialization 291 bool unpack(signature& s) { 292 if (iter_.get_arg_type() != element<signature>::code) { 293 return false; 294 } 295 const char* c; 296 iter_.get_basic(&c); 297 s.value.assign(c); 298 iter_.next(); 299 return true; 300 } 301 302 // variant unpack specialization 303 bool unpack(dbus_variant& v) { 304 if (iter_.get_arg_type() != element<dbus_variant>::code) { 305 return false; 306 } 307 message::unpacker sub; 308 iter_.recurse(sub.iter_); 309 310 char arg_type = sub.iter_.get_arg_type(); 311 312 boost::mpl::for_each<dbus_variant::types>([&](auto t) { 313 if (arg_type == element<decltype(t)>::code) { 314 decltype(t) val_to_fill; 315 sub.unpack(val_to_fill); 316 v = val_to_fill; 317 } 318 }); 319 320 iter_.next(); 321 return true; 322 } 323 324 // dict entry unpack specialization 325 template <typename Key, typename Value> 326 bool unpack(std::pair<Key, Value>& v) { 327 auto this_code = iter_.get_arg_type(); 328 // This can't use element<std::pair> because there is a difference between 329 // the dbus type code 'e' and the dbus signature code for dict entries 330 // '{'. Element_signature will return the full signature, and will never 331 // return e, but we still want to type check it before recursing 332 if (this_code != DBUS_TYPE_DICT_ENTRY) { 333 return false; 334 } 335 message::unpacker sub; 336 iter_.recurse(sub.iter_); 337 if (!sub.unpack(v.first)) { 338 return false; 339 } 340 if (!sub.unpack(v.second)) { 341 return false; 342 } 343 344 iter_.next(); 345 return true; 346 } 347 348 // dbus array / c++ vector unpack specialization 349 template <typename Element> 350 bool unpack(std::vector<Element>& s) { 351 auto top_level_arg_type = iter_.get_arg_type(); 352 if (top_level_arg_type != element<std::vector<Element>>::code) { 353 return false; 354 } 355 message::unpacker sub; 356 357 iter_.recurse(sub.iter_); 358 auto arg_type = sub.iter_.get_arg_type(); 359 while (arg_type != DBUS_TYPE_INVALID) { 360 s.emplace_back(); 361 if (!sub.unpack(s.back())) { 362 return false; 363 } 364 arg_type = sub.iter_.get_arg_type(); 365 } 366 iter_.next(); 367 return true; 368 } 369 }; 370 371 template <typename... Args> 372 bool unpack(Args&... args) { 373 return unpacker(*this).unpack(args...); 374 } 375 376 private: 377 static std::string sanitize(const char* str) { 378 return (str == NULL) ? "(null)" : str; 379 } 380 }; 381 382 inline std::ostream& operator<<(std::ostream& os, const message& m) { 383 os << "type='" << m.get_type() << "'," 384 << "sender='" << m.get_sender() << "'," 385 << "interface='" << m.get_interface() << "'," 386 << "member='" << m.get_member() << "'," 387 << "path='" << m.get_path() << "'," 388 << "destination='" << m.get_destination() << "'"; 389 return os; 390 } 391 392 } // namespace dbus 393 394 // primary template. 395 template <class T> 396 struct function_traits : function_traits<decltype(&T::operator())> {}; 397 398 // partial specialization for function type 399 template <class R, class... Args> 400 struct function_traits<R(Args...)> { 401 using result_type = R; 402 using argument_types = std::tuple<Args...>; 403 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 404 }; 405 406 // partial specialization for function pointer 407 template <class R, class... Args> 408 struct function_traits<R (*)(Args...)> { 409 using result_type = R; 410 using argument_types = std::tuple<Args...>; 411 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 412 }; 413 414 // partial specialization for std::function 415 template <class R, class... Args> 416 struct function_traits<std::function<R(Args...)>> { 417 using result_type = R; 418 using argument_types = std::tuple<Args...>; 419 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 420 }; 421 422 // partial specialization for pointer-to-member-function (i.e., operator()'s) 423 template <class T, class R, class... Args> 424 struct function_traits<R (T::*)(Args...)> { 425 using result_type = R; 426 using argument_types = std::tuple<Args...>; 427 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 428 }; 429 430 template <class T, class R, class... Args> 431 struct function_traits<R (T::*)(Args...) const> { 432 using result_type = R; 433 using argument_types = std::tuple<Args...>; 434 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 435 }; 436 437 template <class F, size_t... Is> 438 constexpr auto index_apply_impl(F f, std::index_sequence<Is...>) { 439 return f(std::integral_constant<size_t, Is>{}...); 440 } 441 442 template <size_t N, class F> 443 constexpr auto index_apply(F f) { 444 return index_apply_impl(f, std::make_index_sequence<N>{}); 445 } 446 447 template <class Tuple, class F> 448 constexpr auto apply(F f, Tuple& t) { 449 return index_apply<std::tuple_size<Tuple>{}>( 450 [&](auto... Is) { return f(std::get<Is>(t)...); }); 451 } 452 453 template <class Tuple> 454 constexpr bool unpack_into_tuple(Tuple& t, dbus::message& m) { 455 return index_apply<std::tuple_size<Tuple>{}>( 456 [&](auto... Is) { return m.unpack(std::get<Is>(t)...); }); 457 } 458 459 // Specialization for empty tuples. No need to unpack if no arguments 460 constexpr bool unpack_into_tuple(std::tuple<>& t, dbus::message& m) { 461 return true; 462 } 463 464 template <typename... Args> 465 constexpr bool pack_tuple_into_msg(std::tuple<Args...>& t, dbus::message& m) { 466 return index_apply<std::tuple_size<std::tuple<Args...>>{}>( 467 [&](auto... Is) { return m.pack(std::get<Is>(t)...); }); 468 } 469 470 // Specialization for empty tuples. No need to pack if no arguments 471 constexpr bool pack_tuple_into_msg(std::tuple<>& t, dbus::message& m) { 472 return true; 473 } 474 475 // Specialization for single types. Used when callbacks simply return one value 476 template <typename Element> 477 constexpr bool pack_tuple_into_msg(Element& t, dbus::message& m) { 478 return m.pack(t); 479 } 480 481 #include <dbus/impl/message_iterator.ipp> 482 483 #endif // DBUS_MESSAGE_HPP 484