191cdbe46SBenjamin Kietzman // Copyright (c) Benjamin Kietzman (github.com/bkietz) 291cdbe46SBenjamin Kietzman // 391cdbe46SBenjamin Kietzman // Distributed under the Boost Software License, Version 1.0. (See accompanying 491cdbe46SBenjamin Kietzman // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 591cdbe46SBenjamin Kietzman 6fc79e461SBenjamin Kietzman #ifndef DBUS_CONNECTION_HPP 7fc79e461SBenjamin Kietzman #define DBUS_CONNECTION_HPP 8fc79e461SBenjamin Kietzman 9da3eeb6aSEd Tanous #include <dbus/connection_service.hpp> 10a83e5951SBenjamin Kietzman #include <dbus/element.hpp> 11fc79e461SBenjamin Kietzman #include <dbus/message.hpp> 12da3eeb6aSEd Tanous #include <chrono> 13da3eeb6aSEd Tanous #include <string> 14da3eeb6aSEd Tanous #include <boost/asio.hpp> 15dae7063cSBenjamin Kietzman 16dae7063cSBenjamin Kietzman namespace dbus { 17dae7063cSBenjamin Kietzman 1817826fe7SBenjamin Kietzman class filter; 1917826fe7SBenjamin Kietzman class match; 2017826fe7SBenjamin Kietzman 21dae7063cSBenjamin Kietzman /// Root D-Bus IO object 22dae7063cSBenjamin Kietzman /** 23dae7063cSBenjamin Kietzman * A connection to a bus, through which messages may be sent or received. 24dae7063cSBenjamin Kietzman */ 25da3eeb6aSEd Tanous class connection : public boost::asio::basic_io_object<connection_service> { 26dae7063cSBenjamin Kietzman public: 27cd8b76a3SBenjamin Kietzman /// Open a connection to a specified address. 28dae7063cSBenjamin Kietzman /** 29dae7063cSBenjamin Kietzman * @param io_service The io_service object that the connection will use to 30dae7063cSBenjamin Kietzman * wire D-Bus for asynchronous operation. 31dae7063cSBenjamin Kietzman * 32dae7063cSBenjamin Kietzman * @param address The address of the bus to connect to. 33dae7063cSBenjamin Kietzman * 34dae7063cSBenjamin Kietzman * @throws boost::system::system_error When opening the connection failed. 35dae7063cSBenjamin Kietzman */ connection(boost::asio::io_service & io,const string & address)36da3eeb6aSEd Tanous connection(boost::asio::io_service& io, const string& address) 37da3eeb6aSEd Tanous : basic_io_object<connection_service>(io) { 38da3eeb6aSEd Tanous this->get_service().open(this->get_implementation(), address); 39dae7063cSBenjamin Kietzman } 40dae7063cSBenjamin Kietzman 41dae7063cSBenjamin Kietzman /// Open a connection to a well-known bus. 42dae7063cSBenjamin Kietzman /** 43dae7063cSBenjamin Kietzman * D-Bus connections are usually opened to well-known buses like the 44dae7063cSBenjamin Kietzman * system or session bus. 45dae7063cSBenjamin Kietzman * 46cd8b76a3SBenjamin Kietzman * @param bus The well-known bus to connect to. 47dae7063cSBenjamin Kietzman * 48dae7063cSBenjamin Kietzman * @throws boost::system::system_error When opening the connection failed. 49dae7063cSBenjamin Kietzman */ 50dae7063cSBenjamin Kietzman // TODO: change this unsigned to an enumeration connection(boost::asio::io_service & io,const int bus)51da3eeb6aSEd Tanous connection(boost::asio::io_service& io, const int bus) 52da3eeb6aSEd Tanous : basic_io_object<connection_service>(io) { 53da3eeb6aSEd Tanous this->get_service().open(this->get_implementation(), bus); 54dae7063cSBenjamin Kietzman } 55dae7063cSBenjamin Kietzman 56458a9c10SVernon Mauery /// Request a name on the bus. 57458a9c10SVernon Mauery /** 58458a9c10SVernon Mauery * @param name The name requested on the bus 59458a9c10SVernon Mauery * 60458a9c10SVernon Mauery * @return 61458a9c10SVernon Mauery * 62458a9c10SVernon Mauery * @throws boost::system::system_error When the response timed out or 63458a9c10SVernon Mauery * there was some other error. 64458a9c10SVernon Mauery */ request_name(const string & name)65458a9c10SVernon Mauery void request_name(const string& name) { 66458a9c10SVernon Mauery this->get_implementation().request_name(name); 67458a9c10SVernon Mauery } 68458a9c10SVernon Mauery get_unique_name()690d6f56d2SEd Tanous std::string get_unique_name() { 700d6f56d2SEd Tanous return this->get_implementation().get_unique_name(); 710d6f56d2SEd Tanous } 720d6f56d2SEd Tanous 73458a9c10SVernon Mauery /// Reply to a message. 74458a9c10SVernon Mauery /** 75458a9c10SVernon Mauery * @param m The message from which to create the reply 76458a9c10SVernon Mauery * 77458a9c10SVernon Mauery * @return The new reply message 78458a9c10SVernon Mauery * 79458a9c10SVernon Mauery * @throws boost::system::system_error When the response timed out or 80458a9c10SVernon Mauery * there was some other error. 81458a9c10SVernon Mauery */ reply(message & m)82458a9c10SVernon Mauery message reply(message& m) { 83458a9c10SVernon Mauery return this->get_implementation().new_method_return(m); 84458a9c10SVernon Mauery } 85458a9c10SVernon Mauery 860de54404SBenjamin Kietzman /// Send a message. 870de54404SBenjamin Kietzman /** 880de54404SBenjamin Kietzman * @param m The message to send. 890de54404SBenjamin Kietzman * 900de54404SBenjamin Kietzman * @return The reply received. 910de54404SBenjamin Kietzman * 920de54404SBenjamin Kietzman * @throws boost::system::system_error When the response timed out or 930de54404SBenjamin Kietzman * there was some other error. 940de54404SBenjamin Kietzman */ send(message & m)95da3eeb6aSEd Tanous message send(message& m) { 96da3eeb6aSEd Tanous return this->get_service().send(this->get_implementation(), m); 970de54404SBenjamin Kietzman } 98dae7063cSBenjamin Kietzman 99dae7063cSBenjamin Kietzman /// Send a message. 100dae7063cSBenjamin Kietzman /** 101dae7063cSBenjamin Kietzman * @param m The message to send. 102dae7063cSBenjamin Kietzman * 103fc79e461SBenjamin Kietzman * @param t Time to wait for a reply. Passing 0 as the timeout means 104dae7063cSBenjamin Kietzman * that you wish to ignore the reply. (Or catch it later somehow...) 105dae7063cSBenjamin Kietzman * 106dae7063cSBenjamin Kietzman * @return The reply received. 107dae7063cSBenjamin Kietzman * 1080de54404SBenjamin Kietzman * @throws boost::system::system_error When the response timed out (if 1090de54404SBenjamin Kietzman * timeout was not 0), or there was some other error. 110dae7063cSBenjamin Kietzman */ 111dae7063cSBenjamin Kietzman template <typename Duration> send(message & m,const Duration & t)112e62be329SEd Tanous message send(message& m, const Duration& t) { 113da3eeb6aSEd Tanous return this->get_service().send(this->get_implementation(), m, t); 114dae7063cSBenjamin Kietzman } 115dae7063cSBenjamin Kietzman 116a8b4eac4SEd Tanous template <typename... InputArgs> method_call(const dbus::endpoint & e,const InputArgs &...a)117a8b4eac4SEd Tanous message method_call(const dbus::endpoint& e, const InputArgs&... a) { 118a8b4eac4SEd Tanous message m = dbus::message::new_call(e); 119a8b4eac4SEd Tanous m.pack(a...); 120a8b4eac4SEd Tanous return this->get_service().send(this->get_implementation(), m, 121a8b4eac4SEd Tanous std::chrono::seconds(30)); 122a8b4eac4SEd Tanous } 123a8b4eac4SEd Tanous 124dae7063cSBenjamin Kietzman /// Send a message asynchronously. 125dae7063cSBenjamin Kietzman /** 126dae7063cSBenjamin Kietzman * @param m The message to send. 127dae7063cSBenjamin Kietzman * 128dae7063cSBenjamin Kietzman * @param handler Handler for the reply. 129dae7063cSBenjamin Kietzman * 130dae7063cSBenjamin Kietzman * @return Asynchronous result 131dae7063cSBenjamin Kietzman */ 132e62be329SEd Tanous 133dae7063cSBenjamin Kietzman template <typename MessageHandler> BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,void (boost::system::error_code,message))134dae7063cSBenjamin Kietzman inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler, 135dae7063cSBenjamin Kietzman void(boost::system::error_code, message)) 136da3eeb6aSEd Tanous async_send(message& m, BOOST_ASIO_MOVE_ARG(MessageHandler) handler) { 137dae7063cSBenjamin Kietzman return this->get_service().async_send( 138da3eeb6aSEd Tanous this->get_implementation(), m, 139dae7063cSBenjamin Kietzman BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)); 140dae7063cSBenjamin Kietzman } 141dae7063cSBenjamin Kietzman 142e62be329SEd Tanous // Small helper class for stipping off the error code from the function 143e62be329SEd Tanous // agrument definitions so unpack can be called appriately 144e62be329SEd Tanous template <typename T> 145e62be329SEd Tanous struct strip_first_arg {}; 146e62be329SEd Tanous 147e62be329SEd Tanous template <typename FirstArg, typename... Rest> 148e62be329SEd Tanous struct strip_first_arg<std::tuple<FirstArg, Rest...>> { 149e62be329SEd Tanous typedef std::tuple<Rest...> type; 150e62be329SEd Tanous }; 151e62be329SEd Tanous 152e62be329SEd Tanous template <typename MessageHandler, typename... InputArgs> async_method_call(MessageHandler handler,const dbus::endpoint & e,const InputArgs &...a)153a8b4eac4SEd Tanous auto async_method_call(MessageHandler handler, const dbus::endpoint& e, 154e62be329SEd Tanous const InputArgs&... a) { 155e62be329SEd Tanous message m = dbus::message::new_call(e); 156e62be329SEd Tanous if (!m.pack(a...)) { 157e62be329SEd Tanous // TODO(ed) Set error code? 158a8b4eac4SEd Tanous std::cerr << "Pack error\n"; 159e62be329SEd Tanous } else { 160a8b4eac4SEd Tanous // explicit copy of handler here. At this time, not clear why a copy is 161a8b4eac4SEd Tanous // needed 162a8b4eac4SEd Tanous return async_send( 163a8b4eac4SEd Tanous m, [handler](boost::system::error_code ec, dbus::message r) { 164e62be329SEd Tanous // Make a copy of the error code so we can modify it 165e62be329SEd Tanous typedef typename function_traits<MessageHandler>::decayed_arg_types 166e62be329SEd Tanous function_tuple; 167e62be329SEd Tanous typedef typename strip_first_arg<function_tuple>::type unpack_type; 168e62be329SEd Tanous unpack_type response_args; 169e62be329SEd Tanous if (!ec) { 170e62be329SEd Tanous if (!unpack_into_tuple(response_args, r)) { 171e62be329SEd Tanous // Set error code 172e62be329SEd Tanous ec = boost::system::errc::make_error_code( 173e62be329SEd Tanous boost::system::errc::invalid_argument); 174e62be329SEd Tanous } 175e62be329SEd Tanous } 176e62be329SEd Tanous // Should this (the callback) be done in a try catch block? 177a8b4eac4SEd Tanous // should throwing from a handler flow all the way to the 178a8b4eac4SEd Tanous // io_service? 179e62be329SEd Tanous 180e62be329SEd Tanous // Note. Callback is called whether or not the unpack was sucessful 181e62be329SEd Tanous // to allow the user to implement their own handling 182a8b4eac4SEd Tanous index_apply<std::tuple_size<unpack_type>{}>([&](auto... Is) { 183a8b4eac4SEd Tanous handler(ec, std::get<Is>(response_args)...); 184a8b4eac4SEd Tanous }); 185e62be329SEd Tanous }); 186e62be329SEd Tanous } 187e62be329SEd Tanous } 188e62be329SEd Tanous flush(void)189*70f79f4dSJames Feist void flush(void) { this->get_implementation().flush(); }; 190*70f79f4dSJames Feist 191dae7063cSBenjamin Kietzman /// Create a new match. new_match(match & m)192da3eeb6aSEd Tanous void new_match(match& m) { 193da3eeb6aSEd Tanous this->get_service().new_match(this->get_implementation(), m); 194cd8b76a3SBenjamin Kietzman } 195cd8b76a3SBenjamin Kietzman 196cd8b76a3SBenjamin Kietzman /// Destroy a match. delete_match(match & m)197da3eeb6aSEd Tanous void delete_match(match& m) { 198da3eeb6aSEd Tanous this->get_service().delete_match(this->get_implementation(), m); 199dae7063cSBenjamin Kietzman } 200dae7063cSBenjamin Kietzman 201dae7063cSBenjamin Kietzman /// Create a new filter. new_filter(filter & f)202da3eeb6aSEd Tanous void new_filter(filter& f) { 203da3eeb6aSEd Tanous this->get_service().new_filter(this->get_implementation(), f); 204dae7063cSBenjamin Kietzman } 205dae7063cSBenjamin Kietzman 20617826fe7SBenjamin Kietzman /// Destroy a filter. delete_filter(filter & f)207da3eeb6aSEd Tanous void delete_filter(filter& f) { 208da3eeb6aSEd Tanous this->get_service().delete_filter(this->get_implementation(), f); 209cd8b76a3SBenjamin Kietzman } 210fc79e461SBenjamin Kietzman 211da3eeb6aSEd Tanous // FIXME the only way around this I see is to expose start() here, which seems 212da3eeb6aSEd Tanous // ugly 2132003615dSBenjamin Kietzman friend class filter; 214dae7063cSBenjamin Kietzman }; 215dae7063cSBenjamin Kietzman 216b573e22eSEd Tanous typedef std::shared_ptr<connection> connection_ptr; 217b573e22eSEd Tanous 218dae7063cSBenjamin Kietzman } // namespace dbus 219fc79e461SBenjamin Kietzman 220fc79e461SBenjamin Kietzman #endif // DBUS_CONNECTION_HPP 221