1 // 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 LIBBRILLO_BRILLO_GLIB_DBUS_H_
6 #define LIBBRILLO_BRILLO_GLIB_DBUS_H_
7
8 // IMPORTANT: Do not use this in new code. Instead, use libchrome's D-Bus
9 // bindings. See https://goo.gl/EH3MmR for more details.
10
11 #include <dbus/dbus-glib.h>
12 #include <glib-object.h>
13
14 #include <algorithm>
15 #include <string>
16 #include <utility>
17
18 #include "base/logging.h"
19 #include <brillo/brillo_export.h>
20 #include <brillo/glib/object.h>
21
22 struct DBusMessage;
23 struct DBusConnection;
24
25 namespace brillo {
26
27 namespace dbus {
28
29 // \brief BusConnection manages the ref-count for a ::DBusGConnection*.
30 //
31 // A BusConnection has reference semantics bound to a particular communication
32 // bus.
33 //
34 // \models Copyable, Assignable
35 // \related GetSystemBusConnection()
36
37 class BRILLO_EXPORT BusConnection {
38 public:
39 typedef ::DBusGConnection* value_type;
40
BusConnection(const BusConnection & x)41 BusConnection(const BusConnection& x) : object_(x.object_) {
42 if (object_)
43 ::dbus_g_connection_ref(object_);
44 }
45
~BusConnection()46 ~BusConnection() {
47 if (object_)
48 ::dbus_g_connection_unref(object_);
49 }
50
51 BusConnection& operator=(BusConnection x) {
52 swap(*this, x);
53 return *this;
54 }
55
g_connection()56 const value_type& g_connection() const {
57 DCHECK(object_) << "referencing an empty connection";
58 return object_;
59 }
60
61 operator bool() const { return object_; }
62
HasConnection()63 bool HasConnection() const { return object_; }
64
65 private:
66 friend void swap(BusConnection& x, BusConnection& y);
67
68 friend class Proxy;
69 friend BusConnection GetSystemBusConnection();
70 friend BusConnection GetPrivateBusConnection(const char* address);
71
72 // Constructor takes ownership
BusConnection(::DBusGConnection * x)73 BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {}
74
75 value_type object_;
76 };
77
swap(BusConnection & x,BusConnection & y)78 inline void swap(BusConnection& x, BusConnection& y) {
79 std::swap(x.object_, y.object_);
80 }
81
82 // \brief Proxy manages the ref-count for a ::DBusGProxy*.
83 //
84 // Proxy has reference semantics and represents a connection to on object on
85 // the bus. A proxy object is constructed with a connection to a bus, a name
86 // to an entity on the bus, a path to an object owned by the entity, and an
87 // interface protocol name used to communicate with the object.
88
89 class BRILLO_EXPORT Proxy {
90 public:
91 typedef ::DBusGProxy* value_type;
92
93 Proxy();
94
95 // Set |connect_to_name_owner| true if you'd like to use
96 // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
97 Proxy(const BusConnection& connection,
98 const char* name,
99 const char* path,
100 const char* interface,
101 bool connect_to_name_owner);
102
103 // Equivalent to Proxy(connection, name, path, interface, false).
104 Proxy(const BusConnection& connection,
105 const char* name,
106 const char* path,
107 const char* interface);
108
109 // Creates a peer proxy using dbus_g_proxy_new_for_peer.
110 Proxy(const BusConnection& connection,
111 const char* path,
112 const char* interface);
113
114 Proxy(const Proxy& x);
115
116 ~Proxy();
117
118 Proxy& operator=(Proxy x) {
119 swap(*this, x);
120 return *this;
121 }
122
path()123 const char* path() const {
124 DCHECK(object_) << "referencing an empty proxy";
125 return ::dbus_g_proxy_get_path(object_);
126 }
127
128 // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
129 // library evolves, the gproxy() will be moved to be private.
130
gproxy()131 const value_type& gproxy() const {
132 DCHECK(object_) << "referencing an empty proxy";
133 return object_;
134 }
135
136 operator bool() const { return object_; }
137
138 private:
139 BRILLO_PRIVATE static value_type GetGProxy(const BusConnection& connection,
140 const char* name,
141 const char* path,
142 const char* interface,
143 bool connect_to_name_owner);
144
145 BRILLO_PRIVATE static value_type GetGPeerProxy(
146 const BusConnection& connection,
147 const char* path,
148 const char* interface);
149
150 BRILLO_PRIVATE operator int() const; // for safe bool cast
151 friend void swap(Proxy& x, Proxy& y);
152
153 value_type object_;
154 };
155
swap(Proxy & x,Proxy & y)156 inline void swap(Proxy& x, Proxy& y) {
157 std::swap(x.object_, y.object_);
158 }
159
160 // \brief RegisterExclusiveService configures a GObject to run as a service on
161 // a supplied ::BusConnection.
162 //
163 // RegisterExclusiveService encapsulates the process of configuring the
164 // supplied \param object at \param service_path on the \param connection.
165 // Exclusivity is ensured by replacing any existing services at that named
166 // location and confirming that the connection is the primary owner.
167 //
168 // Type information for the \param object must be installed with
169 // dbus_g_object_type_install_info prior to use.
170
171 BRILLO_EXPORT bool RegisterExclusiveService(const BusConnection& connection,
172 const char* interface_name,
173 const char* service_name,
174 const char* service_path,
175 GObject* object);
176
177 template<typename F> // F is a function signature
178 class MonitorConnection;
179
180 template<typename A1>
181 class MonitorConnection<void(A1)> {
182 public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1),void * object)183 MonitorConnection(const Proxy& proxy,
184 const char* name,
185 void (*monitor)(void*, A1),
186 void* object)
187 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
188
Run(::DBusGProxy *,A1 x,MonitorConnection * self)189 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
190 self->monitor_(self->object_, x);
191 }
proxy()192 const Proxy& proxy() const { return proxy_; }
name()193 const std::string& name() const { return name_; }
194
195 private:
196 Proxy proxy_;
197 std::string name_;
198 void (*monitor_)(void*, A1);
199 void* object_;
200 };
201
202 template<typename A1, typename A2>
203 class MonitorConnection<void(A1, A2)> {
204 public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2),void * object)205 MonitorConnection(const Proxy& proxy,
206 const char* name,
207 void (*monitor)(void*, A1, A2),
208 void* object)
209 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
210
Run(::DBusGProxy *,A1 x,A2 y,MonitorConnection * self)211 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
212 self->monitor_(self->object_, x, y);
213 }
proxy()214 const Proxy& proxy() const { return proxy_; }
name()215 const std::string& name() const { return name_; }
216
217 private:
218 Proxy proxy_;
219 std::string name_;
220 void (*monitor_)(void*, A1, A2);
221 void* object_;
222 };
223
224 template<typename A1, typename A2, typename A3>
225 class MonitorConnection<void(A1, A2, A3)> {
226 public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3),void * object)227 MonitorConnection(const Proxy& proxy,
228 const char* name,
229 void (*monitor)(void*, A1, A2, A3),
230 void* object)
231 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
232
Run(::DBusGProxy *,A1 x,A2 y,A3 z,MonitorConnection * self)233 static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
234 self->monitor_(self->object_, x, y, z);
235 }
proxy()236 const Proxy& proxy() const { return proxy_; }
name()237 const std::string& name() const { return name_; }
238
239 private:
240 Proxy proxy_;
241 std::string name_;
242 void (*monitor_)(void*, A1, A2, A3);
243 void* object_;
244 };
245
246 template<typename A1, typename A2, typename A3, typename A4>
247 class MonitorConnection<void(A1, A2, A3, A4)> {
248 public:
MonitorConnection(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3,A4),void * object)249 MonitorConnection(const Proxy& proxy,
250 const char* name,
251 void (*monitor)(void*, A1, A2, A3, A4),
252 void* object)
253 : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
254
Run(::DBusGProxy *,A1 x,A2 y,A3 z,A4 w,MonitorConnection * self)255 static void Run(::DBusGProxy*,
256 A1 x,
257 A2 y,
258 A3 z,
259 A4 w,
260 MonitorConnection* self) {
261 self->monitor_(self->object_, x, y, z, w);
262 }
proxy()263 const Proxy& proxy() const { return proxy_; }
name()264 const std::string& name() const { return name_; }
265
266 private:
267 Proxy proxy_;
268 std::string name_;
269 void (*monitor_)(void*, A1, A2, A3, A4);
270 void* object_;
271 };
272
273 template<typename A1>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1),void * object)274 MonitorConnection<void(A1)>* Monitor(const Proxy& proxy,
275 const char* name,
276 void (*monitor)(void*, A1),
277 void* object) {
278 typedef MonitorConnection<void(A1)> ConnectionType;
279
280 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
281
282 ::dbus_g_proxy_add_signal(
283 proxy.gproxy(), name, glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
284 ::dbus_g_proxy_connect_signal(
285 proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
286 return result;
287 }
288
289 template<typename A1, typename A2>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2),void * object)290 MonitorConnection<void(A1, A2)>* Monitor(const Proxy& proxy,
291 const char* name,
292 void (*monitor)(void*, A1, A2),
293 void* object) {
294 typedef MonitorConnection<void(A1, A2)> ConnectionType;
295
296 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
297
298 ::dbus_g_proxy_add_signal(proxy.gproxy(),
299 name,
300 glib::type_to_gtypeid<A1>(),
301 glib::type_to_gtypeid<A2>(),
302 G_TYPE_INVALID);
303 ::dbus_g_proxy_connect_signal(
304 proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
305 return result;
306 }
307
308 template<typename A1, typename A2, typename A3>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3),void * object)309 MonitorConnection<void(A1, A2, A3)>* Monitor(const Proxy& proxy,
310 const char* name,
311 void (*monitor)(void*, A1, A2, A3),
312 void* object) {
313 typedef MonitorConnection<void(A1, A2, A3)> ConnectionType;
314
315 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
316
317 ::dbus_g_proxy_add_signal(proxy.gproxy(),
318 name,
319 glib::type_to_gtypeid<A1>(),
320 glib::type_to_gtypeid<A2>(),
321 glib::type_to_gtypeid<A3>(),
322 G_TYPE_INVALID);
323 ::dbus_g_proxy_connect_signal(
324 proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
325 return result;
326 }
327
328 template<typename A1, typename A2, typename A3, typename A4>
Monitor(const Proxy & proxy,const char * name,void (* monitor)(void *,A1,A2,A3,A4),void * object)329 MonitorConnection<void(A1, A2, A3, A4)>* Monitor(
330 const Proxy& proxy,
331 const char* name,
332 void (*monitor)(void*, A1, A2, A3, A4),
333 void* object) {
334 typedef MonitorConnection<void(A1, A2, A3, A4)> ConnectionType;
335
336 ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
337
338 ::dbus_g_proxy_add_signal(proxy.gproxy(),
339 name,
340 glib::type_to_gtypeid<A1>(),
341 glib::type_to_gtypeid<A2>(),
342 glib::type_to_gtypeid<A3>(),
343 glib::type_to_gtypeid<A4>(),
344 G_TYPE_INVALID);
345 ::dbus_g_proxy_connect_signal(
346 proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
347 return result;
348 }
349
350 template<typename F>
Disconnect(MonitorConnection<F> * connection)351 void Disconnect(MonitorConnection<F>* connection) {
352 typedef MonitorConnection<F> ConnectionType;
353
354 ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
355 connection->name().c_str(),
356 G_CALLBACK(&ConnectionType::Run),
357 connection);
358 delete connection;
359 }
360
361 // \brief call_PtrArray() invokes a method on a proxy returning a
362 // glib::PtrArray.
363 //
364 // CallPtrArray is the first instance of what is likely to be a general
365 // way to make method calls to a proxy. It will likely be replaced with
366 // something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
367 // future. However, I don't yet have enough cases to generalize from.
368
369 BRILLO_EXPORT bool CallPtrArray(const Proxy& proxy,
370 const char* method,
371 glib::ScopedPtrArray<const char*>* result);
372
373 // \brief RetrieveProperty() retrieves a property of an object associated with a
374 // proxy.
375 //
376 // Given a proxy to an object supporting the org.freedesktop.DBus.Properties
377 // interface, the RetrieveProperty() call will retrieve a property of the
378 // specified interface on the object storing it in \param result and returning
379 // \true. If the dbus call fails or the object returned is not of type \param T,
380 // then \false is returned and \param result is unchanged.
381 //
382 // \example
383 // Proxy proxy(GetSystemBusConnection(),
384 // "org.freedesktop.DeviceKit.Power", // A named entity on the bus
385 // battery_name, // Path to a battery on the bus
386 // "org.freedesktop.DBus.Properties") // Properties interface
387 //
388 // double x;
389 // if (RetrieveProperty(proxy,
390 // "org.freedesktop.DeviceKit.Power.Device",
391 // "percentage")
392 // std::cout << "Battery charge is " << x << "% of capacity.";
393 // \end_example
394
395 template<typename T>
RetrieveProperty(const Proxy & proxy,const char * interface,const char * property,T * result)396 inline bool RetrieveProperty(const Proxy& proxy,
397 const char* interface,
398 const char* property,
399 T* result) {
400 glib::ScopedError error;
401 glib::Value value;
402
403 if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
404 G_TYPE_STRING, interface,
405 G_TYPE_STRING, property,
406 G_TYPE_INVALID,
407 G_TYPE_VALUE, &value,
408 G_TYPE_INVALID)) {
409 LOG(ERROR) << "Getting property failed: "
410 << (error->message ? error->message : "Unknown Error.");
411 return false;
412 }
413 return glib::Retrieve(value, result);
414 }
415
416 // \brief RetrieveProperties returns a HashTable of all properties for the
417 // specified interface.
418
419 BRILLO_EXPORT bool RetrieveProperties(const Proxy& proxy,
420 const char* interface,
421 glib::ScopedHashTable* result);
422
423 // \brief Returns a connection to the system bus.
424
425 BRILLO_EXPORT BusConnection GetSystemBusConnection();
426
427 // \brief Returns a private connection to a bus at |address|.
428
429 BRILLO_EXPORT BusConnection GetPrivateBusConnection(const char* address);
430
431 // \brief Calls a method |method_name| with no arguments per the given |path|
432 // and |interface_name|. Ignores return value.
433
434 BRILLO_EXPORT void CallMethodWithNoArguments(const char* service_name,
435 const char* path,
436 const char* interface_name,
437 const char* method_name);
438
439 // \brief Low-level signal monitor base class.
440 //
441 // Used when there is no definite named signal sender (that Proxy
442 // could be used for).
443
444 class BRILLO_EXPORT SignalWatcher {
445 public:
SignalWatcher()446 SignalWatcher() {}
447 ~SignalWatcher();
448 void StartMonitoring(const std::string& interface, const std::string& signal);
449
450 private:
451 // Callback invoked on the given signal arrival.
452 virtual void OnSignal(DBusMessage* message) = 0;
453
454 // Returns a string matching the D-Bus messages that we want to listen for.
455 BRILLO_PRIVATE std::string GetDBusMatchString() const;
456
457 // A D-Bus message filter to receive signals.
458 BRILLO_PRIVATE static DBusHandlerResult FilterDBusMessage(
459 DBusConnection* dbus_conn,
460 DBusMessage* message,
461 void* data);
462 std::string interface_;
463 std::string signal_;
464 };
465
466 } // namespace dbus
467 } // namespace brillo
468
469 #endif // LIBBRILLO_BRILLO_GLIB_DBUS_H_
470