blob: 51e836af92082188f6b026f6e6ad3d0cbc77ead7 [file] [log] [blame]
rspangler@google.com570c65b2009-10-09 20:56:14 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROMEOS_DBUS_H_
6#define CHROMEOS_DBUS_H_
7
8#include <dbus/dbus-glib.h>
9#include <glib-object.h>
rspangler@google.com570c65b2009-10-09 20:56:14 +000010
11#include <algorithm>
12#include <string>
13
seanparent@google.comf2ea0242009-11-04 21:04:51 +000014#include "base/logging.h"
rspangler@google.com570c65b2009-10-09 20:56:14 +000015#include "chromeos/glib/object.h"
16
Denis Glotov8a93c902011-02-11 22:32:49 +030017struct DBusMessage;
18struct DBusConnection;
19
rspangler@google.com570c65b2009-10-09 20:56:14 +000020namespace chromeos {
21
22// \precondition No functions in the dbus namespace can be called before
23// ::g_type_init();
24
25namespace dbus {
26
27// \brief BusConnection manages the ref-count for a ::DBusGConnection*.
28//
29// A BusConnection has reference semantics bound to a particular communication
30// bus.
31//
32// \models Copyable, Assignable
33// \related GetSystemBusConnection()
34
35class BusConnection {
36 public:
37 typedef ::DBusGConnection* value_type;
38
39 BusConnection(const BusConnection& x)
Yusuke Sato35371c82010-06-23 19:04:02 +090040 : object_(x.object_) {
41 if (object_)
42 ::dbus_g_connection_ref(object_);
rspangler@google.com570c65b2009-10-09 20:56:14 +000043 }
44
45 ~BusConnection() {
Yusuke Sato35371c82010-06-23 19:04:02 +090046 if (object_)
47 ::dbus_g_connection_unref(object_);
rspangler@google.com570c65b2009-10-09 20:56:14 +000048 }
49
50 BusConnection& operator=(BusConnection x) {
51 swap(*this, x);
52 return *this;
53 }
54
Yusuke Satof8059812010-01-09 20:13:07 +090055 const value_type& g_connection() const {
56 DCHECK(object_) << "referencing an empty connection";
57 return object_;
58 }
59
Yusuke Sato35371c82010-06-23 19:04:02 +090060 operator bool() const {
61 return object_;
62 }
63
64 bool HasConnection() const {
65 return object_;
66 }
67
rspangler@google.com570c65b2009-10-09 20:56:14 +000068 private:
69 friend void swap(BusConnection& x, BusConnection& y);
70
71 friend class Proxy;
72 friend BusConnection GetSystemBusConnection();
Yusuke Sato71da5ce2009-12-15 10:29:43 +090073 friend BusConnection GetPrivateBusConnection(const char* address);
rspangler@google.com570c65b2009-10-09 20:56:14 +000074
75 // Constructor takes ownership
76 explicit BusConnection(::DBusGConnection* x)
77 : object_(x) {
rspangler@google.com570c65b2009-10-09 20:56:14 +000078 }
79
80 value_type object_;
81};
82
83inline void swap(BusConnection& x, BusConnection& y) {
84 std::swap(x.object_, y.object_);
85}
86
87// \brief Proxy manages the ref-count for a ::DBusGProxy*.
88//
89// Proxy has reference semantics and represents a connection to on object on
90// the bus. A proxy object is constructed with a connection to a bus, a name
91// to an entity on the bus, a path to an object owned by the entity, and an
92// interface protocol name used to communicate with the object.
93
94class Proxy {
95 public:
96 typedef ::DBusGProxy* value_type;
97
98 Proxy()
99 : object_(NULL) {
100 }
101
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900102 // Set |connect_to_name_owner| true if you'd like to use
103 // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
104 Proxy(const BusConnection& connection,
105 const char* name,
106 const char* path,
107 const char* interface,
108 bool connect_to_name_owner)
109 : object_(GetGProxy(
110 connection, name, path, interface, connect_to_name_owner)) {
111 }
112
113 // Equivalent to Proxy(connection, name, path, interface, false).
rspangler@google.com570c65b2009-10-09 20:56:14 +0000114 Proxy(const BusConnection& connection,
115 const char* name,
116 const char* path,
117 const char* interface)
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900118 : object_(GetGProxy(connection, name, path, interface, false)) {
rspangler@google.com570c65b2009-10-09 20:56:14 +0000119 }
120
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700121 // Creates a peer proxy using dbus_g_proxy_new_for_peer.
122 Proxy(const BusConnection& connection,
123 const char* path,
124 const char* interface)
125 : object_(GetGPeerProxy(connection, path, interface)) {
126 }
127
rspangler@google.com570c65b2009-10-09 20:56:14 +0000128 Proxy(const Proxy& x)
129 : object_(x.object_) {
130 if (object_)
131 ::g_object_ref(object_);
132 }
133
134 ~Proxy() {
135 if (object_)
136 ::g_object_unref(object_);
137 }
138
139 Proxy& operator=(Proxy x) {
140 swap(*this, x);
141 return *this;
142 }
143
144 const char* path() const {
145 DCHECK(object_) << "referencing an empty proxy";
146 return ::dbus_g_proxy_get_path(object_);
147 }
148
149 // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
150 // library evolves, the gproxy() will be moved to be private.
151
152 const value_type& gproxy() const {
153 DCHECK(object_) << "referencing an empty proxy";
154 return object_;
155 }
156
157 operator bool() const {
158 return object_;
159 }
160
161 private:
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900162 static value_type GetGProxy(const BusConnection& connection,
163 const char* name,
164 const char* path,
165 const char* interface,
166 bool connect_to_name_owner);
167
Mitsuru Oshima93b37832010-05-18 14:17:57 -0700168 static value_type GetGPeerProxy(const BusConnection& connection,
169 const char* path,
170 const char* interface);
171
rspangler@google.com570c65b2009-10-09 20:56:14 +0000172 operator int() const; // for safe bool cast
173 friend void swap(Proxy& x, Proxy& y);
174
175 value_type object_;
176};
177
178inline void swap(Proxy& x, Proxy& y) {
179 std::swap(x.object_, y.object_);
180}
181
Chris Masonec8150f12010-01-12 12:23:22 -0800182// \brief RegisterExclusiveService configures a GObject to run as a service on
183// a supplied ::BusConnection.
184//
185// RegisterExclusiveService encapsulates the process of configuring the
186// supplied \param object at \param service_path on the \param connection.
187// Exclusivity is ensured by replacing any existing services at that named
188// location and confirming that the connection is the primary owner.
189//
190// Type information for the \param object must be installed with
191// dbus_g_object_type_install_info prior to use.
192
193bool RegisterExclusiveService(const BusConnection& connection,
194 const char* interface_name,
195 const char* service_name,
196 const char* service_path,
197 GObject* object);
198
rspangler@google.com570c65b2009-10-09 20:56:14 +0000199template <typename F> // F is a function signature
200class MonitorConnection;
201
202template <typename A1>
203class MonitorConnection<void (A1)> {
204 public:
205 MonitorConnection(const Proxy& proxy, const char* name,
206 void (*monitor)(void*, A1), void* object)
207 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
208 }
209
210 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
211 self->monitor_(self->object_, x);
212 }
213 const Proxy& proxy() const {
214 return proxy_;
215 }
216 const std::string& name() const {
217 return name_;
218 }
219
220 private:
221 Proxy proxy_;
222 std::string name_;
223 void (*monitor_)(void*, A1);
224 void* object_;
225};
226
227template <typename A1, typename A2>
228class MonitorConnection<void (A1, A2)> {
229 public:
230 MonitorConnection(const Proxy& proxy, const char* name,
231 void (*monitor)(void*, A1, A2), void* object)
232 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
233 }
234
235 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
236 self->monitor_(self->object_, x, y);
237 }
238 const Proxy& proxy() const {
239 return proxy_;
240 }
241 const std::string& name() const {
242 return name_;
243 }
244
245 private:
246 Proxy proxy_;
247 std::string name_;
248 void (*monitor_)(void*, A1, A2);
249 void* object_;
rspangler@google.com570c65b2009-10-09 20:56:14 +0000250};
251
Toni Barzicfa027112010-08-16 19:21:34 -0700252template <typename A1, typename A2, typename A3>
253class MonitorConnection<void (A1, A2, A3)> {
254 public:
255 MonitorConnection(const Proxy& proxy, const char* name,
256 void (*monitor)(void*, A1, A2, A3), void* object)
257 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
258 }
259
260 static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
261 self->monitor_(self->object_, x, y, z);
262 }
263 const Proxy& proxy() const {
264 return proxy_;
265 }
266 const std::string& name() const {
267 return name_;
268 }
269
270 private:
271 Proxy proxy_;
272 std::string name_;
273 void (*monitor_)(void*, A1, A2, A3);
274 void* object_;
tbarzic6dd315a2011-07-20 16:53:10 -0700275};
Toni Barzicfa027112010-08-16 19:21:34 -0700276
tbarzic6dd315a2011-07-20 16:53:10 -0700277template <typename A1, typename A2, typename A3, typename A4>
278class MonitorConnection<void (A1, A2, A3, A4)> {
279 public:
280 MonitorConnection(const Proxy& proxy, const char* name,
281 void (*monitor)(void*, A1, A2, A3, A4), void* object)
282 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {
283 }
284
285 static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, A4 w,
286 MonitorConnection* self) {
287 self->monitor_(self->object_, x, y, z, w);
288 }
289 const Proxy& proxy() const {
290 return proxy_;
291 }
292 const std::string& name() const {
293 return name_;
294 }
295
296 private:
297 Proxy proxy_;
298 std::string name_;
299 void (*monitor_)(void*, A1, A2, A3, A4);
300 void* object_;
Toni Barzicfa027112010-08-16 19:21:34 -0700301};
302
rspangler@google.com570c65b2009-10-09 20:56:14 +0000303template <typename A1>
304MonitorConnection<void (A1)>* Monitor(const Proxy& proxy, const char* name,
305 void (*monitor)(void*, A1),
306 void* object) {
307 typedef MonitorConnection<void (A1)> ConnectionType;
308
309 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
310
311 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
312 glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
313 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
314 G_CALLBACK(&ConnectionType::Run),
315 result, NULL);
316 return result;
317}
318
319template <typename A1, typename A2>
320MonitorConnection<void (A1, A2)>* Monitor(const Proxy& proxy, const char* name,
321 void (*monitor)(void*, A1, A2),
322 void* object) {
323 typedef MonitorConnection<void (A1, A2)> ConnectionType;
324
325 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
326
327 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
328 glib::type_to_gtypeid<A1>(),
329 glib::type_to_gtypeid<A2>(),
330 G_TYPE_INVALID);
331 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
332 G_CALLBACK(&ConnectionType::Run),
333 result, NULL);
334 return result;
335}
336
Toni Barzicfa027112010-08-16 19:21:34 -0700337template <typename A1, typename A2, typename A3>
338MonitorConnection<void (A1, A2, A3)>* Monitor(const Proxy& proxy,
339 const char* name,
340 void (*monitor)(void*, A1, A2, A3),
341 void* object) {
342 typedef MonitorConnection<void (A1, A2, A3)> ConnectionType;
343
344 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
345
346 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
347 glib::type_to_gtypeid<A1>(),
348 glib::type_to_gtypeid<A2>(),
349 glib::type_to_gtypeid<A3>(),
350 G_TYPE_INVALID);
351 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
352 G_CALLBACK(&ConnectionType::Run),
353 result, NULL);
354 return result;
355}
356
tbarzic6dd315a2011-07-20 16:53:10 -0700357template <typename A1, typename A2, typename A3, typename A4>
358MonitorConnection<void (A1, A2, A3, A4)>* Monitor(const Proxy& proxy,
359 const char* name,
360 void (*monitor)(void*, A1, A2, A3, A4),
361 void* object) {
362 typedef MonitorConnection<void (A1, A2, A3, A4)> ConnectionType;
363
364 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
365
366 ::dbus_g_proxy_add_signal(proxy.gproxy(), name,
367 glib::type_to_gtypeid<A1>(),
368 glib::type_to_gtypeid<A2>(),
369 glib::type_to_gtypeid<A3>(),
370 glib::type_to_gtypeid<A4>(),
371 G_TYPE_INVALID);
372 ::dbus_g_proxy_connect_signal(proxy.gproxy(), name,
373 G_CALLBACK(&ConnectionType::Run),
374 result, NULL);
375 return result;
376}
377
rspangler@google.com570c65b2009-10-09 20:56:14 +0000378template <typename F>
379void Disconnect(MonitorConnection<F>* connection) {
380 typedef MonitorConnection<F> ConnectionType;
381
382 ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
383 connection->name().c_str(),
384 G_CALLBACK(&ConnectionType::Run),
385 connection);
386 delete connection;
387}
388
389// \brief call_PtrArray() invokes a method on a proxy returning a
390// glib::PtrArray.
391//
392// CallPtrArray is the first instance of what is likely to be a general
393// way to make method calls to a proxy. It will likely be replaced with
394// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
395// future. However, I don't yet have enough cases to generalize from.
396
397bool CallPtrArray(const Proxy& proxy,
398 const char* method,
399 glib::ScopedPtrArray<const char*>* result);
400
401// \brief RetrieveProperty() retrieves a property of an object associated with a
402// proxy.
403//
404// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
405// interface, the RetrieveProperty() call will retrieve a property of the
406// specified interface on the object storing it in \param result and returning
407// \true. If the dbus call fails or the object returned is not of type \param T,
408// then \false is returned and \param result is unchanged.
409//
410// \example
411// Proxy proxy(GetSystemBusConnection(),
412// "org.freedesktop.DeviceKit.Power", // A named entity on the bus
413// battery_name, // Path to a battery on the bus
414// "org.freedesktop.DBus.Properties") // Properties interface
415//
416// double x;
417// if (RetrieveProperty(proxy,
418// "org.freedesktop.DeviceKit.Power.Device",
419// "percentage")
420// std::cout << "Battery charge is " << x << "% of capacity.";
421// \end_example
422
423template <typename T>
424bool RetrieveProperty(const Proxy& proxy,
425 const char* interface,
426 const char* property,
427 T* result) {
428 glib::ScopedError error;
429 glib::Value value;
430
431 if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
432 G_TYPE_STRING, interface,
433 G_TYPE_STRING, property,
434 G_TYPE_INVALID,
435 G_TYPE_VALUE, &value,
dhg@google.com7ec90e92009-10-27 16:44:35 +0000436 G_TYPE_INVALID)){
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900437 LOG(ERROR) << "Getting property failed: "
438 << (error->message ? error->message : "Unknown Error.");
rspangler@google.com570c65b2009-10-09 20:56:14 +0000439 return false;
440
dhg@google.com7ec90e92009-10-27 16:44:35 +0000441 }
442 return glib::Retrieve(value, result);
rspangler@google.com570c65b2009-10-09 20:56:14 +0000443}
444
445// \brief RetrieveProperties returns a HashTable of all properties for the
446// specified interface.
447
448bool RetrieveProperties(const Proxy& proxy,
449 const char* interface,
450 glib::ScopedHashTable* result);
451
452// \brief Returns a connection to the system bus.
453
454BusConnection GetSystemBusConnection();
455
Yusuke Sato71da5ce2009-12-15 10:29:43 +0900456// \brief Returns a private connection to a bus at |address|.
457
458BusConnection GetPrivateBusConnection(const char* address);
459
Satoru Takabayashi295dee22010-10-20 14:50:52 +0900460// \brief Sends a signal named |signal_name| with no arguments to the
461// system bus per the given |path| and |interface_name|.
462
463void SendSignalWithNoArgumentsToSystemBus(const char* path,
464 const char* interface_name,
465 const char* signal_name);
466
Denis Glotov8a93c902011-02-11 22:32:49 +0300467// \brief Low-level signal monitor base class.
468//
469// Used when there is no definite named signal sender (that Proxy
470// could be used for).
471
472class SignalWatcher {
473 public:
474 SignalWatcher() {}
475 ~SignalWatcher();
476 void StartMonitoring(const std::string& interface, const std::string& signal);
477 private:
478
479 // Callback invoked on the given signal arrival.
480 virtual void OnSignal(DBusMessage* message) = 0;
481
482 // Returns a string matching the D-Bus messages that we want to listen for.
483 std::string GetDBusMatchString() const;
484
485 // A D-Bus message filter to receive signals.
486 static DBusHandlerResult FilterDBusMessage(DBusConnection* dbus_conn,
487 DBusMessage* message,
488 void* data);
489 std::string interface_;
490 std::string signal_;
491};
492
rspangler@google.com570c65b2009-10-09 20:56:14 +0000493} // namespace dbus
494} // namespace chromeos
495
496#endif // CHROMEOS_DBUS_H_