• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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