// Copyright (c) 2009 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef LIBBRILLO_BRILLO_GLIB_DBUS_H_ #define LIBBRILLO_BRILLO_GLIB_DBUS_H_ #include #include #include #include #include "base/logging.h" #include #include struct DBusMessage; struct DBusConnection; namespace brillo { // \precondition No functions in the dbus namespace can be called before // ::g_type_init(); namespace dbus { // \brief BusConnection manages the ref-count for a ::DBusGConnection*. // // A BusConnection has reference semantics bound to a particular communication // bus. // // \models Copyable, Assignable // \related GetSystemBusConnection() class BRILLO_EXPORT BusConnection { public: typedef ::DBusGConnection* value_type; BusConnection(const BusConnection& x) : object_(x.object_) { if (object_) ::dbus_g_connection_ref(object_); } ~BusConnection() { if (object_) ::dbus_g_connection_unref(object_); } BusConnection& operator=(BusConnection x) { swap(*this, x); return *this; } const value_type& g_connection() const { DCHECK(object_) << "referencing an empty connection"; return object_; } operator bool() const { return object_; } bool HasConnection() const { return object_; } private: friend void swap(BusConnection& x, BusConnection& y); friend class Proxy; friend BusConnection GetSystemBusConnection(); friend BusConnection GetPrivateBusConnection(const char* address); // Constructor takes ownership BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {} value_type object_; }; inline void swap(BusConnection& x, BusConnection& y) { std::swap(x.object_, y.object_); } // \brief Proxy manages the ref-count for a ::DBusGProxy*. // // Proxy has reference semantics and represents a connection to on object on // the bus. A proxy object is constructed with a connection to a bus, a name // to an entity on the bus, a path to an object owned by the entity, and an // interface protocol name used to communicate with the object. class BRILLO_EXPORT Proxy { public: typedef ::DBusGProxy* value_type; Proxy(); // Set |connect_to_name_owner| true if you'd like to use // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name(). Proxy(const BusConnection& connection, const char* name, const char* path, const char* interface, bool connect_to_name_owner); // Equivalent to Proxy(connection, name, path, interface, false). Proxy(const BusConnection& connection, const char* name, const char* path, const char* interface); // Creates a peer proxy using dbus_g_proxy_new_for_peer. Proxy(const BusConnection& connection, const char* path, const char* interface); Proxy(const Proxy& x); ~Proxy(); Proxy& operator=(Proxy x) { swap(*this, x); return *this; } const char* path() const { DCHECK(object_) << "referencing an empty proxy"; return ::dbus_g_proxy_get_path(object_); } // gproxy() returns a reference to the underlying ::DBusGProxy*. As this // library evolves, the gproxy() will be moved to be private. const value_type& gproxy() const { DCHECK(object_) << "referencing an empty proxy"; return object_; } operator bool() const { return object_; } private: BRILLO_PRIVATE static value_type GetGProxy(const BusConnection& connection, const char* name, const char* path, const char* interface, bool connect_to_name_owner); BRILLO_PRIVATE static value_type GetGPeerProxy( const BusConnection& connection, const char* path, const char* interface); BRILLO_PRIVATE operator int() const; // for safe bool cast friend void swap(Proxy& x, Proxy& y); value_type object_; }; inline void swap(Proxy& x, Proxy& y) { std::swap(x.object_, y.object_); } // \brief RegisterExclusiveService configures a GObject to run as a service on // a supplied ::BusConnection. // // RegisterExclusiveService encapsulates the process of configuring the // supplied \param object at \param service_path on the \param connection. // Exclusivity is ensured by replacing any existing services at that named // location and confirming that the connection is the primary owner. // // Type information for the \param object must be installed with // dbus_g_object_type_install_info prior to use. BRILLO_EXPORT bool RegisterExclusiveService(const BusConnection& connection, const char* interface_name, const char* service_name, const char* service_path, GObject* object); template // F is a function signature class MonitorConnection; template class MonitorConnection { public: MonitorConnection(const Proxy& proxy, const char* name, void (*monitor)(void*, A1), void* object) : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {} static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) { self->monitor_(self->object_, x); } const Proxy& proxy() const { return proxy_; } const std::string& name() const { return name_; } private: Proxy proxy_; std::string name_; void (*monitor_)(void*, A1); void* object_; }; template class MonitorConnection { public: MonitorConnection(const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2), void* object) : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {} static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) { self->monitor_(self->object_, x, y); } const Proxy& proxy() const { return proxy_; } const std::string& name() const { return name_; } private: Proxy proxy_; std::string name_; void (*monitor_)(void*, A1, A2); void* object_; }; template class MonitorConnection { public: MonitorConnection(const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2, A3), void* object) : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {} static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) { self->monitor_(self->object_, x, y, z); } const Proxy& proxy() const { return proxy_; } const std::string& name() const { return name_; } private: Proxy proxy_; std::string name_; void (*monitor_)(void*, A1, A2, A3); void* object_; }; template class MonitorConnection { public: MonitorConnection(const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2, A3, A4), void* object) : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {} static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, A4 w, MonitorConnection* self) { self->monitor_(self->object_, x, y, z, w); } const Proxy& proxy() const { return proxy_; } const std::string& name() const { return name_; } private: Proxy proxy_; std::string name_; void (*monitor_)(void*, A1, A2, A3, A4); void* object_; }; template MonitorConnection* Monitor(const Proxy& proxy, const char* name, void (*monitor)(void*, A1), void* object) { typedef MonitorConnection ConnectionType; ConnectionType* result = new ConnectionType(proxy, name, monitor, object); ::dbus_g_proxy_add_signal( proxy.gproxy(), name, glib::type_to_gtypeid(), G_TYPE_INVALID); ::dbus_g_proxy_connect_signal( proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); return result; } template MonitorConnection* Monitor(const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2), void* object) { typedef MonitorConnection ConnectionType; ConnectionType* result = new ConnectionType(proxy, name, monitor, object); ::dbus_g_proxy_add_signal(proxy.gproxy(), name, glib::type_to_gtypeid(), glib::type_to_gtypeid(), G_TYPE_INVALID); ::dbus_g_proxy_connect_signal( proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); return result; } template MonitorConnection* Monitor(const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2, A3), void* object) { typedef MonitorConnection ConnectionType; ConnectionType* result = new ConnectionType(proxy, name, monitor, object); ::dbus_g_proxy_add_signal(proxy.gproxy(), name, glib::type_to_gtypeid(), glib::type_to_gtypeid(), glib::type_to_gtypeid(), G_TYPE_INVALID); ::dbus_g_proxy_connect_signal( proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); return result; } template MonitorConnection* Monitor( const Proxy& proxy, const char* name, void (*monitor)(void*, A1, A2, A3, A4), void* object) { typedef MonitorConnection ConnectionType; ConnectionType* result = new ConnectionType(proxy, name, monitor, object); ::dbus_g_proxy_add_signal(proxy.gproxy(), name, glib::type_to_gtypeid(), glib::type_to_gtypeid(), glib::type_to_gtypeid(), glib::type_to_gtypeid(), G_TYPE_INVALID); ::dbus_g_proxy_connect_signal( proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); return result; } template void Disconnect(MonitorConnection* connection) { typedef MonitorConnection ConnectionType; ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(), connection->name().c_str(), G_CALLBACK(&ConnectionType::Run), connection); delete connection; } // \brief call_PtrArray() invokes a method on a proxy returning a // glib::PtrArray. // // CallPtrArray is the first instance of what is likely to be a general // way to make method calls to a proxy. It will likely be replaced with // something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the // future. However, I don't yet have enough cases to generalize from. BRILLO_EXPORT bool CallPtrArray(const Proxy& proxy, const char* method, glib::ScopedPtrArray* result); // \brief RetrieveProperty() retrieves a property of an object associated with a // proxy. // // Given a proxy to an object supporting the org.freedesktop.DBus.Properties // interface, the RetrieveProperty() call will retrieve a property of the // specified interface on the object storing it in \param result and returning // \true. If the dbus call fails or the object returned is not of type \param T, // then \false is returned and \param result is unchanged. // // \example // Proxy proxy(GetSystemBusConnection(), // "org.freedesktop.DeviceKit.Power", // A named entity on the bus // battery_name, // Path to a battery on the bus // "org.freedesktop.DBus.Properties") // Properties interface // // double x; // if (RetrieveProperty(proxy, // "org.freedesktop.DeviceKit.Power.Device", // "percentage") // std::cout << "Battery charge is " << x << "% of capacity."; // \end_example template inline bool RetrieveProperty(const Proxy& proxy, const char* interface, const char* property, T* result) { glib::ScopedError error; glib::Value value; if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(), G_TYPE_STRING, interface, G_TYPE_STRING, property, G_TYPE_INVALID, G_TYPE_VALUE, &value, G_TYPE_INVALID)) { LOG(ERROR) << "Getting property failed: " << (error->message ? error->message : "Unknown Error."); return false; } return glib::Retrieve(value, result); } // \brief RetrieveProperties returns a HashTable of all properties for the // specified interface. BRILLO_EXPORT bool RetrieveProperties(const Proxy& proxy, const char* interface, glib::ScopedHashTable* result); // \brief Returns a connection to the system bus. BRILLO_EXPORT BusConnection GetSystemBusConnection(); // \brief Returns a private connection to a bus at |address|. BRILLO_EXPORT BusConnection GetPrivateBusConnection(const char* address); // \brief Calls a method |method_name| with no arguments per the given |path| // and |interface_name|. Ignores return value. BRILLO_EXPORT void CallMethodWithNoArguments(const char* service_name, const char* path, const char* interface_name, const char* method_name); // \brief Low-level signal monitor base class. // // Used when there is no definite named signal sender (that Proxy // could be used for). class BRILLO_EXPORT SignalWatcher { public: SignalWatcher() {} ~SignalWatcher(); void StartMonitoring(const std::string& interface, const std::string& signal); private: // Callback invoked on the given signal arrival. virtual void OnSignal(DBusMessage* message) = 0; // Returns a string matching the D-Bus messages that we want to listen for. BRILLO_PRIVATE std::string GetDBusMatchString() const; // A D-Bus message filter to receive signals. BRILLO_PRIVATE static DBusHandlerResult FilterDBusMessage( DBusConnection* dbus_conn, DBusMessage* message, void* data); std::string interface_; std::string signal_; }; } // namespace dbus } // namespace brillo #endif // LIBBRILLO_BRILLO_GLIB_DBUS_H_