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_CONNECTION_IPP 7#define DBUS_CONNECTION_IPP 8 9#include <dbus/dbus.h> 10#include <dbus/detail/watch_timeout.hpp> 11 12#include <boost/atomic.hpp> 13 14namespace dbus { 15namespace impl { 16 17class connection { 18 public: 19 boost::atomic<bool> is_paused; 20 21 private: 22 DBusConnection* conn; 23 24 public: 25 connection() : is_paused(true), conn(NULL) {} 26 27 connection(const connection& other) = delete; // non construction-copyable 28 connection& operator=(const connection&) = delete; // non copyable 29 connection(connection&&) = delete; 30 connection& operator=(connection&&) = delete; 31 32 void open(boost::asio::io_service& io, int bus) { 33 error e; 34 conn = dbus_bus_get_private((DBusBusType)bus, e); 35 e.throw_if_set(); 36 37 dbus_connection_set_exit_on_disconnect(conn, false); 38 39 detail::set_watch_timeout_dispatch_functions(conn, io); 40 } 41 42 void open(boost::asio::io_service& io, const string& address) { 43 error e; 44 conn = dbus_connection_open_private(address.c_str(), e); 45 e.throw_if_set(); 46 47 dbus_bus_register(conn, e); 48 e.throw_if_set(); 49 50 dbus_connection_set_exit_on_disconnect(conn, false); 51 52 detail::set_watch_timeout_dispatch_functions(conn, io); 53 } 54 55 void request_name(const string& name) { 56 error e; 57 dbus_bus_request_name( 58 conn, name.c_str(), 59 DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING, e); 60 e.throw_if_set(); 61 } 62 63 std::string get_unique_name() { 64 error e; 65 auto name = dbus_bus_get_unique_name(conn); 66 e.throw_if_set(); 67 return std::string(name); 68 } 69 70 ~connection() { 71 if (conn != NULL) { 72 dbus_connection_close(conn); 73 dbus_connection_unref(conn); 74 } 75 } 76 77 message new_method_return(message& m) { 78 auto ptr = dbus_message_new_method_return(m); 79 auto x = message(ptr); 80 dbus_message_unref(ptr); 81 return x; 82 } 83 84 operator DBusConnection*() { return conn; } 85 operator const DBusConnection*() const { return conn; } 86 87 message send_with_reply_and_block(message& m, 88 int timeout_in_milliseconds = -1) { 89 error e; 90 91 DBusMessage* out = dbus_connection_send_with_reply_and_block( 92 conn, m, timeout_in_milliseconds, e); 93 94 e.throw_if_set(); 95 message reply(out); 96 dbus_message_unref(out); 97 return reply; 98 } 99 100 void send(message& m) { 101 // ignoring message serial for now 102 dbus_connection_send(conn, m, NULL); 103 } 104 105 void send_with_reply(message& m, DBusPendingCall** p, 106 int timeout_in_milliseconds = -1) { 107 // TODO(Ed) check error code 108 dbus_connection_send_with_reply(conn, m, p, timeout_in_milliseconds); 109 } 110 111 // begin asynchronous operation 112 // FIXME should not get io from an argument 113 void start(boost::asio::io_service& io) { 114 bool old_value(true); 115 if (is_paused.compare_exchange_strong(old_value, false)) { 116 // If two threads call connection::async_send() 117 // simultaneously on a paused connection, then 118 // only one will pass the CAS instruction and 119 // only one dispatch_handler will be injected. 120 io.post(detail::dispatch_handler(io, conn)); 121 } 122 } 123 124 void cancel(boost::asio::io_service& io) { 125 bool old_value(false); 126 if (is_paused.compare_exchange_strong(old_value, true)) { 127 // TODO 128 } 129 } 130 131 void flush(void) { dbus_connection_flush(conn); } 132}; 133 134} // namespace impl 135} // namespace dbus 136 137#endif // DBUS_CONNECTION_IPP 138