From c90dd765e793fb1810ca1b82725b67ebb8a790a3 Mon Sep 17 00:00:00 2001 From: Niraj Kumar Goit Date: Fri, 10 Sep 2021 00:56:00 +0530 Subject: [PATCH] Add url checker and downgrade service state feature. Change-Id: I134b1018f3c580bb3d3a999fd01ebc650f82d7c6 Signed-off-by: Niraj Kumar Goit --- packaging/net-config.spec | 1 + plugin/online-monitor/CMakeLists.txt | 1 + plugin/online-monitor/online-monitor.h | 2 + plugin/online-monitor/url-checker.c | 295 +++++++++++++++++++++++++++++++++ 4 files changed, 299 insertions(+) diff --git a/packaging/net-config.spec b/packaging/net-config.spec index 51ce1fa..81c7123 100755 --- a/packaging/net-config.spec +++ b/packaging/net-config.spec @@ -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 diff --git a/plugin/online-monitor/CMakeLists.txt b/plugin/online-monitor/CMakeLists.txt index 3d3652b..0b1f0f5 100755 --- a/plugin/online-monitor/CMakeLists.txt +++ b/plugin/online-monitor/CMakeLists.txt @@ -12,6 +12,7 @@ INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(pkgs_online_mon REQUIRED dlog glib-2.0 + libcurl ) FOREACH(flag ${pkgs_online_mon_CFLAGS}) diff --git a/plugin/online-monitor/online-monitor.h b/plugin/online-monitor/online-monitor.h index 312eae1..a987508 100644 --- a/plugin/online-monitor/online-monitor.h +++ b/plugin/online-monitor/online-monitor.h @@ -17,6 +17,8 @@ * */ +#include + #include "plugin.h" #include "util.h" diff --git a/plugin/online-monitor/url-checker.c b/plugin/online-monitor/url-checker.c index a0029e8..38427b0 100755 --- a/plugin/online-monitor/url-checker.c +++ b/plugin/online-monitor/url-checker.c @@ -19,15 +19,308 @@ #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; } -- 2.7.4