1fc79e461SBenjamin Kietzman #ifndef DBUS_CONNECTION_SERVICE_HPP 2fc79e461SBenjamin Kietzman #define DBUS_CONNECTION_SERVICE_HPP 3fc79e461SBenjamin Kietzman 4fc79e461SBenjamin Kietzman #include <string> 5d620effbSBenjamin Kietzman #include <boost/asio.hpp> 6d620effbSBenjamin Kietzman 7fc79e461SBenjamin Kietzman #include <dbus/message.hpp> 8fc79e461SBenjamin Kietzman #include <dbus/detail/watch_timeout.hpp> 9fc79e461SBenjamin Kietzman #include <dbus/detail/queue.hpp> 10*cd8b76a3SBenjamin Kietzman #include <dbus/match.hpp> 11fc79e461SBenjamin Kietzman 12d620effbSBenjamin Kietzman namespace dbus { 13d620effbSBenjamin Kietzman 14*cd8b76a3SBenjamin Kietzman namespace bus { 15*cd8b76a3SBenjamin Kietzman static const int session = DBUS_BUS_SESSION; 16*cd8b76a3SBenjamin Kietzman static const int system = DBUS_BUS_SYSTEM; 17*cd8b76a3SBenjamin Kietzman static const int starter = DBUS_BUS_STARTER; 18*cd8b76a3SBenjamin Kietzman } // namespace bus 19*cd8b76a3SBenjamin Kietzman 20fc79e461SBenjamin Kietzman using std::string; 21fc79e461SBenjamin Kietzman using namespace boost::asio; 22fc79e461SBenjamin Kietzman 23d620effbSBenjamin Kietzman class connection_service 24d620effbSBenjamin Kietzman : public io_service::service 25d620effbSBenjamin Kietzman { 26d620effbSBenjamin Kietzman public: 27d620effbSBenjamin Kietzman static io_service::id id; 28d620effbSBenjamin Kietzman 29d620effbSBenjamin Kietzman typedef DBusConnection *implementation_type; 30d620effbSBenjamin Kietzman 31d620effbSBenjamin Kietzman explicit connection_service(io_service& io) 32d620effbSBenjamin Kietzman : service(io) 33d620effbSBenjamin Kietzman { 34d620effbSBenjamin Kietzman } 35d620effbSBenjamin Kietzman 36d620effbSBenjamin Kietzman void construct(implementation_type& impl) 37d620effbSBenjamin Kietzman { 38d620effbSBenjamin Kietzman } 39d620effbSBenjamin Kietzman 40d620effbSBenjamin Kietzman void destroy(implementation_type& impl) 41d620effbSBenjamin Kietzman { 42d620effbSBenjamin Kietzman dbus_connection_unref(impl); 43d620effbSBenjamin Kietzman } 44d620effbSBenjamin Kietzman 45d620effbSBenjamin Kietzman void shutdown_service() 46d620effbSBenjamin Kietzman { 47*cd8b76a3SBenjamin Kietzman //TODO is there anything that needs shutting down? 48d620effbSBenjamin Kietzman } 49d620effbSBenjamin Kietzman 50d620effbSBenjamin Kietzman void open(implementation_type& impl, 51d620effbSBenjamin Kietzman const string& address, bool shared=true) 52d620effbSBenjamin Kietzman { 53d620effbSBenjamin Kietzman io_service& io = this->get_io_service(); 54d620effbSBenjamin Kietzman 55d620effbSBenjamin Kietzman DBusError error; 56d620effbSBenjamin Kietzman dbus_error_init(&error); 57d620effbSBenjamin Kietzman impl = dbus_connection_open(address.c_str(), &error); 58d620effbSBenjamin Kietzman //TODO actually deal with that error 59d620effbSBenjamin Kietzman 60*cd8b76a3SBenjamin Kietzman detail::set_watch_timeout_dispatch_functions(impl, io); 61d620effbSBenjamin Kietzman } 62d620effbSBenjamin Kietzman 63d620effbSBenjamin Kietzman void open(implementation_type& impl, 64*cd8b76a3SBenjamin Kietzman const int bus = (int) DBUS_BUS_SYSTEM, 65d620effbSBenjamin Kietzman bool shared=true) 66d620effbSBenjamin Kietzman { 67d620effbSBenjamin Kietzman io_service& io = this->get_io_service(); 68d620effbSBenjamin Kietzman 69d620effbSBenjamin Kietzman DBusError error; 70d620effbSBenjamin Kietzman dbus_error_init(&error); 71*cd8b76a3SBenjamin Kietzman impl = dbus_bus_get((DBusBusType)bus, &error); 72d620effbSBenjamin Kietzman //TODO actually deal with that error 73d620effbSBenjamin Kietzman 74*cd8b76a3SBenjamin Kietzman detail::set_watch_timeout_dispatch_functions(impl, io); 75*cd8b76a3SBenjamin Kietzman } 76d620effbSBenjamin Kietzman 77*cd8b76a3SBenjamin Kietzman message send(implementation_type& impl, 78*cd8b76a3SBenjamin Kietzman message& m) 79*cd8b76a3SBenjamin Kietzman { 80*cd8b76a3SBenjamin Kietzman DBusError error; 81*cd8b76a3SBenjamin Kietzman dbus_error_init(&error); 82*cd8b76a3SBenjamin Kietzman return message(dbus_connection_send_with_reply_and_block(impl, 83*cd8b76a3SBenjamin Kietzman m, -1, &error)); 84*cd8b76a3SBenjamin Kietzman //TODO deal with that error 85d620effbSBenjamin Kietzman } 86d620effbSBenjamin Kietzman 87d620effbSBenjamin Kietzman template <typename Duration> 88d620effbSBenjamin Kietzman message send(implementation_type& impl, 89d620effbSBenjamin Kietzman message& m, 90d620effbSBenjamin Kietzman const Duration& timeout) 91d620effbSBenjamin Kietzman { 92d620effbSBenjamin Kietzman //TODO generically convert timeout to milliseconds 93*cd8b76a3SBenjamin Kietzman if(timeout == Duration::zero()) { 94d620effbSBenjamin Kietzman //TODO this can return false if it failed 95d620effbSBenjamin Kietzman dbus_connection_send(impl, m, &m.serial); 96d620effbSBenjamin Kietzman return message(); 97d620effbSBenjamin Kietzman } else { 98d620effbSBenjamin Kietzman DBusError error; 99d620effbSBenjamin Kietzman dbus_error_init(&error); 1000de54404SBenjamin Kietzman return message(dbus_connection_send_with_reply_and_block(impl, 101*cd8b76a3SBenjamin Kietzman m, chrono::milliseconds(timeout).count(), &error)); 102d620effbSBenjamin Kietzman //TODO deal with that error 103d620effbSBenjamin Kietzman } 104d620effbSBenjamin Kietzman } 105d620effbSBenjamin Kietzman 106d620effbSBenjamin Kietzman template<typename MessageHandler> 107d620effbSBenjamin Kietzman inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler, 108d620effbSBenjamin Kietzman void(boost::system::error_code, message)) 109d620effbSBenjamin Kietzman async_send(implementation_type& impl, 110d620effbSBenjamin Kietzman message& m, 111d620effbSBenjamin Kietzman BOOST_ASIO_MOVE_ARG(MessageHandler) handler) 112d620effbSBenjamin Kietzman { 113d620effbSBenjamin Kietzman DBusPendingCall *p; 114d620effbSBenjamin Kietzman dbus_connection_send_with_reply(impl, 115d620effbSBenjamin Kietzman m, &p, -1); 116*cd8b76a3SBenjamin Kietzman /* 117*cd8b76a3SBenjamin Kietzman dbus_pending_call_set_notify(p, 118*cd8b76a3SBenjamin Kietzman &pending_call_notify, &get_io_service(), NULL); 119*cd8b76a3SBenjamin Kietzman 120*cd8b76a3SBenjamin Kietzman //FIXME Race condition: another thread might have 121*cd8b76a3SBenjamin Kietzman // processed the pending call's reply before a notify 122*cd8b76a3SBenjamin Kietzman // function could be set. If so, the notify function 123*cd8b76a3SBenjamin Kietzman // will never trigger, so it must be called manually: 124*cd8b76a3SBenjamin Kietzman if(dbus_pending_call_get_completed(p)) 125*cd8b76a3SBenjamin Kietzman { 126*cd8b76a3SBenjamin Kietzman //TODO: does this work, or might it call the notify 127*cd8b76a3SBenjamin Kietzman // function too many times? Might have to use steal_reply 128*cd8b76a3SBenjamin Kietzman pending_call_notify(p, &get_io_service()); 129*cd8b76a3SBenjamin Kietzman } 130*cd8b76a3SBenjamin Kietzman */ 131d620effbSBenjamin Kietzman } 132d620effbSBenjamin Kietzman 133*cd8b76a3SBenjamin Kietzman void new_match(implementation_type& impl, 134*cd8b76a3SBenjamin Kietzman match& m) 135*cd8b76a3SBenjamin Kietzman { 136*cd8b76a3SBenjamin Kietzman DBusError err; 137*cd8b76a3SBenjamin Kietzman dbus_error_init(&err); 138*cd8b76a3SBenjamin Kietzman dbus_bus_add_match(impl, m.get_expression().c_str(), &err); 139*cd8b76a3SBenjamin Kietzman //TODO deal with that error 140*cd8b76a3SBenjamin Kietzman // eventually, for complete asynchronicity, this should connect to 141*cd8b76a3SBenjamin Kietzman // org.freedesktop.DBus and call org.freedesktop.DBus.AddMatch 142*cd8b76a3SBenjamin Kietzman } 143*cd8b76a3SBenjamin Kietzman 144*cd8b76a3SBenjamin Kietzman void delete_match(implementation_type& impl, 145*cd8b76a3SBenjamin Kietzman match& m) 146*cd8b76a3SBenjamin Kietzman { 147*cd8b76a3SBenjamin Kietzman DBusError err; 148*cd8b76a3SBenjamin Kietzman dbus_error_init(&err); 149*cd8b76a3SBenjamin Kietzman dbus_bus_remove_match(impl, m.get_expression().c_str(), &err); 150*cd8b76a3SBenjamin Kietzman } 151*cd8b76a3SBenjamin Kietzman 152*cd8b76a3SBenjamin Kietzman static DBusHandlerResult filter_wrap( 153*cd8b76a3SBenjamin Kietzman DBusConnection *c, 154*cd8b76a3SBenjamin Kietzman DBusMessage *m, 155*cd8b76a3SBenjamin Kietzman void *userdata) 156*cd8b76a3SBenjamin Kietzman { 157*cd8b76a3SBenjamin Kietzman try 158*cd8b76a3SBenjamin Kietzman { 159*cd8b76a3SBenjamin Kietzman filter& f = *static_cast<filter *>(userdata); 160*cd8b76a3SBenjamin Kietzman if(f.offer(message(m))) 161*cd8b76a3SBenjamin Kietzman { 162*cd8b76a3SBenjamin Kietzman return DBUS_HANDLER_RESULT_HANDLED; 163*cd8b76a3SBenjamin Kietzman } 164*cd8b76a3SBenjamin Kietzman } catch(...) { 165*cd8b76a3SBenjamin Kietzman // do not throw in C callbacks. Just don't. 166*cd8b76a3SBenjamin Kietzman } 167*cd8b76a3SBenjamin Kietzman 168*cd8b76a3SBenjamin Kietzman return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 169*cd8b76a3SBenjamin Kietzman } 170*cd8b76a3SBenjamin Kietzman 171*cd8b76a3SBenjamin Kietzman void new_filter(implementation_type& impl, 172*cd8b76a3SBenjamin Kietzman filter& f) 173*cd8b76a3SBenjamin Kietzman { 174*cd8b76a3SBenjamin Kietzman dbus_connection_add_filter(impl, 175*cd8b76a3SBenjamin Kietzman &filter_wrap, &f, NULL); 176*cd8b76a3SBenjamin Kietzman } 177*cd8b76a3SBenjamin Kietzman 178*cd8b76a3SBenjamin Kietzman void delete_filter(implementation_type& impl, 179*cd8b76a3SBenjamin Kietzman filter& f) 180*cd8b76a3SBenjamin Kietzman { 181*cd8b76a3SBenjamin Kietzman dbus_connection_remove_filter(impl, 182*cd8b76a3SBenjamin Kietzman &filter_wrap, &f); 183*cd8b76a3SBenjamin Kietzman } 184d620effbSBenjamin Kietzman }; 185d620effbSBenjamin Kietzman 186d620effbSBenjamin Kietzman io_service::id connection_service::id; 187d620effbSBenjamin Kietzman 188*cd8b76a3SBenjamin Kietzman 189*cd8b76a3SBenjamin Kietzman 190*cd8b76a3SBenjamin Kietzman 191d620effbSBenjamin Kietzman } // namespace dbus 192fc79e461SBenjamin Kietzman 193fc79e461SBenjamin Kietzman #endif // DBUS_CONNECTION_SERVICE_HPP 194