1a3cc3d57SBenjamin Kietzman// Copyright (c) Benjamin Kietzman (github.com/bkietz)
2a3cc3d57SBenjamin Kietzman//
3a3cc3d57SBenjamin Kietzman// Distributed under the Boost Software License, Version 1.0. (See accompanying
4a3cc3d57SBenjamin Kietzman// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5a3cc3d57SBenjamin Kietzman
6a3cc3d57SBenjamin Kietzman#ifndef DBUS_CONNECTION_IPP
7a3cc3d57SBenjamin Kietzman#define DBUS_CONNECTION_IPP
8a3cc3d57SBenjamin Kietzman
9a3cc3d57SBenjamin Kietzman#include <dbus/dbus.h>
10a3cc3d57SBenjamin Kietzman#include <dbus/detail/watch_timeout.hpp>
11a3cc3d57SBenjamin Kietzman
12cfc0655fSBenjamin Kietzman#include <boost/atomic.hpp>
13a3cc3d57SBenjamin Kietzman
14a3cc3d57SBenjamin Kietzmannamespace dbus {
15a3cc3d57SBenjamin Kietzmannamespace impl {
16a3cc3d57SBenjamin Kietzman
17da3eeb6aSEd Tanousclass connection {
18a3cc3d57SBenjamin Kietzman public:
19cfc0655fSBenjamin Kietzman  boost::atomic<bool> is_paused;
2077e62c83SEd Tanous
2177e62c83SEd Tanous private:
22cfc0655fSBenjamin Kietzman  DBusConnection* conn;
23a3cc3d57SBenjamin Kietzman
2477e62c83SEd Tanous public:
25da3eeb6aSEd Tanous  connection() : is_paused(true), conn(NULL) {}
26a3cc3d57SBenjamin Kietzman
2777e62c83SEd Tanous  connection(const connection& other) = delete;  // non construction-copyable
2877e62c83SEd Tanous  connection& operator=(const connection&) = delete;  // non copyable
2977e62c83SEd Tanous  connection(connection&&) = delete;
3077e62c83SEd Tanous  connection& operator=(connection&&) = delete;
3177e62c83SEd Tanous
32da3eeb6aSEd Tanous  void open(boost::asio::io_service& io, int bus) {
33a3cc3d57SBenjamin Kietzman    error e;
34a3cc3d57SBenjamin Kietzman    conn = dbus_bus_get_private((DBusBusType)bus, e);
35a3cc3d57SBenjamin Kietzman    e.throw_if_set();
36a3cc3d57SBenjamin Kietzman
37cfc0655fSBenjamin Kietzman    dbus_connection_set_exit_on_disconnect(conn, false);
38a3cc3d57SBenjamin Kietzman
39cfc0655fSBenjamin Kietzman    detail::set_watch_timeout_dispatch_functions(conn, io);
40a3cc3d57SBenjamin Kietzman  }
41a3cc3d57SBenjamin Kietzman
42da3eeb6aSEd Tanous  void open(boost::asio::io_service& io, const string& address) {
43a3cc3d57SBenjamin Kietzman    error e;
44a3cc3d57SBenjamin Kietzman    conn = dbus_connection_open_private(address.c_str(), e);
452003615dSBenjamin Kietzman    e.throw_if_set();
46a3cc3d57SBenjamin Kietzman
47cfc0655fSBenjamin Kietzman    dbus_bus_register(conn, e);
48a3cc3d57SBenjamin Kietzman    e.throw_if_set();
49a3cc3d57SBenjamin Kietzman
50cfc0655fSBenjamin Kietzman    dbus_connection_set_exit_on_disconnect(conn, false);
51a3cc3d57SBenjamin Kietzman
52cfc0655fSBenjamin Kietzman    detail::set_watch_timeout_dispatch_functions(conn, io);
53a3cc3d57SBenjamin Kietzman  }
54a3cc3d57SBenjamin Kietzman
55458a9c10SVernon Mauery  void request_name(const string& name) {
56458a9c10SVernon Mauery    error e;
5777e62c83SEd Tanous    dbus_bus_request_name(
5877e62c83SEd Tanous        conn, name.c_str(),
59458a9c10SVernon Mauery        DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING, e);
60458a9c10SVernon Mauery    e.throw_if_set();
61458a9c10SVernon Mauery  }
62458a9c10SVernon Mauery
630d6f56d2SEd Tanous  std::string get_unique_name() {
640d6f56d2SEd Tanous    error e;
650d6f56d2SEd Tanous    auto name = dbus_bus_get_unique_name(conn);
660d6f56d2SEd Tanous    e.throw_if_set();
670d6f56d2SEd Tanous    return std::string(name);
680d6f56d2SEd Tanous  }
690d6f56d2SEd Tanous
70da3eeb6aSEd Tanous  ~connection() {
718f81b71dSBenjamin Kietzman    if (conn != NULL) {
72cfc0655fSBenjamin Kietzman      dbus_connection_close(conn);
73cfc0655fSBenjamin Kietzman      dbus_connection_unref(conn);
74a3cc3d57SBenjamin Kietzman    }
758f81b71dSBenjamin Kietzman  }
76a3cc3d57SBenjamin Kietzman
77458a9c10SVernon Mauery  message new_method_return(message& m) {
7877e62c83SEd Tanous    auto ptr = dbus_message_new_method_return(m);
7977e62c83SEd Tanous    auto x = message(ptr);
8077e62c83SEd Tanous    dbus_message_unref(ptr);
8177e62c83SEd Tanous    return x;
82458a9c10SVernon Mauery  }
83458a9c10SVernon Mauery
84da3eeb6aSEd Tanous  operator DBusConnection*() { return conn; }
85da3eeb6aSEd Tanous  operator const DBusConnection*() const { return conn; }
86a3cc3d57SBenjamin Kietzman
87b55ed5d5SBenjamin Kietzman  message send_with_reply_and_block(message& m,
88da3eeb6aSEd Tanous                                    int timeout_in_milliseconds = -1) {
89b55ed5d5SBenjamin Kietzman    error e;
9077e62c83SEd Tanous
91da3eeb6aSEd Tanous    DBusMessage* out = dbus_connection_send_with_reply_and_block(
92da3eeb6aSEd Tanous        conn, m, timeout_in_milliseconds, e);
9377e62c83SEd Tanous
94b55ed5d5SBenjamin Kietzman    e.throw_if_set();
95da3eeb6aSEd Tanous    message reply(out);
9677e62c83SEd Tanous    dbus_message_unref(out);
97b55ed5d5SBenjamin Kietzman    return reply;
98b55ed5d5SBenjamin Kietzman  }
99b55ed5d5SBenjamin Kietzman
100da3eeb6aSEd Tanous  void send(message& m) {
101b55ed5d5SBenjamin Kietzman    // ignoring message serial for now
102b55ed5d5SBenjamin Kietzman    dbus_connection_send(conn, m, NULL);
103b55ed5d5SBenjamin Kietzman  }
104b55ed5d5SBenjamin Kietzman
105da3eeb6aSEd Tanous  void send_with_reply(message& m, DBusPendingCall** p,
106da3eeb6aSEd Tanous                       int timeout_in_milliseconds = -1) {
107377e76abSEd Tanous    // TODO(Ed) check error code
108da3eeb6aSEd Tanous    dbus_connection_send_with_reply(conn, m, p, timeout_in_milliseconds);
109b55ed5d5SBenjamin Kietzman  }
110b55ed5d5SBenjamin Kietzman
1112003615dSBenjamin Kietzman  // begin asynchronous operation
1122003615dSBenjamin Kietzman  // FIXME should not get io from an argument
113da3eeb6aSEd Tanous  void start(boost::asio::io_service& io) {
114cfc0655fSBenjamin Kietzman    bool old_value(true);
115da3eeb6aSEd Tanous    if (is_paused.compare_exchange_strong(old_value, false)) {
116cfc0655fSBenjamin Kietzman      // If two threads call connection::async_send()
117cfc0655fSBenjamin Kietzman      // simultaneously on a paused connection, then
118cfc0655fSBenjamin Kietzman      // only one will pass the CAS instruction and
119cfc0655fSBenjamin Kietzman      // only one dispatch_handler will be injected.
120cfc0655fSBenjamin Kietzman      io.post(detail::dispatch_handler(io, conn));
121cfc0655fSBenjamin Kietzman    }
122cfc0655fSBenjamin Kietzman  }
123cfc0655fSBenjamin Kietzman
124da3eeb6aSEd Tanous  void cancel(boost::asio::io_service& io) {
125cfc0655fSBenjamin Kietzman    bool old_value(false);
126da3eeb6aSEd Tanous    if (is_paused.compare_exchange_strong(old_value, true)) {
127cfc0655fSBenjamin Kietzman      // TODO
1282003615dSBenjamin Kietzman    }
129a3cc3d57SBenjamin Kietzman  }
130*70f79f4dSJames Feist
131*70f79f4dSJames Feist  void flush(void) { dbus_connection_flush(conn); }
132a3cc3d57SBenjamin Kietzman};
133a3cc3d57SBenjamin Kietzman
134a3cc3d57SBenjamin Kietzman}  // namespace impl
135a3cc3d57SBenjamin Kietzman}  // namespace dbus
136a3cc3d57SBenjamin Kietzman
137a3cc3d57SBenjamin Kietzman#endif  // DBUS_CONNECTION_IPP
138