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 40 BusConnection(const BusConnection& x) : object_(x.object_) { 41 if (object_) 42 ::dbus_g_connection_ref(object_); 43 } 44 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 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 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 72 BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {} 73 74 value_type object_; 75 }; 76 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 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 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 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: 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 188 static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) { 189 self->monitor_(self->object_, x); 190 } 191 const Proxy& proxy() const { return proxy_; } 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: 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 210 static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) { 211 self->monitor_(self->object_, x, y); 212 } 213 const Proxy& proxy() const { return proxy_; } 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: 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 232 static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) { 233 self->monitor_(self->object_, x, y, z); 234 } 235 const Proxy& proxy() const { return proxy_; } 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: 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 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 } 262 const Proxy& proxy() const { return proxy_; } 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> 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> 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> 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> 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> 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> 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: 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