Add network connection state
authorJiwan Kim <ji-wan.kim@samsung.com>
Thu, 8 Jun 2017 07:16:10 +0000 (16:16 +0900)
committersaerome.kim <saerome.kim@samsung.com>
Mon, 17 Jul 2017 02:35:36 +0000 (11:35 +0900)
- Remove 'joined_network / left_network' signal
- Add 'connection_state' signal
- Subscribe mesh profile property from connman
- Add connection state to 'get_joined_mesh_network'
  and 'get_found_mesh_networks'

include/mesh-request.h
include/mesh.h
introspection/mesh.xml
src/mesh-gdbus.c
src/mesh-request.c
src/mesh-service-interface.c

index 5afb019..466d304 100644 (file)
@@ -95,9 +95,11 @@ int mesh_request_unregister_event_handler();
 
 /* Notifications */
 void mesh_notify_scan_done();
-void mesh_notify_joined_network();
-void mesh_notify_left_network();
-void mesh_notify_mesh_connected(int result);
+//void mesh_notify_joined_network();
+//void mesh_notify_left_network();
+//void mesh_notify_mesh_connected(int result);
+void mesh_notify_connection_state(const char* mesh_id, const char* bssid,
+               int channel, meshd_connection_state_e state);
 void mesh_notify_station_joined(const char* bssid);
 void mesh_notify_station_left(const char* bssid);
 
index ce9ee33..06e45c3 100644 (file)
@@ -35,6 +35,14 @@ typedef enum {
        MESHD_ERROR_IN_PROGRESS /**< operation is in progress */
 } meshd_error_e;
 
+/**< Internal enum for connection state. It should be matched with API side */
+typedef enum {
+       MESHD_CONNECTION_STATE_DISCONNECTED = 0, /**< Disconnected state */
+       MESHD_CONNECTION_STATE_ASSOCIATION, /**< Association state */
+       MESHD_CONNECTION_STATE_CONFIGURATION, /**< Configuration state */
+       MESHD_CONNECTION_STATE_CONNECTED /**< Connected state */
+} meshd_connection_state_e;
+
 /**< mesh interface information structure */
 typedef struct {
        gchar *bridge_interface; /**< Bridge name between mesh and others */
@@ -53,6 +61,7 @@ typedef struct _mesh_network_info {
        char* bssid; /**< BSSID */
        int channel; /**< Channel */
        int security; /**< Security type */
+       meshd_connection_state_e state; /**< Connection state */
 } mesh_network_info_s;
 
 /**< Mesh network scan result structure */
@@ -64,6 +73,7 @@ typedef struct {
        gint rssi; /**< RSSI */
        gint channel; /**< Channel */
        gint data_rate; /**< Data rate */
+       meshd_connection_state_e state; /**< Connection state */
 } mesh_scan_result_s;
 
 /**< Mesh peer structure */
index 3ed8faf..604b6f0 100644 (file)
                        <arg type="i" name="result" direction="out"/>\r
                </method>\r
                <method name="get_joined_mesh_network">\r
-                       <arg type="s" name="meshid" direction="out"/>\r
+                       <arg type="s" name="mesh_id" direction="out"/>\r
                        <arg type="s" name="bssid" direction="out"/>\r
                        <arg type="i" name="channel" direction="out"/>\r
+                       <arg type="i" name="state" direction="out"/>\r
                        <arg type="i" name="result" direction="out"/>\r
                </method>\r
                <method name="set_gate">\r
                </signal>\r
                <signal name="scan_done">\r
                </signal>\r
-               <signal name="joined_network">\r
-               </signal>\r
-               <signal name="left_network">\r
-               </signal>\r
-               <signal name="mesh_connected">\r
-                       <arg type="i" name="result" direction="out"/>\r
+               <signal name="connection_state">\r
+                       <arg type="s" name="mesh_id" direction="out"/>\r
+                       <arg type="s" name="bssid" direction="out"/>\r
+                       <arg type="i" name="channel" direction="out"/>\r
+                       <arg type="i" name="state" direction="out"/>\r
                </signal>\r
                <signal name="sta_joined">\r
                        <arg type="s" name="bssid" direction="out"/>\r
index a128641..4f7bdf7 100644 (file)
@@ -26,6 +26,8 @@ static GDBusProxy *_gproxy_connman_mesh = NULL;
 static GDBusProxy *_gproxy_connman_technology = NULL;
 
 static int _meshd_close_gdbus_call(mesh_service *service);
+static int _mesh_ipc_get_mesh_network_property(mesh_service *service,
+       const gchar* object_path, mesh_network_info_s *result);
 
 static int __channel_to_frequency(int channel, enum nl80211_band band)
 {
@@ -186,28 +188,75 @@ static void _meshd_signal_handler(GDBusConnection *connection,
                const gchar *signal_name, GVariant *parameters, gpointer user_data)
 {
        mesh_service *service = (mesh_service*)user_data;
+       mesh_network_info_s network_info = { 0, 0, 0, 0, 0 };
+       int ret = MESHD_ERROR_NONE;
 
        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);
 
        MESH_LOGD("signal received = %s", signal_name);
        if (0 == g_strcmp0(signal_name, "ScanDone")) {
                /* TODO: Handle event */
                mesh_notify_scan_done();
+       } else if (0 == g_strcmp0(signal_name, "PropertyChanged")) {
+               const gchar* var = NULL;
+               gchar* key = NULL;
+               GVariant *variant = NULL;
+               meshd_connection_state_e state = MESHD_CONNECTION_STATE_DISCONNECTED;
+
+               if (NULL == parameters) {
+                       MESH_LOGE("Unexpected parameter");
+                       return;
+               }
+
+               g_variant_get(parameters, "(sv)", &key, &variant);
+               if (NULL == variant) {
+                       MESH_LOGE("Invalid variant");
+                       return;
+               }
+
+               /* State [???] */
+               var = g_variant_get_string(variant, NULL);
+               MESH_LOGD("  %s [%s]", key, var);
+               MESH_LOGD("    %s", object_path);
+
+               ret = _mesh_ipc_get_mesh_network_property(service, object_path, &network_info);
+               if (MESHD_ERROR_NONE != ret)
+                       MESH_LOGE("Cannot get valid network property !");
+
+               if (g_strcmp0("association", var) == 0) {
+                       /* Joined mesh network */
+                       state = MESHD_CONNECTION_STATE_ASSOCIATION;
+               } else if (g_strcmp0("configuration", var) == 0) {
+                       /* Trying to get IP address */
+                       state = MESHD_CONNECTION_STATE_CONFIGURATION;
+               } else if (g_strcmp0("ready", var) == 0 || g_strcmp0("online", var) == 0) {
+                       /* IP address is obtained */
+                       state = MESHD_CONNECTION_STATE_CONNECTED;
+               } else if (g_strcmp0("disconnect", var) == 0 || g_strcmp0("failure", var) == 0) {
+                       state = MESHD_CONNECTION_STATE_DISCONNECTED;
+               } else {
+                       MESH_LOGE("  Unhandled state !");
+                       g_free(network_info.mesh_id);
+                       g_free(network_info.bssid);
+                       return;
+               }
+
+               mesh_notify_connection_state(network_info.mesh_id, network_info.bssid,
+                       network_info.channel, state);
+
+               g_free(network_info.mesh_id);
+               g_free(network_info.bssid);
        }
 }
 
 static void _meshd_subscribe_event(mesh_service *service)
 {
-       unsigned int id;
+       unsigned int id = 0;
+
+       meshd_check_null_ret("service", service);
 
        id = g_dbus_connection_signal_subscribe(
                        (GDBusConnection *)service->connection,
@@ -221,9 +270,45 @@ static void _meshd_subscribe_event(mesh_service *service)
        service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
        MESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
 
+       /* To monitor mesh profiles */
+       id = g_dbus_connection_signal_subscribe(
+                       (GDBusConnection *)service->connection,
+                       CONNMAN_SERVER_NAME,
+                       CONNMAN_INTERFACE_MESH,
+                       "PropertyChanged",
+                       NULL, /* Path */
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
+       if (0 == id) {
+               MESH_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));
+       MESH_LOGD("[Signal subscribe] : PropertyChanged (%d)", id);
+
        /* End of subscription */
 }
 
+static void _on_unsubscribe_ids(gpointer data, gpointer user_data)
+{
+       unsigned int id = GPOINTER_TO_UINT(data);
+       mesh_service *service = (mesh_service*)user_data;
+
+       MESH_LOGD("[Signal unsubscribe] : %d", id);
+       g_dbus_connection_signal_unsubscribe(
+               (GDBusConnection *)service->connection, id);
+}
+
+static void _meshd_unsubscribe_event(mesh_service *service)
+{
+       meshd_check_null_ret("service", service);
+
+       g_list_foreach(service->dbus_sub_ids, _on_unsubscribe_ids, service);
+
+       g_list_free(service->dbus_sub_ids);
+       service->dbus_sub_ids = NULL;
+}
+
 int meshd_dbus_start(mesh_service *service)
 {
        int rv;
@@ -266,6 +351,9 @@ int meshd_dbus_stop(mesh_service *service)
        if (NULL == service)
                return MESHD_ERROR_INVALID_PARAMETER;
 
+       /* Unsubscribe events */
+       _meshd_unsubscribe_event(service);
+
        /* Unref all proxies here */
        if (_gproxy_connman) {
                g_object_unref(_gproxy_connman);
@@ -518,6 +606,12 @@ static void _get_joined_network(mesh_service *service, GVariant *variant)
                                        || g_strcmp0(buf, "failure") == 0) {
                                        valid_state = FALSE;
                                        break;
+                               } else if (g_strcmp0(buf, "association") == 0) {
+                                       joined_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
+                               } else if (g_strcmp0(buf, "configuration") == 0) {
+                                       joined_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
+                               } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
+                                       joined_info->state = MESHD_CONNECTION_STATE_CONNECTED;
                                }
                        }
                        else if (strcasecmp(key, "Frequency") == 0)  {
@@ -588,6 +682,18 @@ static void _get_mesh_peers(mesh_service *service, GVariant *variant)
                        else if (strcasecmp(key, "State") == 0)  {
                                const char *buf = g_variant_get_string(val, &len);
                                MESH_LOGD("    State : %s", buf);
+
+                               if (g_strcmp0(buf, "idle") == 0
+                                       || g_strcmp0(buf, "disconnect") == 0
+                                       || g_strcmp0(buf, "failure") == 0) {
+                                       scan_info->state = MESHD_CONNECTION_STATE_DISCONNECTED;
+                               } else if (g_strcmp0(buf, "association") == 0) {
+                                       scan_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
+                               } else if (g_strcmp0(buf, "configuration") == 0) {
+                                       scan_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
+                               } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
+                                       scan_info->state = MESHD_CONNECTION_STATE_CONNECTED;
+                               }
                        }
                        else if (strcasecmp(key, "Security") == 0)  {
                                const char *buf = g_variant_get_string(val, &len);
@@ -760,6 +866,97 @@ int mesh_ipc_get_joined_mesh_network(mesh_service *service)
        return MESHD_ERROR_NONE;
 }
 
+static void _get_mesh_property(GVariant *variant, mesh_network_info_s *result)
+{
+       GVariantIter *property = NULL;
+       gchar *key = NULL;
+       GVariant *val = NULL;
+       gsize len = 0;
+
+       MESH_LOGD("Type [%s]", g_variant_get_type_string(variant));
+
+       g_variant_get(variant, "(a{sv})", &property);
+
+       while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
+               if (strcasecmp(key, "Name") == 0)  {
+                       const char *buf = g_variant_get_string(val, &len);
+                       result->mesh_id = g_strdup(buf);
+                       MESH_LOGD("    Mesh ID : %s", result->mesh_id);
+               }
+               else if (strcasecmp(key, "Address") == 0)  {
+                       const char *buf = g_variant_get_string(val, &len);
+                       result->bssid = g_strdup(buf);
+                       MESH_LOGD("    BSSID : %s", result->bssid);
+               }
+               else if (strcasecmp(key, "State") == 0)  {
+                       const char *buf = g_variant_get_string(val, &len);
+                       MESH_LOGD("    State : %s", buf);
+
+                       if (g_strcmp0(buf, "idle") == 0
+                               || g_strcmp0(buf, "disconnect") == 0
+                               || g_strcmp0(buf, "failure") == 0) {
+                               result->state = MESHD_CONNECTION_STATE_DISCONNECTED;
+                       } else if (g_strcmp0(buf, "association") == 0) {
+                               result->state = MESHD_CONNECTION_STATE_ASSOCIATION;
+                       } else if (g_strcmp0(buf, "configuration") == 0) {
+                               result->state = MESHD_CONNECTION_STATE_CONFIGURATION;
+                       } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
+                               result->state = MESHD_CONNECTION_STATE_CONNECTED;
+                       }
+               }
+               else if (strcasecmp(key, "Security") == 0)  {
+                       const char *buf = g_variant_get_string(val, &len);
+                       MESH_LOGD("    Security : %s", buf);
+               }
+               else if (strcasecmp(key, "Frequency") == 0)  {
+                       result->channel = __frequency_to_channel(g_variant_get_uint16(val));
+                       MESH_LOGD("    Channel : %d", result->channel);
+               }
+               else if (strcasecmp(key, "Favorite") == 0)  {
+                       const char *buf = g_variant_get_string(val, &len);
+                       MESH_LOGD("    Favorite : %s", buf);
+               }
+               else if (strcasecmp(key, "Strength") == 0)  {
+                       gint rssi = (gint)g_variant_get_byte(val);
+                       MESH_LOGD("    RSSI : %d", rssi);
+               }
+       }
+       g_variant_iter_free(property);
+}
+
+static int _mesh_ipc_get_mesh_network_property(mesh_service *service,
+       const gchar* object_path, mesh_network_info_s *result)
+{
+       GVariant *variant = NULL;
+       GError *error = NULL;
+
+       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("result", result, MESHD_ERROR_INVALID_PARAMETER);
+
+       variant = g_dbus_connection_call_sync(service->connection,
+                       CONNMAN_SERVER_NAME,
+                       object_path,
+                       CONNMAN_INTERFACE_MESH,
+                       "GetProperties",
+                       NULL, NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1, NULL, &error);
+       if (variant) {
+               MESH_LOGD("Successfully requested. [GetProperties]");
+
+               /* Get properties */
+               _get_mesh_property(variant, result);
+       } else if (error) {
+               LOGE("Failed DBus call [%s]", error->message);
+               g_error_free(error);
+               return MESHD_ERROR_IO_ERROR;
+       }
+
+       return MESHD_ERROR_NONE;
+}
+
 int mesh_ipc_create_network(mesh_service *service, gchar *mesh_id, gint channel,
         gint security)
 {
@@ -814,7 +1011,7 @@ int mesh_ipc_create_network(mesh_service *service, gchar *mesh_id, gint channel,
 
        return MESHD_ERROR_NONE;
 }
-
+#if 0
 static void on_response_connect_network(GObject *source_object,
        GAsyncResult *res, gpointer user_data)
 {
@@ -828,6 +1025,8 @@ static void on_response_connect_network(GObject *source_object,
                        G_DBUS_CONNECTION(source_object), res, &error);
        if (variant) {
                MESH_LOGD("Successfully requested. [Connect]");
+
+               /* TODO: Unregister property change event */
        } else if (error) {
                ret = MESHD_ERROR_IO_ERROR;
                LOGE("Failed DBus call [%s]", error->message);
@@ -841,9 +1040,8 @@ static void on_response_connect_network(GObject *source_object,
 
                g_error_free(error);
        }
-
-       mesh_notify_mesh_connected(ret);
 }
+#endif
 
 int mesh_ipc_connect_network(mesh_service *service, mesh_scan_result_s *info)
 {
@@ -857,9 +1055,10 @@ int mesh_ipc_connect_network(mesh_service *service, mesh_scan_result_s *info)
                        "Connect",
                        NULL, NULL,
                        G_DBUS_CALL_FLAGS_NONE,
-                       MESH_DBUS_PROXY_TIMEOUT * 2, /* Waits for long time */
-                       NULL,
-                       on_response_connect_network, service);
+                       -1,
+                       NULL, /* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED */
+                       NULL, NULL);
+       MESH_LOGD("Successfully requested. [Connect]");
 
        return MESHD_ERROR_NONE;
 }
index cd7f1d0..917d26a 100644 (file)
@@ -247,8 +247,6 @@ int mesh_request_enable_mesh(const char* base_interface,
                        MESH_LOGD("    BSSID   : [%s]", info.mesh_id);
                        MESH_LOGD("    channel : [%d]", info.channel);
                        MESH_LOGD("    security: [%d]", info.security);
-
-                       mesh_notify_joined_network();
                }
        }
 
@@ -972,25 +970,12 @@ void mesh_notify_scan_done()
        net_mesh_emit_scan_done(object);
 }
 
-void mesh_notify_joined_network()
-{
-       NetMesh *object = meshd_dbus_get_object();
-
-       net_mesh_emit_joined_network(object);
-}
-
-void mesh_notify_left_network()
-{
-       NetMesh *object = meshd_dbus_get_object();
-
-       net_mesh_emit_left_network(object);
-}
-
-void mesh_notify_mesh_connected(int result)
+void mesh_notify_connection_state(const char* mesh_id, const char* bssid,
+               int channel, meshd_connection_state_e state)
 {
        NetMesh *object = meshd_dbus_get_object();
 
-       net_mesh_emit_mesh_connected(object, result);
+       net_mesh_emit_connection_state(object, mesh_id, bssid, channel, (int)state);
 }
 
 void mesh_notify_station_joined(const char* bssid)
index 52a1e25..85c99f4 100644 (file)
@@ -384,6 +384,8 @@ static gboolean _meshd_dbus_handle_get_found_mesh_networks(NetMesh *object,
                                g_variant_new_int32(scan_item->rssi));
                g_variant_builder_add(&builder, "{sv}", "channel",
                                g_variant_new_uint32(scan_item->channel));
+               g_variant_builder_add(&builder, "{sv}", "state",
+                               g_variant_new_uint32(scan_item->state));
                g_variant_builder_close(&builder);
 
                iter = g_list_next(iter);
@@ -511,9 +513,6 @@ static gboolean _meshd_dbus_handle_disable_mesh(NetMesh *object,
        /* Make response */
        net_mesh_complete_disable_mesh(object, invocation, ret);
 
-       /* Make notification */
-       mesh_notify_left_network();
-
        return TRUE;
 }
 
@@ -534,14 +533,15 @@ static gboolean _meshd_dbus_handle_get_joined_mesh_network(NetMesh *object,
                joined = service->joined_network;
                if (joined) {
                        net_mesh_complete_get_joined_mesh_network(object, invocation,
-                               joined->mesh_id, joined->bssid, joined->channel, ret);
+                               joined->mesh_id, joined->bssid,
+                               joined->channel, joined->state, ret);
                } else {
                        net_mesh_complete_get_joined_mesh_network(object, invocation,
-                               "", "", 0, MESHD_ERROR_NO_DATA);
+                               "", "", 0, 0, MESHD_ERROR_NO_DATA);
                }
        } else {
                net_mesh_complete_get_joined_mesh_network(object, invocation,
-                       "", "", 0, ret);
+                       "", "", 0, 0, ret);
        }
 
        return TRUE;