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 template <typename Element> 148 typename boost::enable_if<std::is_pointer<Element>, bool>::type pack( 149 const Element e) { 150 return iter_.append_basic( 151 element<typename std::remove_pointer<Element>::type>::code, e); 152 } 153 154 template <typename Container> 155 typename std::enable_if<has_const_iterator<Container>::value && 156 !is_string_type<Container>::value, 157 bool>::type 158 pack(const Container& c) { 159 message::packer sub; 160 161 static const constexpr auto signature = 162 element_signature<Container>::code; 163 if (iter_.open_container(signature[0], &signature[1], sub.iter_) == 164 false) { 165 return false; 166 } 167 for (auto& element : c) { 168 if (!sub.pack(element)) { 169 return false; 170 } 171 } 172 return iter_.close_container(sub.iter_); 173 } 174 175 bool pack(const char* c) { 176 return iter_.append_basic(element<string>::code, &c); 177 } 178 179 template <typename Key, typename Value> 180 bool pack(const std::pair<Key, Value> element) { 181 message::packer dict_entry; 182 if (iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_) == 183 false) { 184 return false; 185 } 186 if (dict_entry.pack(element.first) == false) { 187 return false; 188 }; 189 if (dict_entry.pack(element.second) == false) { 190 return false; 191 }; 192 return iter_.close_container(dict_entry.iter_); 193 } 194 195 bool pack(const string& e) { 196 const char* c = e.c_str(); 197 return pack(c); 198 } 199 200 bool pack(const dbus_variant& v) { 201 // Get the dbus typecode of the variant being packed 202 const char* type = boost::apply_visitor( 203 [&](auto val) { 204 static const constexpr auto sig = 205 element_signature<decltype(val)>::code; 206 static_assert( 207 std::tuple_size<decltype(sig)>::value == 2, 208 "Element signature for dbus_variant too long. Expected " 209 "length of 1"); 210 return &sig[0]; 211 }, 212 v); 213 message::packer sub; 214 iter_.open_container(element<dbus_variant>::code, type, sub.iter_); 215 boost::apply_visitor([&](const auto& val) { sub.pack(val); }, v); 216 iter_.close_container(sub.iter_); 217 218 return true; 219 } 220 }; 221 222 template <typename... Args> 223 bool pack(const Args&... args) { 224 return packer(*this).pack(args...); 225 } 226 227 // noop for template functions that have no arguments 228 bool pack() { return true; } 229 230 struct unpacker { 231 impl::message_iterator iter_; 232 unpacker(message& m) { impl::message_iterator::init(m, iter_); } 233 unpacker() {} 234 235 template <typename Element, typename... Args> 236 bool unpack(Element& e, Args&... args) { 237 if (unpack(e) == false) { 238 return false; 239 } 240 return unpack(args...); 241 } 242 243 // Basic type unpack 244 template <typename Element> 245 typename boost::enable_if<is_fixed_type<Element>, bool>::type unpack( 246 Element& e) { 247 if (iter_.get_arg_type() != element<Element>::code) { 248 return false; 249 } 250 iter_.get_basic(&e); 251 // ignoring return code here, as we might hit last element, and don't 252 // really care because get_arg_type will return invalid if we call it 253 // after we're over the struct boundary 254 iter_.next(); 255 return true; 256 } 257 258 // std::string unpack specialization 259 bool unpack(string& s) { 260 if (iter_.get_arg_type() != element<string>::code) { 261 return false; 262 } 263 const char* c; 264 iter_.get_basic(&c); 265 s.assign(c); 266 iter_.next(); 267 return true; 268 } 269 270 // object_path unpack specialization 271 bool unpack(object_path& s) { 272 if (iter_.get_arg_type() != element<object_path>::code) { 273 return false; 274 } 275 const char* c; 276 iter_.get_basic(&c); 277 s.value.assign(c); 278 iter_.next(); 279 return true; 280 } 281 282 // object_path unpack specialization 283 bool unpack(signature& s) { 284 if (iter_.get_arg_type() != element<signature>::code) { 285 return false; 286 } 287 const char* c; 288 iter_.get_basic(&c); 289 s.value.assign(c); 290 iter_.next(); 291 return true; 292 } 293 294 // variant unpack specialization 295 bool unpack(dbus_variant& v) { 296 if (iter_.get_arg_type() != element<dbus_variant>::code) { 297 return false; 298 } 299 message::unpacker sub; 300 iter_.recurse(sub.iter_); 301 302 char arg_type = sub.iter_.get_arg_type(); 303 304 boost::mpl::for_each<dbus_variant::types>([&](auto t) { 305 if (arg_type == element<decltype(t)>::code) { 306 decltype(t) val_to_fill; 307 sub.unpack(val_to_fill); 308 v = val_to_fill; 309 } 310 }); 311 312 iter_.next(); 313 return true; 314 } 315 316 // dict entry unpack specialization 317 template <typename Key, typename Value> 318 bool unpack(std::pair<Key, Value>& v) { 319 auto this_code = iter_.get_arg_type(); 320 // This can't use element<std::pair> because there is a difference between 321 // the dbus type code 'e' and the dbus signature code for dict entries 322 // '{'. Element_signature will return the full signature, and will never 323 // return e, but we still want to type check it before recursing 324 if (this_code != DBUS_TYPE_DICT_ENTRY) { 325 return false; 326 } 327 message::unpacker sub; 328 iter_.recurse(sub.iter_); 329 if (!sub.unpack(v.first)) { 330 return false; 331 } 332 if (!sub.unpack(v.second)) { 333 return false; 334 } 335 336 iter_.next(); 337 return true; 338 } 339 340 template <typename Container> 341 typename std::enable_if<has_const_iterator<Container>::value && 342 !is_string_type<Container>::value, 343 bool>::type 344 unpack(Container& c) { 345 std::cout << "test\n"; 346 auto top_level_arg_type = iter_.get_arg_type(); 347 constexpr auto type = element_signature<Container>::code[0]; 348 if (top_level_arg_type != type) { 349 return false; 350 } 351 message::unpacker sub; 352 353 iter_.recurse(sub.iter_); 354 auto arg_type = sub.iter_.get_arg_type(); 355 while (arg_type != DBUS_TYPE_INVALID) { 356 c.emplace_back(); 357 if (!sub.unpack(c.back())) { 358 return false; 359 } 360 arg_type = sub.iter_.get_arg_type(); 361 } 362 iter_.next(); 363 return true; 364 } 365 }; 366 367 template <typename... Args> 368 bool unpack(Args&... args) { 369 return unpacker(*this).unpack(args...); 370 } 371 372 private: 373 static std::string sanitize(const char* str) { 374 return (str == NULL) ? "(null)" : str; 375 } 376 }; 377 378 inline std::ostream& operator<<(std::ostream& os, const message& m) { 379 os << "type='" << m.get_type() << "'," 380 << "sender='" << m.get_sender() << "'," 381 << "interface='" << m.get_interface() << "'," 382 << "member='" << m.get_member() << "'," 383 << "path='" << m.get_path() << "'," 384 << "destination='" << m.get_destination() << "'"; 385 return os; 386 } 387 388 } // namespace dbus 389 390 // primary template. 391 template <class T> 392 struct function_traits : function_traits<decltype(&T::operator())> {}; 393 394 // partial specialization for function type 395 template <class R, class... Args> 396 struct function_traits<R(Args...)> { 397 using result_type = R; 398 using argument_types = std::tuple<Args...>; 399 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 400 }; 401 402 // partial specialization for function pointer 403 template <class R, class... Args> 404 struct function_traits<R (*)(Args...)> { 405 using result_type = R; 406 using argument_types = std::tuple<Args...>; 407 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 408 }; 409 410 // partial specialization for std::function 411 template <class R, class... Args> 412 struct function_traits<std::function<R(Args...)>> { 413 using result_type = R; 414 using argument_types = std::tuple<Args...>; 415 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 416 }; 417 418 // partial specialization for pointer-to-member-function (i.e., operator()'s) 419 template <class T, class R, class... Args> 420 struct function_traits<R (T::*)(Args...)> { 421 using result_type = R; 422 using argument_types = std::tuple<Args...>; 423 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 424 }; 425 426 template <class T, class R, class... Args> 427 struct function_traits<R (T::*)(Args...) const> { 428 using result_type = R; 429 using argument_types = std::tuple<Args...>; 430 using decayed_arg_types = std::tuple<typename std::decay<Args>::type...>; 431 }; 432 433 template <class F, size_t... Is> 434 constexpr auto index_apply_impl(F f, std::index_sequence<Is...>) { 435 return f(std::integral_constant<size_t, Is>{}...); 436 } 437 438 template <size_t N, class F> 439 constexpr auto index_apply(F f) { 440 return index_apply_impl(f, std::make_index_sequence<N>{}); 441 } 442 443 template <class Tuple, class F> 444 constexpr auto apply(F f, Tuple& t) { 445 return index_apply<std::tuple_size<Tuple>{}>( 446 [&](auto... Is) { return f(std::get<Is>(t)...); }); 447 } 448 449 template <class Tuple> 450 constexpr bool unpack_into_tuple(Tuple& t, dbus::message& m) { 451 return index_apply<std::tuple_size<Tuple>{}>( 452 [&](auto... Is) { return m.unpack(std::get<Is>(t)...); }); 453 } 454 455 // Specialization for empty tuples. No need to unpack if no arguments 456 constexpr bool unpack_into_tuple(std::tuple<>& t, dbus::message& m) { 457 return true; 458 } 459 460 template <typename... Args> 461 constexpr bool pack_tuple_into_msg(std::tuple<Args...>& t, dbus::message& m) { 462 return index_apply<std::tuple_size<std::tuple<Args...>>{}>( 463 [&](auto... Is) { return m.pack(std::get<Is>(t)...); }); 464 } 465 466 // Specialization for empty tuples. No need to pack if no arguments 467 constexpr bool pack_tuple_into_msg(std::tuple<>& t, dbus::message& m) { 468 return true; 469 } 470 471 // Specialization for single types. Used when callbacks simply return one value 472 template <typename Element> 473 constexpr bool pack_tuple_into_msg(Element& t, dbus::message& m) { 474 return m.pack(t); 475 } 476 477 #include <dbus/impl/message_iterator.ipp> 478 479 #endif // DBUS_MESSAGE_HPP 480