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  DBusConnection* conn;
21
22  connection() : is_paused(true), conn(NULL) {}
23
24  void open(boost::asio::io_service& io, int bus) {
25    error e;
26    conn = dbus_bus_get_private((DBusBusType)bus, e);
27    e.throw_if_set();
28
29    dbus_connection_set_exit_on_disconnect(conn, false);
30
31    detail::set_watch_timeout_dispatch_functions(conn, io);
32  }
33
34  void open(boost::asio::io_service& io, const string& address) {
35    error e;
36    conn = dbus_connection_open_private(address.c_str(), e);
37    e.throw_if_set();
38
39    dbus_bus_register(conn, e);
40    e.throw_if_set();
41
42    dbus_connection_set_exit_on_disconnect(conn, false);
43
44    detail::set_watch_timeout_dispatch_functions(conn, io);
45  }
46
47  void request_name(const string& name) {
48    error e;
49    dbus_bus_request_name(conn, name.c_str(),
50			 DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING, e);
51    e.throw_if_set();
52  }
53
54  ~connection() {
55    if (conn != NULL) {
56      dbus_connection_close(conn);
57      dbus_connection_unref(conn);
58    }
59  }
60
61  message new_method_return(message &m) {
62  	return dbus_message_new_method_return(m);
63  }
64
65  operator DBusConnection*() { return conn; }
66  operator const DBusConnection*() const { return conn; }
67
68  message send_with_reply_and_block(message& m,
69                                    int timeout_in_milliseconds = -1) {
70    error e;
71    DBusMessage* out = dbus_connection_send_with_reply_and_block(
72        conn, m, timeout_in_milliseconds, e);
73    e.throw_if_set();
74    message reply(out);
75
76    return reply;
77  }
78
79  void send(message& m) {
80    // ignoring message serial for now
81    dbus_connection_send(conn, m, NULL);
82  }
83
84  void send_with_reply(message& m, DBusPendingCall** p,
85                       int timeout_in_milliseconds = -1) {
86    dbus_connection_send_with_reply(conn, m, p, timeout_in_milliseconds);
87  }
88
89  // begin asynchronous operation
90  // FIXME should not get io from an argument
91  void start(boost::asio::io_service& io) {
92    bool old_value(true);
93    if (is_paused.compare_exchange_strong(old_value, false)) {
94      // If two threads call connection::async_send()
95      // simultaneously on a paused connection, then
96      // only one will pass the CAS instruction and
97      // only one dispatch_handler will be injected.
98      io.post(detail::dispatch_handler(io, conn));
99    }
100  }
101
102  void cancel(boost::asio::io_service& io) {
103    bool old_value(false);
104    if (is_paused.compare_exchange_strong(old_value, true)) {
105      // TODO
106    }
107  }
108};
109
110}  // namespace impl
111}  // namespace dbus
112
113#endif  // DBUS_CONNECTION_IPP
114