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