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