Add initial gdbus code
authorJiwan Kim <ji-wan.kim@samsung.com>
Wed, 24 May 2017 12:28:23 +0000 (21:28 +0900)
committersaerome.kim <saerome.kim@samsung.com>
Mon, 17 Jul 2017 02:35:36 +0000 (11:35 +0900)
include/mesh-gdbus.h [new file with mode: 0644]
include/mesh.h
src/mesh-gdbus.c [new file with mode: 0644]

diff --git a/include/mesh-gdbus.h b/include/mesh-gdbus.h
new file mode 100644 (file)
index 0000000..7579975
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MESH_GDBUS_H__
+#define __MESH_GDBUS_H__
+
+#include "mesh.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* DBus object paths of connman */
+#define CONNMAN_SERVER_NAME "net.connman"
+#define CONNMAN_OBJECT_PATH "/net/connman"
+#define CONNMAN_OBJECT_PATH_MESH "/net/connman/mesh"
+#define CONNMAN_OBJECT_PATH_TECH_MESH "/net/connman/technology/mesh"
+
+/* DBus interfaces of connman */
+#define CONNMAN_INTERFACE_MANAGER "net.connman.Manager"
+#define CONNMAN_INTERFACE_MESH "net.connman.Mesh"
+#define CONNMAN_INTERFACE_TECH "net.connman.Technology"
+
+#define MESH_DBUS_PROXY_TIMEOUT ((9.5 + 2) * 1000) /**< default timeout for GDBus */
+
+int meshd_dbus_start(mesh_service *service);
+int meshd_dbus_stop(mesh_service *service);
+
+int mesh_ipc_create_mesh_interface(mesh_service *service);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /** __MESH_GDBUS_H__ */
index f3816c4..b823982 100644 (file)
@@ -20,6 +20,7 @@
 #define __MESH_H__
 
 #include <glib.h>
+#include <gio/gio.h>
 #include <tizen.h>
 
 typedef enum {
@@ -28,8 +29,9 @@ typedef enum {
        MESHD_ERROR_NO_DATA, /**< Data not exists */
        MESHD_ERROR_OUT_OF_MEMORY, /**< out of memory */
        MESHD_ERROR_OPERATION_FAILED, /**< operation failed */
-       MESHD_ERROR_IN_PROGRESS, /**< operation is in progress */
-       MESHD_ERROR_INVALID_PARAMETER /**< Invalid parameters */
+       MESHD_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+       MESHD_ERROR_ALREADY_REGISTERED, /**< Request already registered */
+       MESHD_ERROR_IN_PROGRESS /**< operation is in progress */
 } meshd_error_e;
 
 /**< mesh interface information structure */
@@ -124,6 +126,10 @@ typedef struct _mesh_service {
        guint dbus_id; /**< D-Bus id */
        guint activation_dbus_id; /**< D-Bus id for activation */
 
+       gpointer connection; /**< Connection handle for D-Bus call to other process */
+       GCancellable *ca; /**< Cancellable object for D-Bus call (Daemon->other) */
+       GList *dbus_sub_ids; /**< The list of subscribed signals */
+
        mesh_interface_s *interface_info; /**< Name of network interfaces */
        gboolean mesh_activated; /**< Stored if mesh network is activated */
        GList *saved_mesh_network; /**< Saved mesh network list */
diff --git a/src/mesh-gdbus.c b/src/mesh-gdbus.c
new file mode 100644 (file)
index 0000000..1253fa7
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mesh-log.h"
+#include "mesh-util.h"
+#include "mesh-gdbus.h"
+
+static GDBusProxy *_gproxy_connman = NULL;
+static GDBusProxy *_gproxy_connman_mesh = NULL;
+static GDBusProxy *_gproxy_connman_technology = NULL;
+
+static int _meshd_close_gdbus_call(mesh_service *service);
+
+static GDBusProxy *_proxy_get_connman(mesh_service *service)
+{
+       GDBusProxy *proxy = NULL;
+       meshd_check_null_ret_error("service", service, NULL);
+
+       if (NULL == _gproxy_connman) {
+               proxy = g_dbus_proxy_new_sync(service->connection,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       CONNMAN_SERVER_NAME,
+                       CONNMAN_OBJECT_PATH,
+                       CONNMAN_INTERFACE_MANAGER,
+                       NULL, NULL);
+       } else
+               proxy = _gproxy_connman;
+
+       return proxy;
+}
+
+static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
+{
+       GDBusProxy *proxy = NULL;
+       meshd_check_null_ret_error("service", service, NULL);
+
+       if (NULL == _gproxy_connman_mesh) {
+               proxy = g_dbus_proxy_new_sync(service->connection,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       CONNMAN_SERVER_NAME,
+                       CONNMAN_OBJECT_PATH_MESH,
+                       CONNMAN_INTERFACE_MESH,
+                       NULL, NULL);
+       } else
+               proxy = _gproxy_connman_mesh;
+
+       return proxy;
+}
+
+static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
+{
+       GDBusProxy *proxy = NULL;
+       meshd_check_null_ret_error("service", service, NULL);
+
+       if (NULL == _gproxy_connman_technology) {
+               proxy = g_dbus_proxy_new_sync(service->connection,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       CONNMAN_SERVER_NAME,
+                       CONNMAN_OBJECT_PATH_TECH_MESH,
+                       CONNMAN_INTERFACE_TECH,
+                       NULL, NULL);
+       } else
+               proxy = _gproxy_connman_technology;
+
+       return proxy;
+}
+
+static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
+               gpointer *user_data)
+{
+       GDBusProxy *proxy = G_DBUS_PROXY(object);
+       gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
+       mesh_service *service = (mesh_service*)user_data;
+
+       NOTUSED(pspec);
+
+       if (NULL == name_owner) {
+               MESH_LOGE("name_owner is not exists !");
+               _meshd_close_gdbus_call(service);
+       }
+
+       g_free(name_owner);
+}
+
+static int _meshd_create_gdbus_call(mesh_service *service)
+{
+       int id;
+       GError *error = NULL;
+
+       if (NULL == service)
+               return MESHD_ERROR_INVALID_PARAMETER;
+
+       if (NULL != service->connection)
+               return MESHD_ERROR_ALREADY_REGISTERED;
+
+       service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (service->connection == NULL) {
+               if (error != NULL) {
+                       MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
+                       g_error_free(error);
+               }
+               return MESHD_ERROR_IO_ERROR;
+       }
+
+       id = g_signal_connect(service->connection, "notify::g-name-owner",
+                       G_CALLBACK(_dbus_name_owner_notify), service);
+       if (0 == id) {
+               LOGE("g_signal_connect() Fail");
+               g_object_unref(service->connection);
+               service->connection = NULL;
+               return MESHD_ERROR_IO_ERROR;
+       }
+
+       return MESHD_ERROR_NONE;
+}
+
+static int _meshd_close_gdbus_call(mesh_service *service)
+{
+       /* CHECK: is connection ref count required? */
+       g_object_unref(service->connection);
+       service->connection = NULL;
+
+       return MESHD_ERROR_NONE;
+}
+
+static void _meshd_signal_handler(GDBusConnection *connection,
+               const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
+               const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+       mesh_service *service = (mesh_service*)user_data;
+
+       meshd_check_null_ret("user_data", user_data);
+       //meshd_check_null_ret("event_handler", service->event_handler);
+       NOTUSED(connection);
+       NOTUSED(sender_name);
+       NOTUSED(object_path);
+       NOTUSED(interface_name);
+       NOTUSED(signal_name);
+       NOTUSED(parameters);
+
+       NOTUSED(service);
+
+       LOGD("signal received = %s", signal_name);
+       if (0 == g_strcmp0(signal_name, "scan_done")) {
+               /* TODO: Handle event */
+       }
+}
+
+static void _meshd_subscribe_event(mesh_service *service)
+{
+       unsigned int id;
+
+       id = g_dbus_connection_signal_subscribe(
+                       (GDBusConnection *)service->connection,
+                       CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
+                       "ScanDone", "/", NULL,
+                       G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
+       if (0 == id) {
+               LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
+               return;
+       }
+       service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
+       LOGD("[Signal subscribe] : ScanDone (%d)", id);
+
+       /* End of subscription */
+}
+
+int meshd_dbus_start(mesh_service *service)
+{
+       int rv;
+
+       rv = _meshd_create_gdbus_call(service);
+       if (MESHD_ERROR_NONE != rv)
+               return rv;
+
+       service->ca = g_cancellable_new();
+
+       /* Create all required proxies here */
+       _gproxy_connman = _proxy_get_connman(service);
+       meshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
+                               MESHD_ERROR_IO_ERROR);
+       g_dbus_proxy_set_default_timeout(
+                       G_DBUS_PROXY(_gproxy_connman), MESH_DBUS_PROXY_TIMEOUT);
+
+       _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
+       meshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
+                               MESHD_ERROR_IO_ERROR);
+       g_dbus_proxy_set_default_timeout(
+                       G_DBUS_PROXY(_gproxy_connman_mesh), MESH_DBUS_PROXY_TIMEOUT);
+
+       _gproxy_connman_technology = _proxy_get_connman_technology(service);
+       meshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
+                               MESHD_ERROR_IO_ERROR);
+       g_dbus_proxy_set_default_timeout(
+                       G_DBUS_PROXY(_gproxy_connman_technology), MESH_DBUS_PROXY_TIMEOUT);
+
+       /* Subscribe events */
+       _meshd_subscribe_event(service);
+
+       return MESHD_ERROR_NONE;
+}
+
+int meshd_dbus_stop(mesh_service *service)
+{
+       int rv;
+
+       if (NULL == service)
+               return MESHD_ERROR_INVALID_PARAMETER;
+
+       /* Unref all proxies here */
+       if (_gproxy_connman) {
+               g_object_unref(_gproxy_connman);
+               _gproxy_connman = NULL;
+       }
+       if (_gproxy_connman_mesh) {
+               g_object_unref(_gproxy_connman_mesh);
+               _gproxy_connman_mesh = NULL;
+       }
+       if (_gproxy_connman_technology) {
+               g_object_unref(_gproxy_connman_technology);
+               _gproxy_connman_technology = NULL;
+       }
+
+       g_cancellable_cancel(service->ca);
+       g_object_unref(service->ca);
+       service->ca = NULL;
+
+       rv = _meshd_close_gdbus_call(service);
+       return rv;
+}
+
+int mesh_ipc_create_mesh_interface(mesh_service *service)
+{
+       GVariant *variant = NULL;
+       GError *error = NULL;
+       GVariant *var_dict = NULL;
+       GVariantDict dict;
+
+       meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
+       meshd_check_null_ret_error("connection", service->connection,
+                       MESHD_ERROR_INVALID_PARAMETER);
+       meshd_check_null_ret_error("_gproxy_connman_technology",
+                       _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
+
+       g_variant_dict_init(&dict, NULL);
+       g_variant_dict_insert(&dict, "Ifname", "s", "mesh0");
+       g_variant_dict_insert(&dict, "ParentIfname", "s", "wlan0");
+       g_variant_dict_insert(&dict, "BridgeIfname", "s", "br0");
+       var_dict = g_variant_dict_end(&dict);
+
+       variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
+                               g_variant_new("sv", "MeshInterfaceAdd", var_dict),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL, &error);
+       if (variant) {
+               MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
+       } else if (error) {
+               LOGE("Failed DBus call [%s]", error->message);
+               g_error_free(error);
+               return MESHD_ERROR_IO_ERROR;
+       }
+
+       return MESHD_ERROR_NONE;
+}
+
+#if 0
+struct mesh_network_list_s {
+       int count;
+       GList *list;
+};
+struct mesh_network_list_s g_networks;
+
+static void _mesh_free_network(gpointer data)
+{
+       struct mesh_network_s *network = data;
+       if (network) g_free(network);
+       network = NULL;
+}
+
+static void _mesh_append_network(gpointer data)
+{
+       g_networks.list = g_list_append(g_networks.list, data);
+       g_networks.count++;
+       LOGE("%dth item added", g_networks.count);
+}
+
+static void _mesh_remove_networks()
+{
+       if (g_networks.list)
+               g_list_free_full(g_networks.list, _mesh_free_network);
+       g_networks.list = NULL;
+       g_networks.count = 0;
+}
+
+static int _mesh_get_scan_result(mesh_h handle)
+{
+       GVariant *variant = NULL;
+       unsigned int result;
+       GError *error = NULL;
+       struct mesh_handle *h = handle;
+
+       GVariantIter *iter = NULL;
+       GVariantIter *iter_row = NULL;
+
+       gchar *key;
+       GVariant *val;
+       gsize len = 0;
+
+       /* Clear previous scan results */
+       _mesh_remove_networks();
+
+       RETV_IF(NULL == h->dbus_connection, MESH_ITNL_ERR_IO_ERROR);
+       RETV_IF(NULL == _gproxy_mesh_service, MESH_ITNL_ERR_IO_ERROR);
+
+       variant = g_dbus_proxy_call_sync(_gproxy_mesh_service, "get_found_mesh_networks",
+                               NULL,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL, &error);
+       if (variant) {
+               g_variant_get(variant, "(aa{sv}u)", &iter, &result);
+               while (g_variant_iter_next(iter, "a{sv}", &iter_row)) {
+                       struct mesh_network_s *network_info =
+                               g_malloc0(sizeof(struct mesh_network_s));
+                       while (g_variant_iter_loop(iter_row, "{sv}", &key, &val)) {
+                               if (strcasecmp(key, "mesh_id") == 0)  {
+                                       const char *buf = g_variant_get_string(val, &len);
+                                       memcpy(network_info->meshid, buf, len);
+                                       //LOGD("meshid=%s", network_info->meshid);
+                               }
+                               else if (strcasecmp(key, "bssid") == 0)  {
+                                       const char *buf = g_variant_get_string(val, &len);
+                                       memcpy(network_info->bssid, buf, len);
+                                       //LOGD("bssid = %s", network_info->bssid);
+                               }
+                               else if (strcasecmp(key, "rssi") == 0)  {
+                                       network_info->rssi = g_variant_get_int32(val);
+                                       //LOGD("rssi = %d", network_info->rssi);
+                               }
+                               else if (strcasecmp(key, "channel") == 0)  {
+                                       network_info->channel = g_variant_get_uint32(val);
+                                       //LOGD("channel = %d", network_info->channel);
+
+                                       /* Last element */
+                                       _mesh_append_network(network_info);
+                               }
+                       }
+                       g_variant_iter_free(iter_row);
+               }
+               g_variant_iter_free(iter);
+
+       } else if (error) {
+               LOGE("Failed DBus call [%s]", error->message);
+               g_error_free(error);
+               return MESH_ITNL_ERR_IO_ERROR;
+       }
+
+       return MESH_ITNL_ERR_NONE;
+}
+#endif