diff --git a/CMakeLists.txt b/CMakeLists.txt index b4007e3f..511bb20a 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 2c23ed09..70630d9c 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,33 @@ lr_handle_remote_sources_changed(LrHandle *handle, LrChangedRemoteSource type) } } +struct callback_data { + GMainLoop *loop; + long input_seconds; + time_t begin; + GNetworkMonitor *monitor; + GSocketConnectable *connectable; + GCancellable *cancellable; +}; + +gboolean timeout_callback(gpointer data) +{ + struct callback_data *dt = (struct callback_data*)data; + if(!g_network_monitor_can_reach(dt->monitor, dt->connectable, dt->cancellable, NULL) && + time(NULL) - dt->begin <= dt->input_seconds){ + return TRUE; + } + g_main_loop_quit(dt->loop); + return FALSE; +} + +void on_network_available(GObject *object, GParamSpec *pspec, gpointer data) +{ + g_timeout_add(200, timeout_callback, data); + struct callback_data *dt = (struct callback_data*)data; + g_main_loop_run(dt->loop); +} + gboolean lr_handle_setopt(LrHandle *handle, GError **err, @@ -841,7 +870,56 @@ lr_handle_setopt(LrHandle *handle, return ret; } -static gboolean +gboolean +lr_handle_network_wait(LrHandle *handle, GError **err, guint seconds) +{ + + 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(); + GCancellable *cancellable = g_cancellable_new (); + + struct callback_data data_struct; + data_struct.input_seconds = seconds; + data_struct.begin = time(NULL); + data_struct.cancellable = cancellable; + data_struct.monitor = monitor; + + 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); + + 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; + g_autoptr(GMainLoop) loop; + loop = g_main_loop_new(NULL, FALSE); + data_struct.loop = loop; + 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 7c55a95b..90150e34 100644 --- a/librepo/handle.h +++ b/librepo/handle.h @@ -560,6 +560,15 @@ 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 ** + * @return TRUE if everything is ok, FALSE if err is set. + */ +gboolean +lr_handle_network_wait(LrHandle *handle, GError **err, guint seconds); + /** @} */ G_END_DECLS