Implements DBus Utility for WRT
authorWonYoung Choi <wy80.choi@samsung.com>
Fri, 17 Apr 2015 06:17:48 +0000 (15:17 +0900)
committerWonYoung Choi <wy80.choi@samsung.com>
Mon, 20 Apr 2015 07:19:33 +0000 (16:19 +0900)
Change-Id: I217dc2dc2d238a9d4cdf224a1bf0bd2898b18e00

src/common/dbus_client.cc [new file with mode: 0644]
src/common/dbus_client.h [new file with mode: 0644]
src/common/dbus_server.cc [new file with mode: 0644]
src/common/dbus_server.h [new file with mode: 0644]

diff --git a/src/common/dbus_client.cc b/src/common/dbus_client.cc
new file mode 100644 (file)
index 0000000..1262739
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "common/dbus_client.h"
+
+#include "common/logger.h"
+
+namespace wrt {
+
+DBusClient::DBusClient()
+    : connection_(NULL) {
+}
+
+DBusClient::~DBusClient() {
+  if (connection_) {
+    g_dbus_connection_close_sync(connection_, NULL, NULL);
+  }
+}
+
+bool DBusClient::ConnectByName(const std::string& name) {
+  std::string address("unix:path=");
+  address.append(g_get_user_runtime_dir());
+  address.append("/.");
+  address.append(name);
+  return Connect(address);
+}
+
+bool DBusClient::Connect(const std::string& address) {
+  GError *err = NULL;
+  connection_ = g_dbus_connection_new_for_address_sync(
+      address.c_str(),
+      G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+      NULL, NULL, &err);
+  if (!connection_) {
+    LoggerE("Failed to connect to bus address %s : %s",
+           address.c_str(), err->message);
+    g_error_free(err);
+    return false;
+  }
+  return true;
+}
+
+GVariant* DBusClient::CallSync(const std::string& iface,
+                               const std::string& method,
+                               GVariant* parameters,
+                               const GVariantType* reply_type) {
+  if (!connection_) {
+    return NULL;
+  }
+
+  GError *err = NULL;
+  GVariant* reply = g_dbus_connection_call_sync(
+      connection_, NULL, "/", iface.c_str(), method.c_str(), parameters,
+      reply_type, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+  if (!reply) {
+    LoggerE("Failed to CallSync : %s", err->message);
+    g_error_free(err);
+  }
+  return reply;
+}
+
+}  // namespace wrt
diff --git a/src/common/dbus_client.h b/src/common/dbus_client.h
new file mode 100644 (file)
index 0000000..fbea099
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_COMMON_DBUS_CLIENT_H_
+#define WRT_COMMON_DBUS_CLIENT_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
+namespace wrt {
+
+class DBusClient {
+ public:
+  DBusClient();
+  virtual ~DBusClient();
+
+  bool Connect(const std::string& address);
+  bool ConnectByName(const std::string& name);
+
+  GVariant* CallSync(const std::string& iface, const std::string& method,
+                     GVariant* parameters, const GVariantType* reply_type);
+ private:
+  GDBusConnection* connection_;
+};
+
+}  // namespace wrt
+
+#endif  // WRT_COMMON_DBUS_CLIENT_H_
diff --git a/src/common/dbus_server.cc b/src/common/dbus_server.cc
new file mode 100644 (file)
index 0000000..c204862
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "common/dbus_server.h"
+
+#include "common/logger.h"
+
+namespace wrt {
+
+namespace {
+
+static void OnMethodCall(GDBusConnection* /*connection*/,
+                         const gchar* /*sender*/,
+                         const gchar* /*object_path*/,
+                         const gchar* interface_name,
+                         const gchar* method_name,
+                         GVariant* parameters,
+                         GDBusMethodInvocation* invocation,
+                         gpointer user_data) {
+  DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
+  if (!self) {
+    LoggerE("DBusServer is NULL.");
+    return;
+  }
+  auto callback = self->GetMethodCallback(interface_name);
+  if (callback) {
+    callback(method_name, parameters, invocation);
+  }
+}
+
+static GVariant* OnGetProperty(GDBusConnection* /*connection*/,
+                               const gchar* /*sender*/,
+                               const gchar* /*object_path*/,
+                               const gchar* interface_name,
+                               const gchar* property_name,
+                               GError** error,
+                               gpointer user_data) {
+  DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
+  if (!self) {
+    LoggerE("DBusServer is NULL.");
+    return NULL;
+  }
+
+  auto callback =
+      self->GetPropertyGetter(interface_name);
+
+  GVariant* ret = NULL;
+  if (callback) {
+    ret = callback(property_name);
+  }
+
+  return ret;
+}
+
+static gboolean OnSetProperty(GDBusConnection* /*connection*/,
+                              const gchar* /*sender*/,
+                              const gchar* /*object_path*/,
+                              const gchar* interface_name,
+                              const gchar* property_name,
+                              GVariant* value,
+                              GError** error,
+                              gpointer user_data) {
+  DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
+  if (!self) {
+    LoggerE("DBusServer is NULL.");
+    return FALSE;
+  }
+
+  auto callback =
+      self->GetPropertySetter(interface_name);
+
+  gboolean ret = FALSE;
+  if (callback) {
+    if (callback(property_name, value)) {
+      ret = TRUE;
+    }
+  }
+
+  return ret;
+}
+
+static const GDBusInterfaceVTable kInterfaceVTable = {
+  OnMethodCall,
+  OnGetProperty,
+  OnSetProperty
+};
+
+static void OnClosedConnection(GDBusConnection* connection,
+                               gboolean /*remote_peer_vanished*/,
+                               GError* /*error*/,
+                               gpointer user_data) {
+  g_signal_handlers_disconnect_by_func(connection,
+                                       (gpointer)OnClosedConnection,
+                                       user_data);
+  g_object_unref(connection);
+}
+
+static gboolean OnClientRequest(GDBusServer* /*dbus_server*/,
+                                GDBusConnection* connection,
+                                gpointer user_data) {
+  GError* err = NULL;
+  DBusServer* self = reinterpret_cast<DBusServer*>(user_data);
+
+  g_signal_connect(connection, "closed",
+                   G_CALLBACK(OnClosedConnection), self);
+
+  if (self) {
+    // Check Peer Credentials
+    DBusServer::PeerCredentialsCallback callback =
+        self->GetPeerCredentialsCallback();
+    if (callback && !callback(
+        g_dbus_connection_get_peer_credentials(connection))) {
+      LoggerW("Invalid peer credentials");
+      g_dbus_connection_close_sync(connection, NULL, NULL);
+    }
+
+    GDBusNodeInfo* node_info = self->GetIntrospectionNodeInfo();
+    if (!node_info) {
+      LoggerE("Introspection is not set.");
+      return TRUE;
+    }
+
+    // TODO(wy80.choi): register multiple interfaces
+    g_object_ref(connection);
+    guint reg_id = g_dbus_connection_register_object(
+                          connection,
+                          "/",
+                          node_info->interfaces[0],
+                          &kInterfaceVTable,
+                          self,
+                          NULL,
+                          &err);
+    if (reg_id == 0) {
+      LoggerE("Failed to register object : %s", err->message);
+      g_error_free(err);
+    }
+  }
+  return TRUE;
+}
+
+}  // namespace
+
+DBusServer::DBusServer()
+    : server_(NULL),
+      node_info_(NULL) {
+}
+
+DBusServer::~DBusServer() {
+  if (node_info_) {
+    g_dbus_node_info_unref(node_info_);
+  }
+
+  if (server_) {
+    g_object_unref(server_);
+  }
+}
+
+void DBusServer::Start(const std::string& name) {
+  GError* err = NULL;
+
+  std::string address(g_get_user_runtime_dir());
+  address.append("/.");
+  address.append(name);
+
+  // unlink existing bus address
+  unlink(address.c_str());
+  address = "unix:path=" + address;
+
+  // create new bus
+  gchar* guid = g_dbus_generate_guid();
+  server_ = g_dbus_server_new_sync(
+                  address.c_str(), G_DBUS_SERVER_FLAGS_NONE,
+                  guid, NULL, NULL, &err);
+  g_free(guid);
+  if (!server_) {
+    LoggerE("Failed to create dbus server : %s", err->message);
+    g_error_free(err);
+    return;
+  }
+
+  // start server
+  g_signal_connect(server_, "new-connection",
+                   G_CALLBACK(OnClientRequest), this);
+
+  g_dbus_server_start(server_);
+}
+
+std::string DBusServer::GetClientAddress() const {
+  return std::string(g_dbus_server_get_client_address(server_));
+}
+
+void DBusServer::SetIntrospectionXML(const std::string& xml) {
+  GError* err = NULL;
+  node_info_ = g_dbus_node_info_new_for_xml(xml.c_str(), &err);
+  if (!node_info_) {
+    LoggerE("Failed to create node info from introspection xml : %s",
+            err->message);
+    g_error_free(err);
+  }
+}
+
+void DBusServer::SetPeerCredentialsCallback(PeerCredentialsCallback func) {
+  peer_credentials_callback_ = func;
+}
+
+void DBusServer::SetMethodCallback(
+    const std::string& iface, MethodCallback func) {
+  method_callbacks_[iface] = func;
+}
+
+void DBusServer::SetPropertyGetter(
+    const std::string& iface, PropertyGetter func) {
+  property_getters_[iface] = func;
+}
+
+void DBusServer::SetPropertySetter(
+    const std::string& iface, PropertySetter func) {
+  property_setters_[iface] = func;
+}
+
+DBusServer::PeerCredentialsCallback DBusServer::GetPeerCredentialsCallback() const {
+  return peer_credentials_callback_;
+}
+
+DBusServer::MethodCallback DBusServer::GetMethodCallback(const std::string& iface) {
+  return method_callbacks_[iface];
+}
+
+DBusServer::PropertySetter DBusServer::GetPropertySetter(const std::string& iface) {
+  return property_setters_[iface];
+}
+
+DBusServer::PropertyGetter DBusServer::GetPropertyGetter(const std::string& iface) {
+  return property_getters_[iface];
+}
+
+}  // namespace wrt
diff --git a/src/common/dbus_server.h b/src/common/dbus_server.h
new file mode 100644 (file)
index 0000000..41451fe
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WRT_COMMON_DBUS_SERVER_H_
+#define WRT_COMMON_DBUS_SERVER_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string>
+#include <map>
+#include <functional>
+
+namespace wrt {
+
+class DBusServer {
+ public:
+  typedef std::function<bool(GCredentials* creds)> PeerCredentialsCallback;
+  typedef std::function<void(const std::string& method_name,
+                             GVariant* parameters,
+                             GDBusMethodInvocation* invocation)> MethodCallback;
+  typedef std::function<GVariant*(const gchar*)> PropertyGetter;
+  typedef std::function<bool(const gchar*, GVariant*)> PropertySetter;
+
+  explicit DBusServer();
+  virtual ~DBusServer();
+
+  void Start(const std::string& name);
+
+  std::string GetClientAddress() const;
+
+  void SetIntrospectionXML(const std::string& xml);
+  GDBusNodeInfo* GetIntrospectionNodeInfo() const { return node_info_; }
+
+  void SetPeerCredentialsCallback(PeerCredentialsCallback func);
+  void SetMethodCallback(const std::string& iface, MethodCallback func);
+  void SetPropertyGetter(const std::string& iface, PropertyGetter func);
+  void SetPropertySetter(const std::string& iface, PropertySetter func);
+  PeerCredentialsCallback GetPeerCredentialsCallback() const;
+  MethodCallback GetMethodCallback(const std::string& iface);
+  PropertySetter GetPropertySetter(const std::string& iface);
+  PropertyGetter GetPropertyGetter(const std::string& iface);
+ private:
+  GDBusServer* server_;
+  GDBusNodeInfo* node_info_;
+
+  PeerCredentialsCallback peer_credentials_callback_;
+  std::map<std::string, MethodCallback> method_callbacks_;
+  std::map<std::string, PropertyGetter> property_getters_;
+  std::map<std::string, PropertySetter> property_setters_;
+};
+
+}  // namespace wrt
+
+#endif  // WRT_COMMON_DBUS_SERVER_H_