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 std::enable_if<is_fixed_type<Element>::value, bool>::type pack( 143 const Element& e) { 144 return iter_.append_basic(element<Element>::code, &e); 145 } 146 147 template <typename Element> 148 typename std::enable_if<std::is_pointer<Element>::value, bool>::type pack( 149 const Element e) { 150 return pack(*e); 151 } 152 153 template <typename Container> 154 typename std::enable_if<has_const_iterator<Container>::value && 155 !is_string_type<Container>::value, 156 bool>::type 157 pack(const Container& c) { 158 message::packer sub; 159 160 static const constexpr auto signature = 161 element_signature<Container>::code; 162 if (iter_.open_container(signature[0], &signature[1], sub.iter_) == 163 false) { 164 return false; 165 } 166 for (auto& element : c) { 167 if (!sub.pack(element)) { 168 return false; 169 } 170 } 171 return iter_.close_container(sub.iter_); 172 } 173 174 bool pack(const char* c) { 175 return iter_.append_basic(element<string>::code, &c); 176 } 177 178 // bool pack specialization 179 bool pack(bool c) { 180 int v = c; 181 return iter_.append_basic(element<bool>::code, &v); 182 } 183 184 template <typename Key, typename Value> 185 bool pack(const std::pair<Key, Value> element) { 186 message::packer dict_entry; 187 if (iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_) == 188 false) { 189 return false; 190 } 191 if (dict_entry.pack(element.first) == false) { 192 return false; 193 }; 194 if (dict_entry.pack(element.second) == false) { 195 return false; 196 }; 197 return iter_.close_container(dict_entry.iter_); 198 } 199 200 bool pack(const object_path& e) { 201 const char* c = e.value.c_str(); 202 return iter_.append_basic(element<object_path>::code, &c); 203 } 204 205 bool pack(const string& e) { 206 const char* c = e.c_str(); 207 return pack(c); 208 } 209 210 bool pack(const dbus_variant& v) { 211 // Get the dbus typecode of the variant being packed 212 const char* type = boost::apply_visitor( 213 [&](auto val) { 214 static const constexpr auto sig = 215 element_signature<decltype(val)>::code; 216 return &sig[0]; 217 }, 218 v); 219 message::packer sub; 220 iter_.open_container(element<dbus_variant>::code, type, sub.iter_); 221 boost::apply_visitor([&](const auto& val) { sub.pack(val); }, v); 222 iter_.close_container(sub.iter_); 223 224 return true; 225 } 226 }; 227 228 template <typename... Args> 229 bool pack(const Args&... args) { 230 return packer(*this).pack(args...); 231 } 232 233 // noop for template functions that have no arguments 234 bool pack() { return true; } 235 236 struct unpacker { 237 impl::message_iterator iter_; 238 unpacker(message& m) { impl::message_iterator::init(m, iter_); } 239 unpacker() {} 240 241 template <typename Element, typename... Args> 242 bool unpack(Element& e, Args&... args) { 243 if (unpack(e) == false) { 244 return false; 245 } 246 return unpack(args...); 247 } 248 249 // Basic type unpack 250 template <typename Element> 251 typename std::enable_if<is_fixed_type<Element>::value, bool>::type unpack( 252 Element& e) { 253 if (iter_.get_arg_type() != element<Element>::code) { 254 return false; 255 } 256 iter_.get_basic(&e); 257 // ignoring return code here, as we might hit last element, and don't 258 // really care because get_arg_type will return invalid if we call it 259 // after we're over the struct boundary 260 iter_.next(); 261 return true; 262 } 263 264 // bool unpack specialization 265 bool unpack(bool& s) { 266 if (iter_.get_arg_type() != element<bool>::code) { 267 return false; 268 } 269 int c; 270 iter_.get_basic(&c); 271 s = c; 272 iter_.next(); 273 return true; 274 } 275 276 // std::string unpack specialization 277 bool unpack(string& s) { 278 if (iter_.get_arg_type() != element<string>::code) { 279 return false; 280 } 281 const char* c; 282 iter_.get_basic(&c); 283 s.assign(c); 284 iter_.next(); 285 return true; 286 } 287 288 // object_path unpack specialization 289 bool unpack(object_path& s) { 290 if (iter_.get_arg_type() != element<object_path>::code) { 291 return false; 292 } 293 const char* c; 294 iter_.get_basic(&c); 295 s.value.assign(c); 296 iter_.next(); 297 return true; 298 } 299 300 // object_path unpack specialization 301 bool unpack(signature& s) { 302 if (iter_.get_arg_type() != element<signature>::code) { 303 return false; 304 } 305 const char* c; 306 iter_.get_basic(&c); 307 s.value.assign(c); 308 iter_.next(); 309 return true; 310 } 311 312 // variant unpack specialization 313 bool unpack(dbus_variant& v) { 314 if (iter_.get_arg_type() != element<dbus_variant>::code) { 315 return false; 316 } 317 message::unpacker sub; 318 iter_.recurse(sub.iter_); 319 320 char arg_type = sub.iter_.get_arg_type(); 321 322 boost::mpl::for_each<dbus_variant::types>([&](auto t) { 323 if (arg_type == element<decltype(t)>::code) { 324 decltype(t) val_to_fill; 325 sub.unpack(val_to_fill); 326 v = val_to_fill; 327 } 328 }); 329 330 iter_.next(); 331 return true; 332 } 333 334 // dict entry unpack specialization 335 template <typename Key, typename Value> 336 bool unpack(std::pair<Key, Value>& v) { 337 auto this_code = iter_.get_arg_type(); 338 // This can't use element<std::pair> because there is a difference between 339 // the dbus type code 'e' and the dbus signature code for dict entries 340 // '{'. Element_signature will return the full signature, and will never 341 // return e, but we still want to type check it before recursing 342 if (this_code != DBUS_TYPE_DICT_ENTRY) { 343 return false; 344 } 345 message::unpacker sub; 346 iter_.recurse(sub.iter_); 347 if (!sub.unpack(v.first)) { 348 return false; 349 } 350 if (!sub.unpack(v.second)) { 351 return false; 352 } 353 354 iter_.next(); 355 return true; 356 } 357 358 template <typename T> 359 struct has_emplace_method 360 361 { 362 struct dummy {}; 363 364 template <typename C, typename P> 365 static auto test(P* p) 366 -> decltype(std::declval<C>().emplace(*p), std::true_type()); 367 368 template <typename, typename> 369 static std::false_type test(...); 370 371 typedef decltype(test<T, dummy>(nullptr)) type; 372 373 static constexpr bool value = 374 std::is_same<std::true_type, 375 decltype(test<T, dummy>(nullptr))>::value; 376 }; 377 378 template <typename T> 379 struct has_emplace_back_method 380 381 { 382 struct dummy {}; 383 384 template <typename C, typename P> 385 static auto test(P* p) 386 -> decltype(std::declval<C>().emplace_back(*p), std::true_type()); 387 388 template <typename, typename> 389 static std::false_type test(...); 390 391 typedef decltype(test<T, dummy>(nullptr)) type; 392 393 static constexpr bool value = 394 std::is_same<std::true_type, 395 decltype(test<T, dummy>(nullptr))>::value; 396 }; 397 398 template <typename Container> 399 typename std::enable_if<has_emplace_back_method<Container>::value && 400 !is_string_type<Container>::value, 401 bool>::type 402 unpack(Container& c) { 403 auto top_level_arg_type = iter_.get_arg_type(); 404 constexpr auto type = element_signature<Container>::code[0]; 405 if (top_level_arg_type != type) { 406 return false; 407 } 408 message::unpacker sub; 409 410 iter_.recurse(sub.iter_); 411 while (sub.iter_.get_arg_type() != DBUS_TYPE_INVALID) { 412 c.emplace_back(); 413 if (!sub.unpack(c.back())) { 414 return false; 415 } 416 } 417 iter_.next(); 418 return true; 419 } 420 421 template <typename Container> 422 typename std::enable_if<has_emplace_method<Container>::value && 423 !is_string_type<Container>::value, 424 bool>::type 425 unpack(Container& c) { 426 auto top_level_arg_type = iter_.get_arg_type(); 427 constexpr auto type = element_signature<Container>::code[0]; 428 if (top_level_arg_type != type) { 429 return false; 430 } 431 message::unpacker sub; 432 433 iter_.recurse(sub.iter_); 434 while (sub.iter_.get_arg_type() != DBUS_TYPE_INVALID) { 435 // TODO(ed) this is done as an unpack to a stack variable, then an 436 // emplace move into the container (as the key isn't known until the 437 // unpack is done) This could be made more efficient by unpacking only 438 // the key type into a temporary, using find on the temporary, then 439 // unpacking directly into the map type, instead of unpacking both key 440 // and value. 441 442 typename Container::value_type t; 443 if (!sub.unpack(t)) { 444 return false; 445 } 446 c.emplace(std::move(t)); 447 } 448 iter_.next(); 449 return true; 450 } 451 }; 452 453 template <typename... Args> 454 bool unpack(Args&... args) { 455 return unpacker(*this).unpack(args...); 456 } 457 458 private: 459 static std::string sanitize(const char* str) { 460 return (str == NULL) ? "(null)" : str; 461 } 462 }; 463 464 inline std::ostream& operator<<(std::ostream& os, const message& m) { 465 os << "type='" << m.get_type() << "'," 466 << "sender='" << m.get_sender() << "'," 467 << "interface='" << m.get_interface() << "'," 468 << "member='" << m.get_member() << "'," 469 << "path='" << m.get_path() << "'," 470 << "destination='" << m.get_destination() << "'"; 471 return os; 472 } 473 474 } // namespace dbus 475 476 // primary template. 477 template <class T> 478 struct function_traits : function_traits<decltype(&T::operator())> {}; 479 480 // partial specialization for function type 481 template <class R, class... Args> 482 struct function_traits<R(Args...)> { 483 using result_type = R; 484 using argument_types = std::tuple<Args...>; 485 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 486 }; 487 488 // partial specialization for function pointer 489 template <class R, class... Args> 490 struct function_traits<R (*)(Args...)> { 491 using result_type = R; 492 using argument_types = std::tuple<Args...>; 493 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 494 }; 495 496 // partial specialization for std::function 497 template <class R, class... Args> 498 struct function_traits<std::function<R(Args...)>> { 499 using result_type = R; 500 using argument_types = std::tuple<Args...>; 501 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 502 }; 503 504 // partial specialization for pointer-to-member-function (i.e., operator()'s) 505 template <class T, class R, class... Args> 506 struct function_traits<R (T::*)(Args...)> { 507 using result_type = R; 508 using argument_types = std::tuple<Args...>; 509 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 510 }; 511 512 template <class T, class R, class... Args> 513 struct function_traits<R (T::*)(Args...) const> { 514 using result_type = R; 515 using argument_types = std::tuple<Args...>; 516 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 517 }; 518 519 template <class F, size_t... Is> 520 constexpr auto index_apply_impl(F f, std::index_sequence<Is...>) { 521 return f(std::integral_constant<size_t, Is>{}...); 522 } 523 524 template <size_t N, class F> 525 constexpr auto index_apply(F f) { 526 return index_apply_impl(f, std::make_index_sequence<N>{}); 527 } 528 529 template <class Tuple, class F> 530 constexpr auto apply(F f, Tuple& t) { 531 return index_apply<std::tuple_size<Tuple>{}>( 532 [&](auto... Is) { return f(std::get<Is>(t)...); }); 533 } 534 535 template <class Tuple> 536 constexpr bool unpack_into_tuple(Tuple& t, dbus::message& m) { 537 return index_apply<std::tuple_size<Tuple>{}>( 538 [&](auto... Is) { return m.unpack(std::get<Is>(t)...); }); 539 } 540 541 // Specialization for empty tuples. No need to unpack if no arguments 542 constexpr bool unpack_into_tuple(std::tuple<>& t, dbus::message& m) { 543 return true; 544 } 545 546 template <typename... Args> 547 constexpr bool pack_tuple_into_msg(std::tuple<Args...>& t, dbus::message& m) { 548 return index_apply<std::tuple_size<std::tuple<Args...>>{}>( 549 [&](auto... Is) { return m.pack(std::get<Is>(t)...); }); 550 } 551 552 // Specialization for empty tuples. No need to pack if no arguments 553 constexpr bool pack_tuple_into_msg(std::tuple<>& t, dbus::message& m) { 554 return true; 555 } 556 557 // Specialization for single types. Used when callbacks simply return one value 558 template <typename Element> 559 constexpr bool pack_tuple_into_msg(Element& t, dbus::message& m) { 560 return m.pack(t); 561 } 562 563 #include <dbus/impl/message_iterator.ipp> 564 565 #endif // DBUS_MESSAGE_HPP 566