Add url checker and downgrade service state feature. 37/263737/11
authorNiraj Kumar Goit <niraj.g@samsung.com>
Thu, 9 Sep 2021 19:26:00 +0000 (00:56 +0530)
committerJaehyun Kim <jeik01.kim@samsung.com>
Wed, 15 Sep 2021 07:25:45 +0000 (07:25 +0000)
Change-Id: I134b1018f3c580bb3d3a999fd01ebc650f82d7c6
Signed-off-by: Niraj Kumar Goit <niraj.g@samsung.com>
packaging/net-config.spec
plugin/online-monitor/CMakeLists.txt
plugin/online-monitor/online-monitor.h
plugin/online-monitor/url-checker.c

index 51ce1fa..81c7123 100755 (executable)
@@ -18,6 +18,7 @@ BuildRequires:        pkgconfig(key-manager)
 BuildRequires: pkgconfig(libnl-3.0)
 BuildRequires: pkgconfig(libnl-genl-3.0)
 BuildRequires:  pkgconfig(hal-api-wifi)
+BuildRequires: pkgconfig(libcurl)
 Requires:              vconf
 Requires:              connman
 Requires:              systemd
index 3d3652b..0b1f0f5 100755 (executable)
@@ -12,6 +12,7 @@ INCLUDE(FindPkgConfig)
 PKG_CHECK_MODULES(pkgs_online_mon REQUIRED
        dlog
        glib-2.0
+       libcurl
        )
 
 FOREACH(flag ${pkgs_online_mon_CFLAGS})
index 312eae1..a987508 100644 (file)
@@ -17,6 +17,8 @@
  *
  */
 
+#include <curl/curl.h>
+
 #include "plugin.h"
 #include "util.h"
 
index a0029e8..38427b0 100755 (executable)
 
 #include "online-monitor.h"
 
+#define AOC_DBUS_REPLY_TIMEOUT         (15 * 1000)
+
+#define CONNMAN_SERVICE                                "net.connman"
+#define CONNMAN_SERVICE_INTERFACE              CONNMAN_SERVICE ".Service"
+#define CONNMAN_MANAGER_PATH                   "/"
+#define CONNMAN_MANAGER_INTERFACE              CONNMAN_SERVICE ".Manager"
+
+/* Async HTTP Request */
+static CURL *curl_handle = NULL;
+static CURLM *multi_handle = NULL;
+static int still_running = 0;
+static guint timer_id = 0;
+
+static GVariant *__invoke_dbus_method(const char *dest, const char *path,
+               const char *interface_name, const char *method, GVariant *params)
+{
+
+       GError *error = NULL;
+       GVariant *reply = NULL;
+       GDBusConnection *connection;
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (connection == NULL) {
+               ERR("[AOC] Failed to get GDBusconnection");
+               return reply;
+       }
+
+       reply = g_dbus_connection_call_sync(
+                       connection,
+                       dest,
+                       path,
+                       interface_name,
+                       method,
+                       params,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       AOC_DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       g_object_unref(connection);
+
+       if (reply == NULL) {
+               if (error != NULL) {
+                       ERR("[AOC] g_dbus_connection_call_sync() failed"
+                                               "error [%d: %s]", error->code, error->message);
+                       g_error_free(error);
+               } else {
+                       ERR("[AOC] g_dbus_connection_call_sync() failed");
+               }
+
+               return NULL;
+       }
+
+       return reply;
+}
+
+static void _get_default_service_profile(char **profile)
+{
+       GVariant *message = NULL;
+       GVariantIter *iter;
+       gchar *obj_path;
+
+       message = __invoke_dbus_method(CONNMAN_SERVICE,
+                       CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
+                       "GetDefaultService", NULL);
+
+       if (message == NULL) {
+               ERR("Failed to get services informations");
+               return;
+       }
+
+       if (!g_variant_is_of_type(message, G_VARIANT_TYPE("(oa{sv})"))) {
+               DBG("There is no default service");
+               g_variant_unref(message);
+               return;
+       }
+
+       g_variant_get(message, "(oa{sv})", &obj_path, &iter);
+       *profile = g_strdup(obj_path);
+
+       g_variant_iter_free(iter);
+       g_variant_unref(message);
+}
+
+static void _get_url(char **url)
+{
+       online_monitor_config_t *config = online_monitor_get_configuration();
+
+       /* Generate a random number in range [0, 5] */
+       const int max_url = 6;
+
+       srand(time(0));
+       int index = (rand() % max_url);
+
+       *url = g_strdup(config->url_list[index]);
+}
+
+void _curl_state_cleanup()
+{
+       int rv = 0;
+
+       if (timer_id != 0) {
+               g_source_remove(timer_id);
+               timer_id = 0;
+       }
+
+       /* Clean up easy and multi curl handle which might have been initialized
+        * in previous call to curl_easy_init() and not yet cleaned up */
+
+       if (curl_handle != NULL && multi_handle != NULL) {
+               rv = curl_multi_remove_handle(multi_handle, curl_handle);
+               if(rv != CURLM_OK)
+                       ERR("curl_multi_remove_handle Failed [%s]", curl_multi_strerror(rv));
+       }
+
+       if(curl_handle != NULL) {
+               curl_easy_cleanup(curl_handle);
+               curl_handle = NULL;
+       }
+
+       if(multi_handle != NULL) {
+               rv = curl_multi_cleanup(multi_handle);
+               if(rv != CURLM_OK)
+                       ERR("curl_multi_cleanup() Failed [%s]", curl_multi_strerror(rv));
+               multi_handle = NULL;
+       }
+}
+
+static gboolean _curl_http_request(gpointer data)
+{
+       int rv;
+       bool flag = false;
+
+       if (0 != still_running) {
+               rv = curl_multi_perform(multi_handle, &still_running);
+               if (rv != CURLM_OK) {
+                       ERR("curl multi perform failed %s", curl_multi_strerror(rv));
+                       flag = false;
+                       goto out;
+               }
+               return true;
+       }
+
+       CURLMsg *m = NULL;
+       int msg_left = 0;
+
+       m = curl_multi_info_read(multi_handle, &msg_left);
+       if (m && (m->msg == CURLMSG_DONE))
+               DBG("HTTP transfer completed with result code[%d: %s]", m->data.result, curl_easy_strerror(m->data.result));
+
+       if (curl_handle != NULL) {
+               long http_status = 0;
+               curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_status);
+               DBG("HTTP Status [%ld]\n", http_status);
+
+               if (http_status == 200 || (http_status >= 300 && http_status < 400))
+                       flag = true;
+               else
+                       flag = false;
+       }
+
+out:
+       if (!flag) {
+               /* Downgrade service state */
+               char *service_profile = NULL;
+               _get_default_service_profile(&service_profile);
+
+               if (service_profile) {
+                       DBG("service_profile: %s", service_profile);
+                       GVariant *reply = __invoke_dbus_method(CONNMAN_SERVICE,
+                                       service_profile, CONNMAN_SERVICE_INTERFACE, "Downgrade",
+                                       NULL);
+
+                       if (reply != NULL)
+                               g_variant_unref(reply);
+                       else
+                               ERR("Failed to Downgrade service\n");
+                       g_free(service_profile);
+               }
+       }
+       _curl_state_cleanup();
+       online_monitor_url_check_result(flag);
+       return false;
+}
+
+/*
+       HTTP test to check the online state in order to confirm that there are no exceptions.
+       If online check fails, downgrade the ConnMan state to 'ready'.
+ */
+int start_url_check(void)
+{
+       int result;
+       char *url = NULL;
+
+       if (timer_id != 0) {
+               ERR("Request already in progress.");
+               result = 0;
+               goto out;
+       }
+
+       curl_handle = curl_easy_init();
+
+       if (curl_handle == NULL) {
+               ERR("Failed to curl_easy_init()");
+               result = -1;
+               goto out;
+       }
+
+       _get_url(&url);
+       DBG("HTTP Test for url: %s", url);
+
+       int rv = curl_easy_setopt(curl_handle, CURLOPT_URL, url);
+       if (rv != CURLE_OK)
+       {
+               ERR("Failed to set URL %s", curl_easy_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10);
+       if (rv != CURLE_OK) {
+               ERR("Failed to set connection timeout %s", curl_easy_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 12);
+       if (rv != CURLE_OK) {
+               ERR("Failed to set timeout %s", curl_easy_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
+       if (rv != CURLE_OK) {
+               ERR("Failed to set Noprogress option %s", curl_easy_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);
+       if (rv != CURLE_OK) {
+               ERR("Failed to set Nosignal option %s", curl_easy_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       /* Perform curl operation */
+       multi_handle = curl_multi_init();
+       if (multi_handle == NULL) {
+               ERR("Failed to curl_multi_init() %s", curl_multi_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_multi_add_handle(multi_handle, curl_handle);
+       if(rv != CURLM_OK) {
+               ERR("curl multi add handle failed %s", curl_multi_strerror(rv));
+               result = -1;
+               goto out;
+       }
+
+       rv = curl_multi_perform(multi_handle, &still_running);
+       if(rv != CURLM_OK) {
+               ERR("curl multi perform failed %s", curl_multi_strerror(rv));
+               result = -1;
+       } else {
+               /* Adding timeout of 100 msec to check whether data is available
+                * for multi handle to read or write or timeout set initially
+                * has elapsed. curl_multi_perform() should be called whenever
+                * data is available to read or write. Smaller time will result
+                * in faster processing
+                * */
+               timer_id = g_timeout_add(100, _curl_http_request, NULL);
+               result = 0;
+       }
+
+out:
+
+       if (result < 0)
+               _curl_state_cleanup();
+
+       g_free(url);
+       return result;
+}
+
 static void url_checker_state_chaged_cb(online_monitor_state_e state,
                                char* ifname, online_monitor_detection_e reason)
 {
        DBG("state %d, ifname %s, reason %d", state, ifname, reason);
+       if (state == ONLINE_MONITOR_STATE_OFFLINE_DETECTED)
+               start_url_check();
 }
 
 int url_checker_init(void)
 {
        online_monitor_notifier_register(url_checker_state_chaged_cb);
+
+       /* Init curl library */
+       curl_global_init(CURL_GLOBAL_ALL);
+
        DBG("url_checker initialized");
        return 0;
 }
@@ -35,6 +328,8 @@ int url_checker_init(void)
 int url_checker_deinit(void)
 {
        online_monitor_notifier_unregister(url_checker_state_chaged_cb);
+       curl_global_cleanup();
+
        DBG("url_checker deinitialized");
        return 0;
 }