From 6ccecfa9a0ed7d13e094e8ac2df23f3958b261cc Mon Sep 17 00:00:00 2001 From: RishabhSaini Date: Wed, 24 Aug 2022 10:48:51 -0400 Subject: [PATCH] CMakeLists.txt: added requirement for gio-2.0 library handle.h: function signature for lr_handle_network_wait handle.c: Added callback function required for GMainEventLoop Adds API support for waiting on network in an event driven manner: This waits for clients network interfaces till the specified time. lr_handle_network_wait(priv->repo_handle, error, timeout_seconds) This parses metalinkurl/baseurl and upon network-available signal, it polls g_network_monitor_can_reach() with the help of GMainEventLoop. --- CMakeLists.txt | 2 +- librepo/handle.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++- librepo/handle.h | 11 +++++ 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4007e3f2..511bb20ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") # Find necessare libraries FIND_PACKAGE(PkgConfig) -PKG_CHECK_MODULES(GLIB2 glib-2.0>=2.28 REQUIRED) +PKG_CHECK_MODULES(GLIB2 glib-2.0>=2.28 gio-2.0 REQUIRED) PKG_SEARCH_MODULE(LIBCRYPTO REQUIRED libcrypto openssl) PKG_CHECK_MODULES(LIBXML2 libxml-2.0 REQUIRED) FIND_PACKAGE(CURL 7.52.0 REQUIRED) diff --git a/librepo/handle.c b/librepo/handle.c index 2c23ed091..41c663804 100644 --- a/librepo/handle.c +++ b/librepo/handle.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "handle_internal.h" @@ -264,6 +266,50 @@ lr_handle_remote_sources_changed(LrHandle *handle, LrChangedRemoteSource type) } } +struct callback_data { + GMainLoop *loop; + guint64 deadline_millis; + guint timeout_id; + GNetworkMonitor *monitor; + GSocketConnectable *connectable; + GCancellable *cancellable; +}; + +gboolean timeout_callback(gpointer data) +{ + struct callback_data *dt = (struct callback_data*)data; + + //if no internet, remove source + if(!g_network_monitor_get_network_available(dt->monitor)){ + return G_SOURCE_REMOVE; + } + + //if url reached, remove source and exit loop + if(g_network_monitor_can_reach (dt->monitor, dt->connectable, dt->cancellable, NULL)){ + g_main_loop_quit(dt->loop); + return G_SOURCE_REMOVE; + } + + //if url not reached and time exists, keep source and poll + if(!g_network_monitor_can_reach (dt->monitor, dt->connectable, dt->cancellable, NULL) && + g_get_monotonic_time() < dt->deadline_millis){ + return G_SOURCE_CONTINUE; + } + + //if time does not exist, remove source and exit + g_main_loop_quit(dt->loop); + return G_SOURCE_REMOVE; +} + +void on_network_available(GObject *object, GParamSpec *pspec, gpointer data) +{ + struct callback_data *dt = (struct callback_data*)data; + if(dt->timeout_id == 0 && g_network_monitor_get_network_available(dt->monitor)){ + dt->timeout_id = g_timeout_add(200, timeout_callback, dt); + } + g_main_loop_run(dt->loop); +} + gboolean lr_handle_setopt(LrHandle *handle, GError **err, @@ -841,7 +887,62 @@ lr_handle_setopt(LrHandle *handle, return ret; } -static gboolean +gboolean +lr_handle_network_wait(LrHandle *handle, GError **err, guint seconds, GCancellable *cancellable) +{ + + assert(!err || *err == NULL); + + if (!handle) { + g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG, + "No handle specified"); + return FALSE; + } + + GNetworkMonitor *monitor = g_network_monitor_get_default(); + + struct callback_data data_struct; + data_struct.cancellable = cancellable; + data_struct.monitor = monitor; + + const gchar *baseurl; + if(handle->metalinkurl) + baseurl = handle->metalinkurl; + else if(handle->mirrorlisturl) + baseurl = handle->mirrorlisturl; + else if(handle->urls) + baseurl = handle->urls[0]; + assert(baseurl); + + g_autoptr(GUri) uri = g_uri_parse(baseurl, G_URI_FLAGS_NONE, NULL); + if(uri == NULL){ + return FALSE; + } + const gchar* scheme = g_uri_get_scheme(uri); + if(!g_strcmp0(scheme, "file")){ + return TRUE; + } + const gchar* host = g_uri_get_host(uri); + guint16 port = g_uri_get_port(uri); + GSocketConnectable *connectable = g_network_address_new(host, port); + data_struct.connectable = connectable; + data_struct.deadline_millis = g_get_monotonic_time() + seconds * G_USEC_PER_SEC; + g_autoptr(GMainLoop) loop; + loop = g_main_loop_new(NULL, FALSE); + data_struct.loop = loop; + data_struct.timeout_id = 0; + + if(g_network_monitor_get_network_available(data_struct.monitor)){ + data_struct.timeout_id = g_timeout_add(200, timeout_callback, &data_struct); + g_main_loop_run(data_struct.loop); + } + else{ + g_signal_connect(monitor, "notify::network-available", G_CALLBACK(on_network_available), &data_struct); + } + return TRUE; +} + +gboolean lr_handle_prepare_urls(LrHandle *handle, GError **err) { assert(!handle->urls_mirrors); diff --git a/librepo/handle.h b/librepo/handle.h index 7c55a95b5..776b8b130 100644 --- a/librepo/handle.h +++ b/librepo/handle.h @@ -22,6 +22,7 @@ #define __LR_HANDLE_H__ #include +#include #include "result.h" @@ -560,6 +561,16 @@ lr_handle_getinfo(LrHandle *handle, gboolean lr_handle_perform(LrHandle *handle, LrResult *result, GError **err); +/** Handle waiting on network for LRO_URLS. + * @param handle Librepo handle. + * @param seconds Network timeout seconds + * @param err GError ** + * @param cancellable GCancellable * + * @return TRUE if everything is ok, FALSE if err is set. + */ +gboolean +lr_handle_network_wait(LrHandle *handle, GError **err, guint seconds, GCancellable *cancellable); + /** @} */ G_END_DECLS