| // 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 LIBCHROMEOS_CHROMEOS_GLIB_DBUS_H_ |
| #define LIBCHROMEOS_CHROMEOS_GLIB_DBUS_H_ |
| |
| #include <dbus/dbus-glib.h> |
| #include <glib-object.h> |
| |
| #include <algorithm> |
| #include <string> |
| |
| #include "base/logging.h" |
| #include <chromeos/chromeos_export.h> |
| #include <chromeos/glib/object.h> |
| |
| struct DBusMessage; |
| struct DBusConnection; |
| |
| namespace chromeos { |
| |
| // \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 CHROMEOS_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 |
| CHROMEOS_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 CHROMEOS_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: |
| CHROMEOS_PRIVATE static value_type GetGProxy(const BusConnection& connection, |
| const char* name, |
| const char* path, |
| const char* interface, |
| bool connect_to_name_owner); |
| |
| CHROMEOS_PRIVATE static value_type GetGPeerProxy( |
| const BusConnection& connection, |
| const char* path, |
| const char* interface); |
| |
| CHROMEOS_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. |
| |
| CHROMEOS_EXPORT bool RegisterExclusiveService(const BusConnection& connection, |
| const char* interface_name, |
| const char* service_name, |
| const char* service_path, |
| GObject* object); |
| |
| template<typename F> // F is a function signature |
| class MonitorConnection; |
| |
| template<typename A1> |
| class MonitorConnection<void(A1)> { |
| 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<typename A1, typename A2> |
| class MonitorConnection<void(A1, A2)> { |
| 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<typename A1, typename A2, typename A3> |
| class MonitorConnection<void(A1, A2, A3)> { |
| 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<typename A1, typename A2, typename A3, typename A4> |
| class MonitorConnection<void(A1, A2, A3, A4)> { |
| 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<typename A1> |
| MonitorConnection<void(A1)>* Monitor(const Proxy& proxy, |
| const char* name, |
| void (*monitor)(void*, A1), |
| void* object) { |
| typedef MonitorConnection<void(A1)> ConnectionType; |
| |
| ConnectionType* result = new ConnectionType(proxy, name, monitor, object); |
| |
| ::dbus_g_proxy_add_signal( |
| proxy.gproxy(), name, glib::type_to_gtypeid<A1>(), G_TYPE_INVALID); |
| ::dbus_g_proxy_connect_signal( |
| proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); |
| return result; |
| } |
| |
| template<typename A1, typename A2> |
| MonitorConnection<void(A1, A2)>* Monitor(const Proxy& proxy, |
| const char* name, |
| void (*monitor)(void*, A1, A2), |
| void* object) { |
| typedef MonitorConnection<void(A1, A2)> ConnectionType; |
| |
| ConnectionType* result = new ConnectionType(proxy, name, monitor, object); |
| |
| ::dbus_g_proxy_add_signal(proxy.gproxy(), |
| name, |
| glib::type_to_gtypeid<A1>(), |
| glib::type_to_gtypeid<A2>(), |
| G_TYPE_INVALID); |
| ::dbus_g_proxy_connect_signal( |
| proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); |
| return result; |
| } |
| |
| template<typename A1, typename A2, typename A3> |
| MonitorConnection<void(A1, A2, A3)>* Monitor(const Proxy& proxy, |
| const char* name, |
| void (*monitor)(void*, A1, A2, A3), |
| void* object) { |
| typedef MonitorConnection<void(A1, A2, A3)> ConnectionType; |
| |
| ConnectionType* result = new ConnectionType(proxy, name, monitor, object); |
| |
| ::dbus_g_proxy_add_signal(proxy.gproxy(), |
| name, |
| glib::type_to_gtypeid<A1>(), |
| glib::type_to_gtypeid<A2>(), |
| glib::type_to_gtypeid<A3>(), |
| G_TYPE_INVALID); |
| ::dbus_g_proxy_connect_signal( |
| proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); |
| return result; |
| } |
| |
| template<typename A1, typename A2, typename A3, typename A4> |
| MonitorConnection<void(A1, A2, A3, A4)>* Monitor( |
| const Proxy& proxy, |
| const char* name, |
| void (*monitor)(void*, A1, A2, A3, A4), |
| void* object) { |
| typedef MonitorConnection<void(A1, A2, A3, A4)> ConnectionType; |
| |
| ConnectionType* result = new ConnectionType(proxy, name, monitor, object); |
| |
| ::dbus_g_proxy_add_signal(proxy.gproxy(), |
| name, |
| glib::type_to_gtypeid<A1>(), |
| glib::type_to_gtypeid<A2>(), |
| glib::type_to_gtypeid<A3>(), |
| glib::type_to_gtypeid<A4>(), |
| G_TYPE_INVALID); |
| ::dbus_g_proxy_connect_signal( |
| proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr); |
| return result; |
| } |
| |
| template<typename F> |
| void Disconnect(MonitorConnection<F>* connection) { |
| typedef MonitorConnection<F> 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. |
| |
| CHROMEOS_EXPORT bool CallPtrArray(const Proxy& proxy, |
| const char* method, |
| glib::ScopedPtrArray<const char*>* 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<typename T> |
| 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. |
| |
| CHROMEOS_EXPORT bool RetrieveProperties(const Proxy& proxy, |
| const char* interface, |
| glib::ScopedHashTable* result); |
| |
| // \brief Returns a connection to the system bus. |
| |
| CHROMEOS_EXPORT BusConnection GetSystemBusConnection(); |
| |
| // \brief Returns a private connection to a bus at |address|. |
| |
| CHROMEOS_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. |
| |
| CHROMEOS_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 CHROMEOS_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. |
| CHROMEOS_PRIVATE std::string GetDBusMatchString() const; |
| |
| // A D-Bus message filter to receive signals. |
| CHROMEOS_PRIVATE static DBusHandlerResult FilterDBusMessage( |
| DBusConnection* dbus_conn, |
| DBusMessage* message, |
| void* data); |
| std::string interface_; |
| std::string signal_; |
| }; |
| |
| } // namespace dbus |
| } // namespace chromeos |
| |
| #endif // LIBCHROMEOS_CHROMEOS_GLIB_DBUS_H_ |