diff options
Diffstat (limited to 'clients/cloud-setup')
| -rwxr-xr-x | clients/cloud-setup/90-nm-cloud-setup.sh | 9 | ||||
| -rw-r--r-- | clients/cloud-setup/main.c | 605 | ||||
| -rw-r--r-- | clients/cloud-setup/meson.build | 74 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup-utils.c | 902 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup-utils.h | 152 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup.service.in | 42 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-cloud-setup.timer | 9 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-http-client.c | 801 | ||||
| -rw-r--r-- | clients/cloud-setup/nm-http-client.h | 71 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-azure.c | 526 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-azure.h | 28 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-ec2.c | 427 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-ec2.h | 27 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-gcp.c | 464 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-gcp.h | 27 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider.c | 288 | ||||
| -rw-r--r-- | clients/cloud-setup/nmcs-provider.h | 128 | ||||
| -rw-r--r-- | clients/cloud-setup/tests/meson.build | 20 | ||||
| -rw-r--r-- | clients/cloud-setup/tests/test-cloud-setup-general.c | 117 |
19 files changed, 0 insertions, 4717 deletions
diff --git a/clients/cloud-setup/90-nm-cloud-setup.sh b/clients/cloud-setup/90-nm-cloud-setup.sh deleted file mode 100755 index 817e2555..00000000 --- a/clients/cloud-setup/90-nm-cloud-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -case "$2" in - up|dhcp4-change) - if systemctl -q is-enabled nm-cloud-setup.service ; then - exec systemctl --no-block restart nm-cloud-setup.service - fi - ;; -esac diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c deleted file mode 100644 index 06590176..00000000 --- a/clients/cloud-setup/main.c +++ /dev/null @@ -1,605 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nm-libnm-aux/nm-libnm-aux.h" - -#include "nm-cloud-setup-utils.h" -#include "nmcs-provider-ec2.h" -#include "nmcs-provider-gcp.h" -#include "nmcs-provider-azure.h" -#include "nm-libnm-core-intern/nm-libnm-core-utils.h" - -/*****************************************************************************/ - -typedef struct { - GMainLoop * main_loop; - GCancellable *cancellable; - NMCSProvider *provider_result; - guint detect_count; -} ProviderDetectData; - -static void -_provider_detect_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_object NMCSProvider *provider = NMCS_PROVIDER(source); - gs_free_error GError *error = NULL; - ProviderDetectData * dd; - gboolean success; - - success = nmcs_provider_detect_finish(provider, result, &error); - - nm_assert(success != (!!error)); - - if (nm_utils_error_is_cancelled(error)) - return; - - dd = user_data; - - nm_assert(dd->detect_count > 0); - dd->detect_count--; - - if (error) { - _LOGI("provider %s not detected: %s", nmcs_provider_get_name(provider), error->message); - if (dd->detect_count > 0) { - /* wait longer. */ - return; - } - - _LOGI("no provider detected"); - goto done; - } - - _LOGI("provider %s detected", nmcs_provider_get_name(provider)); - dd->provider_result = g_steal_pointer(&provider); - -done: - g_cancellable_cancel(dd->cancellable); - g_main_loop_quit(dd->main_loop); -} - -static void -_provider_detect_sigterm_cb(GCancellable *source, gpointer user_data) -{ - ProviderDetectData *dd = user_data; - - g_cancellable_cancel(dd->cancellable); - g_clear_object(&dd->provider_result); - dd->detect_count = 0; - g_main_loop_quit(dd->main_loop); -} - -static NMCSProvider * -_provider_detect(GCancellable *sigterm_cancellable) -{ - nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); - gs_unref_object GCancellable *cancellable = g_cancellable_new(); - gs_unref_object NMHttpClient *http_client = NULL; - ProviderDetectData dd = { - .cancellable = cancellable, - .main_loop = main_loop, - .detect_count = 0, - .provider_result = NULL, - }; - const GType gtypes[] = { - NMCS_TYPE_PROVIDER_EC2, - NMCS_TYPE_PROVIDER_GCP, - NMCS_TYPE_PROVIDER_AZURE, - }; - int i; - gulong cancellable_signal_id; - - cancellable_signal_id = g_cancellable_connect(sigterm_cancellable, - G_CALLBACK(_provider_detect_sigterm_cb), - &dd, - NULL); - if (!cancellable_signal_id) - goto out; - - http_client = nmcs_wait_for_objects_register(nm_http_client_new()); - - for (i = 0; i < G_N_ELEMENTS(gtypes); i++) { - NMCSProvider *provider; - - provider = g_object_new(gtypes[i], NMCS_PROVIDER_HTTP_CLIENT, http_client, NULL); - nmcs_wait_for_objects_register(provider); - - _LOGD("start detecting %s provider...", nmcs_provider_get_name(provider)); - dd.detect_count++; - nmcs_provider_detect(provider, cancellable, _provider_detect_cb, &dd); - } - - if (dd.detect_count > 0) - g_main_loop_run(main_loop); - -out: - nm_clear_g_signal_handler(sigterm_cancellable, &cancellable_signal_id); - return dd.provider_result; -} - -/*****************************************************************************/ - -static char ** -_nmc_get_hwaddrs(NMClient *nmc) -{ - gs_unref_ptrarray GPtrArray *hwaddrs = NULL; - const GPtrArray * devices; - char ** hwaddrs_v; - gs_free char * str = NULL; - guint i; - - devices = nm_client_get_devices(nmc); - - for (i = 0; i < devices->len; i++) { - NMDevice * device = devices->pdata[i]; - const char *hwaddr; - char * s; - - if (!NM_IS_DEVICE_ETHERNET(device)) - continue; - - if (nm_device_get_state(device) < NM_DEVICE_STATE_UNAVAILABLE) - continue; - - hwaddr = nm_device_ethernet_get_permanent_hw_address(NM_DEVICE_ETHERNET(device)); - if (!hwaddr) - continue; - - s = nmcs_utils_hwaddr_normalize(hwaddr, -1); - if (!s) - continue; - - if (!hwaddrs) - hwaddrs = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add(hwaddrs, s); - } - - if (!hwaddrs) { - _LOGD("found interfaces: none"); - return NULL; - } - - g_ptr_array_add(hwaddrs, NULL); - hwaddrs_v = (char **) g_ptr_array_free(g_steal_pointer(&hwaddrs), FALSE); - - _LOGD("found interfaces: %s", (str = g_strjoinv(", ", hwaddrs_v))); - - return hwaddrs_v; -} - -static NMDevice * -_nmc_get_device_by_hwaddr(NMClient *nmc, const char *hwaddr) -{ - const GPtrArray *devices; - guint i; - - devices = nm_client_get_devices(nmc); - - for (i = 0; i < devices->len; i++) { - NMDevice * device = devices->pdata[i]; - const char * hwaddr_dev; - gs_free char *s = NULL; - - if (!NM_IS_DEVICE_ETHERNET(device)) - continue; - - hwaddr_dev = nm_device_ethernet_get_permanent_hw_address(NM_DEVICE_ETHERNET(device)); - if (!hwaddr_dev) - continue; - - s = nmcs_utils_hwaddr_normalize(hwaddr_dev, -1); - if (s && nm_streq(s, hwaddr)) - return device; - } - - return NULL; -} - -/*****************************************************************************/ - -typedef struct { - GMainLoop * main_loop; - GHashTable *config_dict; -} GetConfigData; - -static void -_get_config_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - GetConfigData * data = user_data; - gs_unref_hashtable GHashTable *config_dict = NULL; - gs_free_error GError *error = NULL; - - config_dict = nmcs_provider_get_config_finish(NMCS_PROVIDER(source), result, &error); - - if (!config_dict) { - if (!nm_utils_error_is_cancelled(error)) - _LOGI("failure to get meta data: %s", error->message); - } else - _LOGD("meta data received"); - - data->config_dict = g_steal_pointer(&config_dict); - g_main_loop_quit(data->main_loop); -} - -static GHashTable * -_get_config(GCancellable *sigterm_cancellable, NMCSProvider *provider, NMClient *nmc) -{ - nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); - GetConfigData data = { - .main_loop = main_loop, - }; - gs_strfreev char **hwaddrs = NULL; - - hwaddrs = _nmc_get_hwaddrs(nmc); - - nmcs_provider_get_config(provider, - TRUE, - (const char *const *) hwaddrs, - sigterm_cancellable, - _get_config_cb, - &data); - - g_main_loop_run(main_loop); - - return data.config_dict; -} - -/*****************************************************************************/ - -static gboolean -_nmc_skip_connection(NMConnection *connection) -{ - NMSettingUser *s_user; - const char * v; - - s_user = NM_SETTING_USER(nm_connection_get_setting(connection, NM_TYPE_SETTING_USER)); - if (!s_user) - return FALSE; - -#define USER_TAG_SKIP "org.freedesktop.nm-cloud-setup.skip" - - nm_assert(nm_setting_user_check_key(USER_TAG_SKIP, NULL)); - - v = nm_setting_user_get_data(s_user, USER_TAG_SKIP); - return _nm_utils_ascii_str_to_bool(v, FALSE); -} - -static gboolean -_nmc_mangle_connection(NMDevice * device, - NMConnection * connection, - const NMCSProviderGetConfigIfaceData *config_data, - gboolean * out_changed) -{ - NMSettingIPConfig *s_ip; - gsize i; - in_addr_t gateway; - gint64 rt_metric; - guint32 rt_table; - NMIPRoute * route_entry; - gboolean addrs_changed = FALSE; - gboolean rules_changed = FALSE; - gboolean routes_changed = FALSE; - gs_unref_ptrarray GPtrArray *addrs_new = NULL; - gs_unref_ptrarray GPtrArray *rules_new = NULL; - gs_unref_ptrarray GPtrArray *routes_new = NULL; - - if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME)) - return FALSE; - - s_ip = nm_connection_get_setting_ip4_config(connection); - if (!s_ip) - return FALSE; - - addrs_new = g_ptr_array_new_full(config_data->ipv4s_len, (GDestroyNotify) nm_ip_address_unref); - rules_new = - g_ptr_array_new_full(config_data->ipv4s_len, (GDestroyNotify) nm_ip_routing_rule_unref); - routes_new = g_ptr_array_new_full(config_data->iproutes_len + !!config_data->ipv4s_len, - (GDestroyNotify) nm_ip_route_unref); - - if (config_data->has_ipv4s && config_data->has_cidr) { - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPAddress *entry; - - entry = nm_ip_address_new_binary(AF_INET, - &config_data->ipv4s_arr[i], - config_data->cidr_prefix, - NULL); - if (entry) - g_ptr_array_add(addrs_new, entry); - } - - gateway = nm_utils_ip4_address_clear_host_address(config_data->cidr_addr, - config_data->cidr_prefix); - ((guint8 *) &gateway)[3] += 1; - - rt_metric = 10; - rt_table = 30400 + config_data->iface_idx; - - route_entry = - nm_ip_route_new_binary(AF_INET, &nm_ip_addr_zero, 0, &gateway, rt_metric, NULL); - nm_ip_route_set_attribute(route_entry, - NM_IP_ROUTE_ATTRIBUTE_TABLE, - g_variant_new_uint32(rt_table)); - g_ptr_array_add(routes_new, route_entry); - - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPRoutingRule *entry; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - entry = nm_ip_routing_rule_new(AF_INET); - nm_ip_routing_rule_set_priority(entry, rt_table); - nm_ip_routing_rule_set_from(entry, - _nm_utils_inet4_ntop(config_data->ipv4s_arr[i], sbuf), - 32); - nm_ip_routing_rule_set_table(entry, rt_table); - - nm_assert(nm_ip_routing_rule_validate(entry, NULL)); - - g_ptr_array_add(rules_new, entry); - } - } - - for (i = 0; i < config_data->iproutes_len; ++i) - g_ptr_array_add(routes_new, config_data->iproutes_arr[i]); - - addrs_changed = nmcs_setting_ip_replace_ipv4_addresses(s_ip, - (NMIPAddress **) addrs_new->pdata, - addrs_new->len); - - routes_changed = nmcs_setting_ip_replace_ipv4_routes(s_ip, - (NMIPRoute **) routes_new->pdata, - routes_new->len); - - rules_changed = nmcs_setting_ip_replace_ipv4_rules(s_ip, - (NMIPRoutingRule **) rules_new->pdata, - rules_new->len); - - NM_SET_OUT(out_changed, addrs_changed || routes_changed || rules_changed); - return TRUE; -} - -/*****************************************************************************/ - -static guint -_config_data_get_num_valid(GHashTable *config_dict) -{ - const NMCSProviderGetConfigIfaceData *config_data; - GHashTableIter h_iter; - guint n = 0; - - g_hash_table_iter_init(&h_iter, config_dict); - while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &config_data)) { - if (nmcs_provider_get_config_iface_data_is_valid(config_data)) - n++; - } - - return n; -} - -static gboolean -_config_one(GCancellable * sigterm_cancellable, - NMClient * nmc, - gboolean is_single_nic, - const char * hwaddr, - const NMCSProviderGetConfigIfaceData *config_data) -{ - gs_unref_object NMDevice *device = NULL; - gs_unref_object NMConnection *applied_connection = NULL; - guint64 applied_version_id; - gs_free_error GError *error = NULL; - gboolean changed; - gboolean version_id_changed; - guint try_count; - gboolean any_changes = FALSE; - - g_main_context_iteration(NULL, FALSE); - - if (g_cancellable_is_cancelled(sigterm_cancellable)) - return FALSE; - - device = nm_g_object_ref(_nmc_get_device_by_hwaddr(nmc, hwaddr)); - if (!device) { - _LOGD("config device %s: skip because device not found", hwaddr); - return FALSE; - } - - if (!nmcs_provider_get_config_iface_data_is_valid(config_data)) { - _LOGD("config device %s: skip because meta data not successfully fetched", hwaddr); - return FALSE; - } - - _LOGD("config device %s: configuring \"%s\" (%s)...", - hwaddr, - nm_device_get_iface(device) ?: "/unknown/", - nm_object_get_path(NM_OBJECT(device))); - - try_count = 0; - -try_again: - - applied_connection = nmcs_device_get_applied_connection(device, - sigterm_cancellable, - &applied_version_id, - &error); - if (!applied_connection) { - if (!nm_utils_error_is_cancelled(error)) - _LOGD("config device %s: device has no applied connection (%s). Skip", - hwaddr, - error->message); - return any_changes; - } - - if (_nmc_skip_connection(applied_connection)) { - _LOGD("config device %s: skip applied connection due to user data %s", - hwaddr, - USER_TAG_SKIP); - return any_changes; - } - - if (!_nmc_mangle_connection(device, applied_connection, config_data, &changed)) { - _LOGD("config device %s: device has no suitable applied connection. Skip", hwaddr); - return any_changes; - } - - if (!changed) { - _LOGD("config device %s: device needs no update to applied connection \"%s\" (%s). Skip", - hwaddr, - nm_connection_get_id(applied_connection), - nm_connection_get_uuid(applied_connection)); - return any_changes; - } - - _LOGD("config device %s: reapply connection \"%s\" (%s)", - hwaddr, - nm_connection_get_id(applied_connection), - nm_connection_get_uuid(applied_connection)); - - /* we are about to call Reapply(). If if that fails, it counts as if we changed something. */ - any_changes = TRUE; - - if (!nmcs_device_reapply(device, - sigterm_cancellable, - applied_connection, - applied_version_id, - &version_id_changed, - &error)) { - if (version_id_changed && try_count < 5) { - _LOGD("config device %s: applied connection changed in the meantime. Retry...", hwaddr); - g_clear_object(&applied_connection); - g_clear_error(&error); - try_count++; - goto try_again; - } - - if (!nm_utils_error_is_cancelled(error)) { - _LOGD("config device %s: failure to reapply connection \"%s\" (%s): %s", - hwaddr, - nm_connection_get_id(applied_connection), - nm_connection_get_uuid(applied_connection), - error->message); - } - return any_changes; - } - - _LOGD("config device %s: connection \"%s\" (%s) reapplied", - hwaddr, - nm_connection_get_id(applied_connection), - nm_connection_get_uuid(applied_connection)); - - return any_changes; -} - -static gboolean -_config_all(GCancellable *sigterm_cancellable, NMClient *nmc, GHashTable *config_dict) -{ - GHashTableIter h_iter; - const NMCSProviderGetConfigIfaceData *c_config_data; - const char * c_hwaddr; - gboolean is_single_nic; - gboolean any_changes = FALSE; - - is_single_nic = (_config_data_get_num_valid(config_dict) <= 1); - - g_hash_table_iter_init(&h_iter, config_dict); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, (gpointer *) &c_config_data)) { - if (_config_one(sigterm_cancellable, nmc, is_single_nic, c_hwaddr, c_config_data)) - any_changes = TRUE; - } - - return any_changes; -} - -/*****************************************************************************/ - -static gboolean -sigterm_handler(gpointer user_data) -{ - GCancellable *sigterm_cancellable = user_data; - - if (!g_cancellable_is_cancelled(sigterm_cancellable)) { - _LOGD("SIGTERM received"); - g_cancellable_cancel(user_data); - } else - _LOGD("SIGTERM received (again)"); - return G_SOURCE_CONTINUE; -} - -/*****************************************************************************/ - -int -main(int argc, const char *const *argv) -{ - gs_unref_object GCancellable * sigterm_cancellable = NULL; - nm_auto_destroy_and_unref_gsource GSource *sigterm_source = NULL; - gs_unref_object NMCSProvider *provider = NULL; - gs_unref_object NMClient *nmc = NULL; - gs_unref_hashtable GHashTable *config_dict = NULL; - gs_free_error GError *error = NULL; - - _nm_logging_enabled_init(g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_LOG"))); - - _LOGD("nm-cloud-setup %s starting...", NM_DIST_VERSION); - - if (argc != 1) { - g_printerr("%s: no command line arguments supported\n", argv[0]); - return EXIT_FAILURE; - } - - sigterm_cancellable = g_cancellable_new(); - - sigterm_source = nm_g_source_attach(nm_g_unix_signal_source_new(SIGTERM, - G_PRIORITY_DEFAULT, - sigterm_handler, - sigterm_cancellable, - NULL), - NULL); - - provider = _provider_detect(sigterm_cancellable); - if (!provider) - goto done; - - nmc_client_new_waitsync(sigterm_cancellable, - &nmc, - &error, - NM_CLIENT_INSTANCE_FLAGS, - (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS, - NULL); - - nmcs_wait_for_objects_register(nmc); - nmcs_wait_for_objects_register(nm_client_get_context_busy_watcher(nmc)); - - if (error) { - if (!nm_utils_error_is_cancelled(error)) - _LOGI("failure to talk to NetworkManager: %s", error->message); - goto done; - } - - if (!nm_client_get_nm_running(nmc)) { - _LOGI("NetworkManager is not running"); - goto done; - } - - config_dict = _get_config(sigterm_cancellable, provider, nmc); - if (!config_dict) - goto done; - - if (_config_all(sigterm_cancellable, nmc, config_dict)) - _LOGI("some changes were applied for provider %s", nmcs_provider_get_name(provider)); - else - _LOGD("no changes were applied for provider %s", nmcs_provider_get_name(provider)); - -done: - nm_clear_pointer(&config_dict, g_hash_table_unref); - g_clear_object(&nmc); - g_clear_object(&provider); - - if (!nmcs_wait_for_objects_iterate_until_done(NULL, 2000)) { - _LOGE("shutdown: timeout waiting to application to quit. This is a bug"); - nm_assert_not_reached(); - } - - nm_clear_g_source_inst(&sigterm_source); - g_clear_object(&sigterm_cancellable); - - return 0; -} diff --git a/clients/cloud-setup/meson.build b/clients/cloud-setup/meson.build deleted file mode 100644 index 581dde6a..00000000 --- a/clients/cloud-setup/meson.build +++ /dev/null @@ -1,74 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -if install_systemdunitdir - - nm_cloud_setup_service = configure_file( - input: 'nm-cloud-setup.service.in', - output: '@BASENAME@', - install_dir: systemd_systemdsystemunitdir, - configuration: data_conf, - ) - - install_data( - 'nm-cloud-setup.timer', - install_dir: systemd_systemdsystemunitdir, - ) - - install_data( - '90-nm-cloud-setup.sh', - install_dir: join_paths(nm_pkglibdir, 'dispatcher.d', 'no-wait.d'), - ) - -endif - -libnm_cloud_setup_core = static_library( - 'nm-cloud-setup-core', - sources: files( - 'nm-cloud-setup-utils.c', - 'nm-http-client.c', - 'nmcs-provider-ec2.c', - 'nmcs-provider-gcp.c', - 'nmcs-provider-azure.c', - 'nmcs-provider.c', - ), - dependencies: [ - libnmc_base_dep, - libnmc_dep, - libcurl_dep, - libnm_libnm_aux_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="nm-cloud-setup"', - ], -) - -libnm_cloud_setup_core_dep = declare_dependency( - include_directories: include_directories('.'), - link_with: libnm_cloud_setup_core, -) - -executable( - 'nm-cloud-setup', - files( - 'main.c', - ), - dependencies: [ - libnmc_base_dep, - libnmc_dep, - libcurl_dep, - libnm_libnm_aux_dep, - libnm_cloud_setup_core_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="nm-cloud-setup"', - ], - link_with: libnm_systemd_logging_stub, - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir, -) - -if enable_tests - subdir('tests') -endif diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c deleted file mode 100644 index f5550a12..00000000 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ /dev/null @@ -1,902 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nm-cloud-setup-utils.h" - -#include <linux/if_ether.h> -#include <linux/if_infiniband.h> - -#include "nm-glib-aux/nm-time-utils.h" -#include "nm-glib-aux/nm-logging-base.h" -#include "nm-glib-aux/nm-str-buf.h" - -/*****************************************************************************/ - -volatile NMLogLevel _nm_logging_configured_level = LOGL_TRACE; - -void -_nm_logging_enabled_init(const char *level_str) -{ - NMLogLevel level; - - if (!_nm_log_parse_level(level_str, &level)) - level = LOGL_WARN; - else if (level == _LOGL_KEEP) - level = LOGL_WARN; - - _nm_logging_configured_level = level; -} - -void -_nm_log_impl_cs(NMLogLevel level, const char *fmt, ...) -{ - gs_free char *msg = NULL; - va_list ap; - const char * level_str; - gint64 ts; - - va_start(ap, fmt); - msg = g_strdup_vprintf(fmt, ap); - va_end(ap); - - switch (level) { - case LOGL_TRACE: - level_str = "<trace>"; - break; - case LOGL_DEBUG: - level_str = "<debug>"; - break; - case LOGL_INFO: - level_str = "<info> "; - break; - case LOGL_WARN: - level_str = "<warn> "; - break; - default: - nm_assert(level == LOGL_ERR); - level_str = "<error>"; - break; - } - - ts = nm_utils_clock_gettime_nsec(CLOCK_BOOTTIME); - - g_print("[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s %s\n", - ts / NM_UTILS_NSEC_PER_SEC, - (ts / (NM_UTILS_NSEC_PER_SEC / 10000)) % 10000, - level_str, - msg); -} - -void -_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp, - gint64 offset_sec, - gboolean is_boottime) -{} - -/*****************************************************************************/ - -G_LOCK_DEFINE_STATIC(_wait_for_objects_lock); -static GSList *_wait_for_objects_list; -static GSList *_wait_for_objects_iterate_loops; - -static void -_wait_for_objects_maybe_quit_mainloops_with_lock(void) -{ - GSList *iter; - - if (!_wait_for_objects_list) { - for (iter = _wait_for_objects_iterate_loops; iter; iter = iter->next) - g_main_loop_quit(iter->data); - } -} - -static void -_wait_for_objects_weak_cb(gpointer data, GObject *where_the_object_was) -{ - G_LOCK(_wait_for_objects_lock); - nm_assert(g_slist_find(_wait_for_objects_list, where_the_object_was)); - _wait_for_objects_list = g_slist_remove(_wait_for_objects_list, where_the_object_was); - _wait_for_objects_maybe_quit_mainloops_with_lock(); - G_UNLOCK(_wait_for_objects_lock); -} - -/** - * nmcs_wait_for_objects_register: - * @target: a #GObject to wait for. - * - * Registers @target as a pointer to wait during shutdown. Using - * nmcs_wait_for_objects_iterate_until_done() we keep waiting until - * @target gets destroyed, which means that it gets completely unreferenced. - */ -gpointer -nmcs_wait_for_objects_register(gpointer target) -{ - g_return_val_if_fail(G_IS_OBJECT(target), NULL); - - G_LOCK(_wait_for_objects_lock); - _wait_for_objects_list = g_slist_prepend(_wait_for_objects_list, target); - G_UNLOCK(_wait_for_objects_lock); - - g_object_weak_ref(target, _wait_for_objects_weak_cb, NULL); - return target; -} - -typedef struct { - GMainLoop *loop; - gboolean got_timeout; -} WaitForObjectsData; - -static gboolean -_wait_for_objects_iterate_until_done_timeout_cb(gpointer user_data) -{ - WaitForObjectsData *data = user_data; - - data->got_timeout = TRUE; - g_main_loop_quit(data->loop); - return G_SOURCE_CONTINUE; -} - -static gboolean -_wait_for_objects_iterate_until_done_idle_cb(gpointer user_data) -{ - /* This avoids a race where: - * - * - we check whether there are objects to wait for. - * - the last object to wait for gets removed (issuing g_main_loop_quit()). - * - we run the mainloop (and missed our signal). - * - * It's really a missing feature of GMainLoop where the "is-running" flag is always set to - * TRUE by g_main_loop_run(). That means, you cannot catch a g_main_loop_quit() in a race - * free way while not iterating the loop. - * - * Avoid this, by checking once again after we start running the mainloop. - */ - - G_LOCK(_wait_for_objects_lock); - _wait_for_objects_maybe_quit_mainloops_with_lock(); - G_UNLOCK(_wait_for_objects_lock); - return G_SOURCE_REMOVE; -} - -/** - * nmcs_wait_for_objects_iterate_until_done: - * @context: the #GMainContext to iterate. - * @timeout_msec: timeout or -1 for no timeout. - * - * Iterates the provided @context until all objects that we wait for - * are destroyed. - * - * The purpose of this is to cleanup all objects that we have on exit. That - * is especially because objects have asynchronous operations pending that - * should be cancelled and properly completed during exit. - * - * Returns: %FALSE on timeout or %TRUE if all objects destroyed before timeout. - */ -gboolean -nmcs_wait_for_objects_iterate_until_done(GMainContext *context, int timeout_msec) -{ - nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(context, FALSE); - nm_auto_destroy_and_unref_gsource GSource *timeout_source = NULL; - WaitForObjectsData data; - gboolean has_more_objects; - - G_LOCK(_wait_for_objects_lock); - if (!_wait_for_objects_list) { - G_UNLOCK(_wait_for_objects_lock); - return TRUE; - } - _wait_for_objects_iterate_loops = g_slist_prepend(_wait_for_objects_iterate_loops, loop); - G_UNLOCK(_wait_for_objects_lock); - - data = (WaitForObjectsData){ - .loop = loop, - .got_timeout = FALSE, - }; - - if (timeout_msec >= 0) { - timeout_source = nm_g_source_attach( - nm_g_timeout_source_new(timeout_msec, - G_PRIORITY_DEFAULT, - _wait_for_objects_iterate_until_done_timeout_cb, - &data, - NULL), - context); - } - - has_more_objects = TRUE; - while (has_more_objects && !data.got_timeout) { - nm_auto_destroy_and_unref_gsource GSource *idle_source = NULL; - - idle_source = - nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_DEFAULT, - _wait_for_objects_iterate_until_done_idle_cb, - &data, - NULL), - context); - - g_main_loop_run(loop); - - G_LOCK(_wait_for_objects_lock); - has_more_objects = (!!_wait_for_objects_list); - if (data.got_timeout || !has_more_objects) - _wait_for_objects_iterate_loops = g_slist_remove(_wait_for_objects_iterate_loops, loop); - G_UNLOCK(_wait_for_objects_lock); - } - - return !data.got_timeout; -} - -/*****************************************************************************/ - -typedef struct { - GTask * task; - GSource * source_timeout; - GSource * source_next_poll; - GMainContext * context; - GCancellable * internal_cancellable; - NMCSUtilsPollProbeStartFcn probe_start_fcn; - NMCSUtilsPollProbeFinishFcn probe_finish_fcn; - gpointer probe_user_data; - gulong cancellable_id; - gint64 last_poll_start_ms; - int sleep_timeout_ms; - int ratelimit_timeout_ms; - bool completed : 1; -} PollTaskData; - -static void -_poll_task_data_free(gpointer data) -{ - PollTaskData *poll_task_data = data; - - nm_assert(G_IS_TASK(poll_task_data->task)); - nm_assert(!poll_task_data->source_next_poll); - nm_assert(!poll_task_data->source_timeout); - nm_assert(poll_task_data->cancellable_id == 0); - - g_main_context_unref(poll_task_data->context); - - nm_g_slice_free(poll_task_data); -} - -static void -_poll_return(PollTaskData *poll_task_data, GError *error_take) -{ - nm_clear_g_source_inst(&poll_task_data->source_next_poll); - nm_clear_g_source_inst(&poll_task_data->source_timeout); - nm_clear_g_cancellable_disconnect(g_task_get_cancellable(poll_task_data->task), - &poll_task_data->cancellable_id); - - nm_clear_g_cancellable(&poll_task_data->internal_cancellable); - - if (error_take) - g_task_return_error(poll_task_data->task, g_steal_pointer(&error_take)); - else - g_task_return_boolean(poll_task_data->task, TRUE); - - g_object_unref(poll_task_data->task); -} - -static gboolean _poll_start_cb(gpointer user_data); - -static void -_poll_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - PollTaskData * poll_task_data = user_data; - _nm_unused gs_unref_object GTask *task = - poll_task_data->task; /* balance ref from _poll_start_cb() */ - gs_free_error GError *error = NULL; - gint64 now_ms; - gint64 wait_ms; - gboolean is_finished; - - is_finished = - poll_task_data->probe_finish_fcn(source, result, poll_task_data->probe_user_data, &error); - - if (nm_utils_error_is_cancelled(error)) { - /* we already handle this differently. Nothing to do. */ - return; - } - - if (error || is_finished) { - _poll_return(poll_task_data, g_steal_pointer(&error)); - return; - } - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - if (poll_task_data->ratelimit_timeout_ms > 0) - wait_ms = - (poll_task_data->last_poll_start_ms + poll_task_data->ratelimit_timeout_ms) - now_ms; - else - wait_ms = 0; - if (poll_task_data->sleep_timeout_ms > 0) - wait_ms = MAX(wait_ms, poll_task_data->sleep_timeout_ms); - - poll_task_data->source_next_poll = - nm_g_source_attach(nm_g_timeout_source_new(MAX(1, wait_ms), - G_PRIORITY_DEFAULT, - _poll_start_cb, - poll_task_data, - NULL), - poll_task_data->context); -} - -static gboolean -_poll_start_cb(gpointer user_data) -{ - PollTaskData *poll_task_data = user_data; - - nm_clear_g_source_inst(&poll_task_data->source_next_poll); - - poll_task_data->last_poll_start_ms = nm_utils_get_monotonic_timestamp_msec(); - - g_object_ref(poll_task_data->task); /* balanced by _poll_done_cb() */ - - poll_task_data->probe_start_fcn(poll_task_data->internal_cancellable, - poll_task_data->probe_user_data, - _poll_done_cb, - poll_task_data); - - return G_SOURCE_CONTINUE; -} - -static gboolean -_poll_timeout_cb(gpointer user_data) -{ - PollTaskData *poll_task_data = user_data; - - _poll_return(poll_task_data, nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "timeout expired")); - return G_SOURCE_CONTINUE; -} - -static void -_poll_cancelled_cb(GObject *object, gpointer user_data) -{ - PollTaskData *poll_task_data = user_data; - GError * error = NULL; - - nm_clear_g_signal_handler(g_task_get_cancellable(poll_task_data->task), - &poll_task_data->cancellable_id); - nm_utils_error_set_cancelled(&error, FALSE, NULL); - _poll_return(poll_task_data, error); -} - -/** - * nmcs_utils_poll: - * @poll_timeout_ms: if >= 0, then this is the overall timeout for how long we poll. - * When this timeout expires, the request completes with failure (and error set). - * @ratelimit_timeout_ms: if > 0, we ratelimit the starts from one prope_start_fcn - * call to the next. - * @sleep_timeout_ms: if > 0, then we wait after a probe finished this timeout - * before the next. Together with @ratelimit_timeout_ms this determines how - * frequently we probe. - * @probe_start_fcn: used to start a (asynchronous) probe. A probe must be completed - * by calling the provided callback. While a probe is in progress, we will not - * start another. This function is already invoked the first time synchronously, - * during nmcs_utils_poll(). - * @probe_finish_fcn: will be called from the callback of @probe_start_fcn. If the - * function returns %TRUE (polling done) or an error, polling stops. Otherwise, - * another poll will be started. - * @probe_user_data: user_data for the probe functions. - * @cancellable: cancellable for polling. - * @callback: when polling completes. - * @user_data: for @callback. - * - * This uses the current g_main_context_get_thread_default() for scheduling - * actions. - */ -void -nmcs_utils_poll(int poll_timeout_ms, - int ratelimit_timeout_ms, - int sleep_timeout_ms, - NMCSUtilsPollProbeStartFcn probe_start_fcn, - NMCSUtilsPollProbeFinishFcn probe_finish_fcn, - gpointer probe_user_data, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PollTaskData *poll_task_data; - - poll_task_data = g_slice_new(PollTaskData); - *poll_task_data = (PollTaskData){ - .task = nm_g_task_new(NULL, cancellable, nmcs_utils_poll, callback, user_data), - .probe_start_fcn = probe_start_fcn, - .probe_finish_fcn = probe_finish_fcn, - .probe_user_data = probe_user_data, - .completed = FALSE, - .context = g_main_context_ref_thread_default(), - .sleep_timeout_ms = sleep_timeout_ms, - .ratelimit_timeout_ms = ratelimit_timeout_ms, - .internal_cancellable = g_cancellable_new(), - }; - - nmcs_wait_for_objects_register(poll_task_data->task); - - g_task_set_task_data(poll_task_data->task, poll_task_data, _poll_task_data_free); - - if (poll_timeout_ms >= 0) { - poll_task_data->source_timeout = - nm_g_source_attach(nm_g_timeout_source_new(poll_timeout_ms, - G_PRIORITY_DEFAULT, - _poll_timeout_cb, - poll_task_data, - NULL), - poll_task_data->context); - } - - poll_task_data->source_next_poll = nm_g_source_attach( - nm_g_idle_source_new(G_PRIORITY_DEFAULT, _poll_start_cb, poll_task_data, NULL), - poll_task_data->context); - - if (cancellable) { - gulong signal_id; - - signal_id = g_cancellable_connect(cancellable, - G_CALLBACK(_poll_cancelled_cb), - poll_task_data, - NULL); - if (signal_id == 0) { - /* the request is already cancelled. Return. */ - return; - } - poll_task_data->cancellable_id = signal_id; - } -} - -/** - * nmcs_utils_poll_finish: - * @result: the GAsyncResult from the GAsyncReadyCallback callback. - * @probe_user_data: the user data provided to nmcs_utils_poll(). - * @error: the failure code. - * - * Returns: %TRUE if the polling completed with success. In that case, - * the error won't be set. - * If the request was cancelled, this is indicated by @error and - * %FALSE will be returned. - * If the probe returned a failure, this returns %FALSE and the error - * provided by @probe_finish_fcn. - * If the request times out, this returns %FALSE with error set. - * Error is always set if (and only if) the function returns %FALSE. - */ -gboolean -nmcs_utils_poll_finish(GAsyncResult *result, gpointer *probe_user_data, GError **error) -{ - GTask * task; - PollTaskData *poll_task_data; - - g_return_val_if_fail(nm_g_task_is_valid(result, NULL, nmcs_utils_poll), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - task = G_TASK(result); - - if (probe_user_data) { - poll_task_data = g_task_get_task_data(task); - NM_SET_OUT(probe_user_data, poll_task_data->probe_user_data); - } - - return g_task_propagate_boolean(task, error); -} - -/*****************************************************************************/ - -char * -nmcs_utils_hwaddr_normalize(const char *hwaddr, gssize len) -{ - gs_free char *hwaddr_clone = NULL; - char * hw; - guint8 buf[ETH_ALEN]; - gsize l; - - nm_assert(len >= -1); - - if (len < 0) { - if (!hwaddr) - return NULL; - l = strlen(hwaddr); - } else { - l = len; - if (l > 0 && hwaddr[l - 1] == '\0') { - /* we accept one '\0' at the end of the string. */ - l--; - } - if (memchr(hwaddr, '\0', l)) { - /* but we don't accept other NUL characters in the middle. */ - return NULL; - } - } - - if (l == 0) - return NULL; - - nm_assert(hwaddr); - hw = nm_strndup_a(300, hwaddr, l, &hwaddr_clone); - - g_strstrip(hw); - - /* we cannot use _nm_utils_hwaddr_aton() because that requires a delimiter. - * Azure exposes MAC addresses without delimiter, so accept that too. */ - if (!nm_utils_hexstr2bin_full(hw, - FALSE, - FALSE, - FALSE, - ":-", - sizeof(buf), - buf, - sizeof(buf), - NULL)) - return NULL; - - return nm_utils_hwaddr_ntoa(buf, sizeof(buf)); -} - -/*****************************************************************************/ - -gboolean -nmcs_utils_ipaddr_normalize_bin(int addr_family, - const char *addr, - gssize len, - int * out_addr_family, - gpointer out_addr_bin) -{ - gs_free char *addr_clone = NULL; - char * ad; - gsize l; - - nm_assert(len >= -1); - - if (len < 0) { - if (!addr) - return FALSE; - l = strlen(addr); - } else { - l = len; - if (l > 0 && addr[l - 1] == '\0') { - /* we accept one '\0' at the end of the string. */ - l--; - } - if (memchr(addr, '\0', l)) { - /* but we don't accept other NUL characters in the middle. */ - return FALSE; - } - } - - if (l == 0) - return FALSE; - - nm_assert(addr); - ad = nm_strndup_a(300, addr, l, &addr_clone); - - g_strstrip(ad); - - return nm_utils_parse_inaddr_bin(addr_family, ad, out_addr_family, out_addr_bin); -} - -char * -nmcs_utils_ipaddr_normalize(int addr_family, const char *addr, gssize len) -{ - NMIPAddr ipaddr; - - if (!nmcs_utils_ipaddr_normalize_bin(addr_family, addr, len, &addr_family, &ipaddr)) - return NULL; - - return nm_utils_inet_ntop_dup(addr_family, &ipaddr); -} - -/*****************************************************************************/ - -const char * -nmcs_utils_parse_memmem(GBytes *mem, const char *needle) -{ - const char *mem_data; - gsize mem_size; - - g_return_val_if_fail(mem, NULL); - g_return_val_if_fail(needle, NULL); - - mem_data = g_bytes_get_data(mem, &mem_size); - return memmem(mem_data, mem_size, needle, strlen(needle)); -} - -const char * -nmcs_utils_parse_get_full_line(GBytes *mem, const char *needle) -{ - const char *mem_data; - gsize mem_size; - gsize c; - gsize l; - - const char *line; - - line = nmcs_utils_parse_memmem(mem, needle); - if (!line) - return NULL; - - mem_data = g_bytes_get_data(mem, &mem_size); - - if (line != mem_data && line[-1] != '\n') { - /* the line must be preceeded either by the begin of the data or - * by a newline. */ - return NULL; - } - - c = mem_size - (line - mem_data); - l = strlen(needle); - - if (c != l && line[l] != '\n') { - /* the end of the needle must be either a newline or the end of the buffer. */ - return NULL; - } - - return line; -} - -/*****************************************************************************/ - -char * -nmcs_utils_uri_build_concat_v(const char *base, const char **components, gsize n_components) -{ - NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); - - nm_assert(base); - nm_assert(base[0]); - nm_assert(!NM_STR_HAS_SUFFIX(base, "/")); - - nm_str_buf_append(&strbuf, base); - - if (n_components > 0 && components[0] && components[0][0] == '/') { - /* the first component starts with a slash. We allow that, and don't add a duplicate - * slash. Otherwise, we add a separator after base. - * - * We only do that for the first component. */ - } else - nm_str_buf_append_c(&strbuf, '/'); - - while (n_components > 0) { - if (!components[0]) { - /* we allow NULL, to indicate nothing to append */ - } else - nm_str_buf_append(&strbuf, components[0]); - components++; - n_components--; - } - - return nm_str_buf_finalize(&strbuf, NULL); -} - -/*****************************************************************************/ - -gboolean -nmcs_setting_ip_replace_ipv4_addresses(NMSettingIPConfig *s_ip, - NMIPAddress ** entries_arr, - guint entries_len) -{ - gboolean any_changes = FALSE; - guint i_next; - guint num; - guint i; - - num = nm_setting_ip_config_get_num_addresses(s_ip); - - i_next = 0; - - for (i = 0; i < entries_len; i++) { - NMIPAddress *entry = entries_arr[i]; - - if (!any_changes) { - if (i_next < num) { - if (nm_ip_address_cmp_full(entry, - nm_setting_ip_config_get_address(s_ip, i_next), - NM_IP_ADDRESS_CMP_FLAGS_WITH_ATTRS) - == 0) { - i_next++; - continue; - } - } - while (i_next < num) - nm_setting_ip_config_remove_address(s_ip, --num); - any_changes = TRUE; - } - - if (!nm_setting_ip_config_add_address(s_ip, entry)) - continue; - - i_next++; - } - if (!any_changes) { - while (i_next < num) { - nm_setting_ip_config_remove_address(s_ip, --num); - any_changes = TRUE; - } - } - - return any_changes; -} - -gboolean -nmcs_setting_ip_replace_ipv4_routes(NMSettingIPConfig *s_ip, - NMIPRoute ** entries_arr, - guint entries_len) -{ - gboolean any_changes = FALSE; - guint i_next; - guint num; - guint i; - - num = nm_setting_ip_config_get_num_routes(s_ip); - - i_next = 0; - - for (i = 0; i < entries_len; i++) { - NMIPRoute *entry = entries_arr[i]; - - if (!any_changes) { - if (i_next < num) { - if (nm_ip_route_equal_full(entry, - nm_setting_ip_config_get_route(s_ip, i_next), - NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS)) { - i_next++; - continue; - } - } - while (i_next < num) - nm_setting_ip_config_remove_route(s_ip, --num); - any_changes = TRUE; - } - - if (!nm_setting_ip_config_add_route(s_ip, entry)) - continue; - - i_next++; - } - if (!any_changes) { - while (i_next < num) { - nm_setting_ip_config_remove_route(s_ip, --num); - any_changes = TRUE; - } - } - - return any_changes; -} - -gboolean -nmcs_setting_ip_replace_ipv4_rules(NMSettingIPConfig *s_ip, - NMIPRoutingRule ** entries_arr, - guint entries_len) -{ - gboolean any_changes = FALSE; - guint i_next; - guint num; - guint i; - - num = nm_setting_ip_config_get_num_routing_rules(s_ip); - - i_next = 0; - - for (i = 0; i < entries_len; i++) { - NMIPRoutingRule *entry = entries_arr[i]; - - if (!any_changes) { - if (i_next < num) { - if (nm_ip_routing_rule_cmp(entry, - nm_setting_ip_config_get_routing_rule(s_ip, i_next)) - == 0) { - i_next++; - continue; - } - } - while (i_next < num) - nm_setting_ip_config_remove_routing_rule(s_ip, --num); - any_changes = TRUE; - } - - nm_setting_ip_config_add_routing_rule(s_ip, entry); - i_next++; - } - if (!any_changes) { - while (i_next < num) { - nm_setting_ip_config_remove_routing_rule(s_ip, --num); - any_changes = TRUE; - } - } - - return any_changes; -} - -/*****************************************************************************/ - -typedef struct { - GMainLoop * main_loop; - NMConnection *connection; - GError * error; - guint64 version_id; -} DeviceGetAppliedConnectionData; - -static void -_nmcs_device_get_applied_connection_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - DeviceGetAppliedConnectionData *data = user_data; - - data->connection = nm_device_get_applied_connection_finish(NM_DEVICE(source), - result, - &data->version_id, - &data->error); - g_main_loop_quit(data->main_loop); -} - -NMConnection * -nmcs_device_get_applied_connection(NMDevice * device, - GCancellable *cancellable, - guint64 * version_id, - GError ** error) -{ - nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); - DeviceGetAppliedConnectionData data = { - .main_loop = main_loop, - }; - - nm_device_get_applied_connection_async(device, - 0, - cancellable, - _nmcs_device_get_applied_connection_cb, - &data); - - g_main_loop_run(main_loop); - - if (data.error) - g_propagate_error(error, data.error); - NM_SET_OUT(version_id, data.version_id); - return data.connection; -} - -/*****************************************************************************/ - -typedef struct { - GMainLoop *main_loop; - GError * error; -} DeviceReapplyData; - -static void -_nmcs_device_reapply_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - DeviceReapplyData *data = user_data; - - nm_device_reapply_finish(NM_DEVICE(source), result, &data->error); - g_main_loop_quit(data->main_loop); -} - -gboolean -nmcs_device_reapply(NMDevice * device, - GCancellable *sigterm_cancellable, - NMConnection *connection, - guint64 version_id, - gboolean * out_version_id_changed, - GError ** error) -{ - nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); - DeviceReapplyData data = { - .main_loop = main_loop, - }; - - nm_device_reapply_async(device, - connection, - version_id, - 0, - sigterm_cancellable, - _nmcs_device_reapply_cb, - &data); - - g_main_loop_run(main_loop); - - if (data.error) { - NM_SET_OUT( - out_version_id_changed, - g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH)); - g_propagate_error(error, data.error); - return FALSE; - } - - NM_SET_OUT(out_version_id_changed, FALSE); - return TRUE; -} diff --git a/clients/cloud-setup/nm-cloud-setup-utils.h b/clients/cloud-setup/nm-cloud-setup-utils.h deleted file mode 100644 index 52edd279..00000000 --- a/clients/cloud-setup/nm-cloud-setup-utils.h +++ /dev/null @@ -1,152 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NM_CLOUD_SETUP_UTILS_H__ -#define __NM_CLOUD_SETUP_UTILS_H__ - -#include "nm-glib-aux/nm-logging-fwd.h" - -/*****************************************************************************/ - -/* mark names for variables that can be used as configuration. Search - * for NMCS_ENV_VARIABLE() to find all honored environment variables. */ -#define NMCS_ENV_VARIABLE(var) "" var "" - -/*****************************************************************************/ - -extern volatile NMLogLevel _nm_logging_configured_level; - -static inline gboolean -nm_logging_enabled(NMLogLevel level) -{ - return level >= _nm_logging_configured_level; -} - -void _nm_logging_enabled_init(const char *level_str); - -void _nm_log_impl_cs(NMLogLevel level, const char *fmt, ...) _nm_printf(2, 3); - -#define _nm_log(level, ...) _nm_log_impl_cs((level), __VA_ARGS__); - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level)) { \ - _nm_log(_level, __VA_ARGS__); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -#ifndef NM_DIST_VERSION - #define NM_DIST_VERSION VERSION -#endif - -/*****************************************************************************/ - -gpointer nmcs_wait_for_objects_register(gpointer target); - -gboolean nmcs_wait_for_objects_iterate_until_done(GMainContext *context, int timeout_msec); - -/*****************************************************************************/ - -typedef void (*NMCSUtilsPollProbeStartFcn)(GCancellable * cancellable, - gpointer probe_user_data, - GAsyncReadyCallback callback, - gpointer user_data); - -typedef gboolean (*NMCSUtilsPollProbeFinishFcn)(GObject * source, - GAsyncResult *result, - gpointer probe_user_data, - GError ** error); - -void nmcs_utils_poll(int poll_timeout_ms, - int ratelimit_timeout_ms, - int sleep_timeout_ms, - NMCSUtilsPollProbeStartFcn probe_start_fcn, - NMCSUtilsPollProbeFinishFcn probe_finish_fcn, - gpointer probe_user_data, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean nmcs_utils_poll_finish(GAsyncResult *result, gpointer *probe_user_data, GError **error); - -/*****************************************************************************/ - -char *nmcs_utils_hwaddr_normalize(const char *hwaddr, gssize len); - -static inline char * -nmcs_utils_hwaddr_normalize_gbytes(GBytes *hwaddr) -{ - const char *str; - gsize len; - - str = g_bytes_get_data(hwaddr, &len); - return nmcs_utils_hwaddr_normalize(str, len); -} - -/*****************************************************************************/ - -gboolean nmcs_utils_ipaddr_normalize_bin(int addr_family, - const char *addr, - gssize len, - int * out_addr_family, - gpointer out_addr_bin); - -char *nmcs_utils_ipaddr_normalize(int addr_family, const char *addr, gssize len); - -static inline char * -nmcs_utils_ipaddr_normalize_gbytes(int addr_family, GBytes *addr) -{ - const char *str; - gsize len; - - str = g_bytes_get_data(addr, &len); - return nmcs_utils_ipaddr_normalize(addr_family, str, len); -} - -/*****************************************************************************/ - -const char *nmcs_utils_parse_memmem(GBytes *mem, const char *needle); - -const char *nmcs_utils_parse_get_full_line(GBytes *mem, const char *needle); - -/*****************************************************************************/ - -char *nmcs_utils_uri_build_concat_v(const char *base, const char **components, gsize n_components); - -#define nmcs_utils_uri_build_concat(base, ...) \ - nmcs_utils_uri_build_concat_v(base, ((const char *[]){__VA_ARGS__}), NM_NARG(__VA_ARGS__)) - -/*****************************************************************************/ - -gboolean nmcs_setting_ip_replace_ipv4_addresses(NMSettingIPConfig *s_ip, - NMIPAddress ** entries_arr, - guint entries_len); - -gboolean nmcs_setting_ip_replace_ipv4_routes(NMSettingIPConfig *s_ip, - NMIPRoute ** entries_arr, - guint entries_len); - -gboolean nmcs_setting_ip_replace_ipv4_rules(NMSettingIPConfig *s_ip, - NMIPRoutingRule ** entries_arr, - guint entries_len); - -/*****************************************************************************/ - -NMConnection *nmcs_device_get_applied_connection(NMDevice * device, - GCancellable *cancellable, - guint64 * version_id, - GError ** error); - -gboolean nmcs_device_reapply(NMDevice * device, - GCancellable *sigterm_cancellable, - NMConnection *connection, - guint64 version_id, - gboolean * out_version_id_changed, - GError ** error); - -#endif /* __NM_CLOUD_SETUP_UTILS_H__ */ diff --git a/clients/cloud-setup/nm-cloud-setup.service.in b/clients/cloud-setup/nm-cloud-setup.service.in deleted file mode 100644 index 809f707d..00000000 --- a/clients/cloud-setup/nm-cloud-setup.service.in +++ /dev/null @@ -1,42 +0,0 @@ -[Unit] -Description=Automatically configure NetworkManager in cloud -Documentation=man:nm-cloud-setup(8) -After=NetworkManager.service - -[Service] -Type=oneshot -ExecStart=@libexecdir@/nm-cloud-setup - -#Environment=NM_CLOUD_SETUP_LOG=TRACE - -# Cloud providers are disabled by default. You need to -# Opt-in by setting the right environment variable for -# the provider. -# -# Create a drop-in file to overwrite these variables or -# use systemctl edit. -#Environment=NM_CLOUD_SETUP_EC2=yes -#Environment=NM_CLOUD_SETUP_GCP=yes -#Environment=NM_CLOUD_SETUP_AZURE=yes - -CapabilityBoundingSet= -LockPersonality=yes -MemoryDenyWriteExecute=yes -NoNewPrivileges=yes -PrivateDevices=yes -PrivateTmp=yes -ProtectControlGroups=yes -ProtectHome=yes -ProtectHostname=yes -ProtectKernelLogs=yes -ProtectKernelModules=yes -ProtectKernelTunables=yes -ProtectSystem=strict -RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 -RestrictNamespaces=yes -RestrictRealtime=yes -RestrictSUIDSGID=yes -SystemCallFilter=@system-service - -[Install] -WantedBy=NetworkManager.service diff --git a/clients/cloud-setup/nm-cloud-setup.timer b/clients/cloud-setup/nm-cloud-setup.timer deleted file mode 100644 index fd1722a6..00000000 --- a/clients/cloud-setup/nm-cloud-setup.timer +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Periodically run nm-cloud-setup - -[Timer] -OnBootSec=5min -OnUnitActiveSec=5min - -[Install] -WantedBy=timers.target diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c deleted file mode 100644 index 144513fc..00000000 --- a/clients/cloud-setup/nm-http-client.c +++ /dev/null @@ -1,801 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nm-http-client.h" - -#include <curl/curl.h> - -#include "nm-cloud-setup-utils.h" -#include "nm-glib-aux/nm-str-buf.h" - -#define NM_CURL_DEBUG 0 - -/*****************************************************************************/ - -typedef struct { - GMainContext *context; - CURLM * mhandle; - GSource * mhandle_source_timeout; - GHashTable * source_sockets_hashtable; -} NMHttpClientPrivate; - -struct _NMHttpClient { - GObject parent; - NMHttpClientPrivate _priv; -}; - -struct _NMHttpClientClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMHttpClient, nm_http_client, G_TYPE_OBJECT); - -#define NM_HTTP_CLIENT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMHttpClient, NM_IS_HTTP_CLIENT) - -/*****************************************************************************/ - -#define _NMLOG2(level, edata, ...) \ - G_STMT_START \ - { \ - EHandleData *_edata = (edata); \ - \ - _NMLOG(level, \ - "http-request[" NM_HASH_OBFUSCATE_PTR_FMT \ - ", \"%s\"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_HASH_OBFUSCATE_PTR(_edata), \ - (_edata)->url _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -G_LOCK_DEFINE_STATIC(_my_curl_initalized_lock); -static bool _my_curl_initialized = FALSE; - -__attribute__((destructor)) static void -_my_curl_global_cleanup(void) -{ - G_LOCK(_my_curl_initalized_lock); - if (_my_curl_initialized) { - _my_curl_initialized = FALSE; - curl_global_cleanup(); - } - G_UNLOCK(_my_curl_initalized_lock); -} - -static void -nm_http_client_curl_global_init(void) -{ - G_LOCK(_my_curl_initalized_lock); - if (!_my_curl_initialized) { - _my_curl_initialized = TRUE; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - /* Even if this fails, we are partly initialized. WTF. */ - _LOGE("curl: curl_global_init() failed!"); - } - } - G_UNLOCK(_my_curl_initalized_lock); -} - -/*****************************************************************************/ - -GMainContext * -nm_http_client_get_main_context(NMHttpClient *self) -{ - g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), NULL); - - return NM_HTTP_CLIENT_GET_PRIVATE(self)->context; -} - -/*****************************************************************************/ - -static GSource * -_source_attach(NMHttpClient *self, GSource *source) -{ - return nm_g_source_attach(source, NM_HTTP_CLIENT_GET_PRIVATE(self)->context); -} - -/*****************************************************************************/ - -typedef struct { - long response_code; - GBytes *response_data; -} GetResult; - -static void -_get_result_free(gpointer data) -{ - GetResult *get_result = data; - - g_bytes_unref(get_result->response_data); - nm_g_slice_free(get_result); -} - -typedef struct { - GTask * task; - GSource * timeout_source; - CURLcode ehandle_result; - CURL * ehandle; - char * url; - NMStrBuf recv_data; - struct curl_slist *headers; - gssize max_data; - gulong cancellable_id; -} EHandleData; - -static void -_ehandle_free_ehandle(EHandleData *edata) -{ - if (edata->ehandle) { - NMHttpClient * self = g_task_get_source_object(edata->task); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - curl_multi_remove_handle(priv->mhandle, edata->ehandle); - curl_easy_cleanup(g_steal_pointer(&edata->ehandle)); - } -} - -static void -_ehandle_free(EHandleData *edata) -{ - nm_assert(!edata->ehandle); - nm_assert(!edata->timeout_source); - - g_object_unref(edata->task); - - nm_str_buf_destroy(&edata->recv_data); - if (edata->headers) - curl_slist_free_all(edata->headers); - g_free(edata->url); - nm_g_slice_free(edata); -} - -static void -_ehandle_complete(EHandleData *edata, GError *error_take) -{ - GetResult * get_result; - gs_free char *str_tmp_1 = NULL; - long response_code = -1; - - nm_clear_pointer(&edata->timeout_source, nm_g_source_destroy_and_unref); - - nm_clear_g_cancellable_disconnect(g_task_get_cancellable(edata->task), &edata->cancellable_id); - - if (error_take) { - if (nm_utils_error_is_cancelled(error_take)) - _LOG2T(edata, "cancelled"); - else - _LOG2D(edata, "failed with %s", error_take->message); - } else if (edata->ehandle_result != CURLE_OK) { - _LOG2D(edata, "failed with curl error \"%s\"", curl_easy_strerror(edata->ehandle_result)); - nm_utils_error_set(&error_take, - NM_UTILS_ERROR_UNKNOWN, - "failed with curl error \"%s\"", - curl_easy_strerror(edata->ehandle_result)); - } - - if (error_take) { - _ehandle_free_ehandle(edata); - g_task_return_error(edata->task, error_take); - _ehandle_free(edata); - return; - } - - if (curl_easy_getinfo(edata->ehandle, CURLINFO_RESPONSE_CODE, &response_code) != CURLE_OK) - _LOG2E(edata, "failed to get response code from curl easy handle"); - - _LOG2D(edata, - "success getting %" G_GSIZE_FORMAT " bytes (response code %ld)", - edata->recv_data.len, - response_code); - - _LOG2T(edata, - "received %" G_GSIZE_FORMAT " bytes: [[%s]]", - edata->recv_data.len, - nm_utils_buf_utf8safe_escape(nm_str_buf_get_str(&edata->recv_data), - edata->recv_data.len, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, - &str_tmp_1)); - - _ehandle_free_ehandle(edata); - - get_result = g_slice_new(GetResult); - *get_result = (GetResult){ - .response_code = response_code, - /* This ensures that response_data is always NUL terminated. This is an important guarantee - * that NMHttpClient makes. */ - .response_data = nm_str_buf_finalize_to_gbytes(&edata->recv_data), - }; - - g_task_return_pointer(edata->task, get_result, _get_result_free); - - _ehandle_free(edata); -} - -/*****************************************************************************/ - -static size_t -_get_writefunction_cb(char *ptr, size_t size, size_t nmemb, void *user_data) -{ - EHandleData *edata = user_data; - gsize nconsume; - - /* size should always be 1, but still. Multiply them to be sure. */ - nmemb *= size; - - if (edata->max_data >= 0) { - nm_assert(edata->recv_data.len <= edata->max_data); - nconsume = (((gsize) edata->max_data) - edata->recv_data.len); - if (nconsume > nmemb) - nconsume = nmemb; - } else - nconsume = nmemb; - - nm_str_buf_append_len(&edata->recv_data, ptr, nconsume); - return nconsume; -} - -static gboolean -_get_timeout_cb(gpointer user_data) -{ - _ehandle_complete( - user_data, - g_error_new_literal(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "HTTP request timed out")); - return G_SOURCE_REMOVE; -} - -static void -_get_cancelled_cb(GObject *object, gpointer user_data) -{ - EHandleData *edata = user_data; - GError * error = NULL; - - nm_clear_g_signal_handler(g_task_get_cancellable(edata->task), &edata->cancellable_id); - nm_utils_error_set_cancelled(&error, FALSE, NULL); - _ehandle_complete(edata, error); -} - -void -nm_http_client_get(NMHttpClient * self, - const char * url, - int timeout_msec, - gssize max_data, - const char *const * http_headers, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMHttpClientPrivate *priv; - EHandleData * edata; - guint i; - - g_return_if_fail(NM_IS_HTTP_CLIENT(self)); - g_return_if_fail(url); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - g_return_if_fail(timeout_msec >= 0); - g_return_if_fail(max_data >= -1); - - priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - edata = g_slice_new(EHandleData); - *edata = (EHandleData){ - .task = nm_g_task_new(self, cancellable, nm_http_client_get, callback, user_data), - .recv_data = NM_STR_BUF_INIT(0, FALSE), - .max_data = max_data, - .url = g_strdup(url), - .headers = NULL, - }; - - nmcs_wait_for_objects_register(edata->task); - - _LOG2D(edata, "start get ..."); - - edata->ehandle = curl_easy_init(); - if (!edata->ehandle) { - _ehandle_complete(edata, - g_error_new_literal(NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "HTTP request failed to create curl handle")); - return; - } - - curl_easy_setopt(edata->ehandle, CURLOPT_URL, url); - - curl_easy_setopt(edata->ehandle, CURLOPT_WRITEFUNCTION, _get_writefunction_cb); - curl_easy_setopt(edata->ehandle, CURLOPT_WRITEDATA, edata); - curl_easy_setopt(edata->ehandle, CURLOPT_PRIVATE, edata); - - if (http_headers) { - for (i = 0; http_headers[i]; ++i) { - struct curl_slist *tmp; - - tmp = curl_slist_append(edata->headers, http_headers[i]); - if (!tmp) { - curl_slist_free_all(tmp); - _LOGE("curl: curl_slist_append() failed adding %s", http_headers[i]); - continue; - } - edata->headers = tmp; - } - - curl_easy_setopt(edata->ehandle, CURLOPT_HTTPHEADER, edata->headers); - } - - if (timeout_msec > 0) { - edata->timeout_source = _source_attach(self, - nm_g_timeout_source_new(timeout_msec, - G_PRIORITY_DEFAULT, - _get_timeout_cb, - edata, - NULL)); - } - - curl_multi_add_handle(priv->mhandle, edata->ehandle); - - if (cancellable) { - gulong signal_id; - - signal_id = g_cancellable_connect(cancellable, G_CALLBACK(_get_cancelled_cb), edata, NULL); - if (signal_id == 0) { - /* the request is already cancelled. Return. */ - return; - } - edata->cancellable_id = signal_id; - } -} - -/** - * nm_http_client_get_finish: - * @self: the #NMHttpClient instance - * @result: the #GAsyncResult which to complete. - * @out_response_code: (allow-none) (out): the HTTP response code or -1 on other error. - * @out_response_data: (allow-none) (transfer full): the HTTP response data, if any. - * The GBytes buffer is guaranteed to have a trailing NUL character *after* the - * returned buffer size. That means, you can always trust that the buffer is NUL terminated - * and that there is one additional hidden byte after the data. - * Also, the returned buffer is allocated just for you. While GBytes is immutable, you are - * allowed to modify the buffer as it's not used by anybody else. - * @error: the error - * - * Returns: %TRUE on success or %FALSE with an error code. - */ -gboolean -nm_http_client_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error) -{ - GetResult *get_result; - - g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_get), FALSE); - - get_result = g_task_propagate_pointer(G_TASK(result), error); - - nm_assert(!error || (!!get_result) == (!*error)); - - if (!get_result) { - NM_SET_OUT(out_response_code, -1); - NM_SET_OUT(out_response_data, NULL); - return FALSE; - } - - NM_SET_OUT(out_response_code, get_result->response_code); - - /* response_data is binary, but is also guaranteed to be NUL terminated! */ - NM_SET_OUT(out_response_data, g_steal_pointer(&get_result->response_data)); - - _get_result_free(get_result); - return TRUE; -} - -/*****************************************************************************/ - -typedef struct { - GTask * task; - char * uri; - const char *const * http_headers; - NMHttpClientPollGetCheckFcn check_fcn; - gpointer check_user_data; - GBytes * response_data; - gsize request_max_data; - long response_code; - int request_timeout_ms; -} PollGetData; - -static void -_poll_get_data_free(gpointer data) -{ - PollGetData *poll_get_data = data; - - g_free(poll_get_data->uri); - - nm_clear_pointer(&poll_get_data->response_data, g_bytes_unref); - g_strfreev((char **) poll_get_data->http_headers); - - nm_g_slice_free(poll_get_data); -} - -static void -_poll_get_probe_start_fcn(GCancellable * cancellable, - gpointer probe_user_data, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PollGetData *poll_get_data = probe_user_data; - - /* balanced by _poll_get_probe_finish_fcn() */ - g_object_ref(poll_get_data->task); - - nm_http_client_get(g_task_get_source_object(poll_get_data->task), - poll_get_data->uri, - poll_get_data->request_timeout_ms, - poll_get_data->request_max_data, - poll_get_data->http_headers, - cancellable, - callback, - user_data); -} - -static gboolean -_poll_get_probe_finish_fcn(GObject * source, - GAsyncResult *result, - gpointer probe_user_data, - GError ** error) -{ - PollGetData * poll_get_data = probe_user_data; - _nm_unused gs_unref_object GTask *task = - poll_get_data->task; /* balance ref from _poll_get_probe_start_fcn() */ - gboolean success; - gs_free_error GError *local_error = NULL; - gs_unref_bytes GBytes *response_data = NULL; - long response_code = -1; - - success = nm_http_client_get_finish(g_task_get_source_object(poll_get_data->task), - result, - &response_code, - &response_data, - &local_error); - - nm_assert((!!success) == (!local_error)); - - if (local_error) { - if (nm_utils_error_is_cancelled(local_error)) { - g_propagate_error(error, g_steal_pointer(&local_error)); - return TRUE; - } - /* any other error. Continue polling. */ - return FALSE; - } - - if (poll_get_data->check_fcn) { - success = poll_get_data->check_fcn(response_code, - response_data, - poll_get_data->check_user_data, - &local_error); - } else - success = (response_code == 200); - - if (local_error) { - g_propagate_error(error, g_steal_pointer(&local_error)); - return TRUE; - } - - if (!success) { - /* Not yet ready. Continue polling. */ - return FALSE; - } - - poll_get_data->response_code = response_code; - poll_get_data->response_data = g_steal_pointer(&response_data); - return TRUE; -} - -static void -_poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - PollGetData * poll_get_data = user_data; - gs_free_error GError *error = NULL; - gboolean success; - - success = nmcs_utils_poll_finish(result, NULL, &error); - - nm_assert((!!success) == (!error)); - - if (error) - g_task_return_error(poll_get_data->task, g_steal_pointer(&error)); - else - g_task_return_boolean(poll_get_data->task, TRUE); - - g_object_unref(poll_get_data->task); -} - -void -nm_http_client_poll_get(NMHttpClient * self, - const char * uri, - int request_timeout_ms, - gssize request_max_data, - int poll_timeout_ms, - int ratelimit_timeout_ms, - const char *const * http_headers, - GCancellable * cancellable, - NMHttpClientPollGetCheckFcn check_fcn, - gpointer check_user_data, - GAsyncReadyCallback callback, - gpointer user_data) -{ - nm_auto_pop_gmaincontext GMainContext *context = NULL; - PollGetData * poll_get_data; - - g_return_if_fail(NM_IS_HTTP_CLIENT(self)); - g_return_if_fail(uri && uri[0]); - g_return_if_fail(request_timeout_ms >= -1); - g_return_if_fail(request_max_data >= -1); - g_return_if_fail(poll_timeout_ms >= -1); - g_return_if_fail(ratelimit_timeout_ms >= -1); - g_return_if_fail(!cancellable || G_CANCELLABLE(cancellable)); - - poll_get_data = g_slice_new(PollGetData); - *poll_get_data = (PollGetData){ - .task = nm_g_task_new(self, cancellable, nm_http_client_poll_get, callback, user_data), - .uri = g_strdup(uri), - .request_timeout_ms = request_timeout_ms, - .request_max_data = request_max_data, - .check_fcn = check_fcn, - .check_user_data = check_user_data, - .response_code = -1, - .http_headers = NM_CAST_STRV_CC(g_strdupv((char **) http_headers)), - }; - - nmcs_wait_for_objects_register(poll_get_data->task); - - g_task_set_task_data(poll_get_data->task, poll_get_data, _poll_get_data_free); - - context = - nm_g_main_context_push_thread_default_if_necessary(nm_http_client_get_main_context(self)); - - nmcs_utils_poll(poll_timeout_ms, - ratelimit_timeout_ms, - 0, - _poll_get_probe_start_fcn, - _poll_get_probe_finish_fcn, - poll_get_data, - cancellable, - _poll_get_done_cb, - poll_get_data); -} - -gboolean -nm_http_client_poll_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error) -{ - PollGetData * poll_get_data; - GTask * task; - gboolean success; - gs_free_error GError *local_error = NULL; - - g_return_val_if_fail(NM_HTTP_CLIENT(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_get), FALSE); - - task = G_TASK(result); - - success = g_task_propagate_boolean(task, &local_error); - - nm_assert((!!success) == (!local_error)); - - if (local_error) { - g_propagate_error(error, g_steal_pointer(&local_error)); - NM_SET_OUT(out_response_code, -1); - NM_SET_OUT(out_response_data, NULL); - return FALSE; - } - - poll_get_data = g_task_get_task_data(task); - - NM_SET_OUT(out_response_code, poll_get_data->response_code); - NM_SET_OUT(out_response_data, g_steal_pointer(&poll_get_data->response_data)); - return TRUE; -} - -/*****************************************************************************/ - -static void -_mhandle_action(NMHttpClient *self, int sockfd, int ev_bitmask) -{ - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - EHandleData * edata; - CURLMsg * msg; - CURLcode eret; - int m_left; - CURLMcode ret; - int running_handles; - - ret = curl_multi_socket_action(priv->mhandle, sockfd, ev_bitmask, &running_handles); - if (ret != CURLM_OK) { - _LOGE("curl: curl_multi_socket_action() failed: (%d) %s", ret, curl_multi_strerror(ret)); - /* really unexpected. Not clear how to handle this. */ - } - - while ((msg = curl_multi_info_read(priv->mhandle, &m_left))) { - if (msg->msg != CURLMSG_DONE) - continue; - - eret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) &edata); - - nm_assert(eret == CURLE_OK); - nm_assert(edata); - - edata->ehandle_result = msg->data.result; - _ehandle_complete(edata, NULL); - } -} - -static gboolean -_mhandle_socket_cb(int fd, GIOCondition condition, gpointer user_data) -{ - int ev_bitmask = 0; - - if (condition & G_IO_IN) - ev_bitmask |= CURL_CSELECT_IN; - if (condition & G_IO_OUT) - ev_bitmask |= CURL_CSELECT_OUT; - if (condition & G_IO_ERR) - ev_bitmask |= CURL_CSELECT_ERR; - - _mhandle_action(user_data, fd, ev_bitmask); - return G_SOURCE_CONTINUE; -} - -static int -_mhandle_socketfunction_cb(CURL * e_handle, - curl_socket_t fd, - int what, - void * user_data, - void * socketp) -{ - GSource * source_socket; - NMHttpClient * self = user_data; - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - (void) _NM_ENSURE_TYPE(int, fd); - - g_hash_table_remove(priv->source_sockets_hashtable, GINT_TO_POINTER(fd)); - - if (what != CURL_POLL_REMOVE) { - GIOCondition condition = 0; - - if (what == CURL_POLL_IN) - condition = G_IO_IN; - else if (what == CURL_POLL_OUT) - condition = G_IO_OUT; - else if (what == CURL_POLL_INOUT) - condition = G_IO_IN | G_IO_OUT; - else - condition = 0; - - if (condition) { - source_socket = nm_g_unix_fd_source_new(fd, - condition, - G_PRIORITY_DEFAULT, - _mhandle_socket_cb, - self, - NULL); - g_source_attach(source_socket, priv->context); - - g_hash_table_insert(priv->source_sockets_hashtable, GINT_TO_POINTER(fd), source_socket); - } - } - - return CURLM_OK; -} - -static gboolean -_mhandle_timeout_cb(gpointer user_data) -{ - _mhandle_action(user_data, CURL_SOCKET_TIMEOUT, 0); - return G_SOURCE_REMOVE; -} - -static int -_mhandle_timerfunction_cb(CURLM *multi, long timeout_msec, void *user_data) -{ - NMHttpClient * self = user_data; - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - nm_clear_pointer(&priv->mhandle_source_timeout, nm_g_source_destroy_and_unref); - if (timeout_msec >= 0) { - priv->mhandle_source_timeout = - _source_attach(self, - nm_g_timeout_source_new(NM_MIN(timeout_msec, G_MAXINT), - G_PRIORITY_DEFAULT, - _mhandle_timeout_cb, - self, - NULL)); - } - return 0; -} - -/*****************************************************************************/ - -static void -nm_http_client_init(NMHttpClient *self) -{ - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - priv->source_sockets_hashtable = - g_hash_table_new_full(nm_direct_hash, - NULL, - NULL, - (GDestroyNotify) nm_g_source_destroy_and_unref); -} - -static void -constructed(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - priv->context = g_main_context_ref_thread_default(); - - priv->mhandle = curl_multi_init(); - if (!priv->mhandle) - _LOGE("curl: failed to create multi-handle"); - else { - curl_multi_setopt(priv->mhandle, CURLMOPT_SOCKETFUNCTION, _mhandle_socketfunction_cb); - curl_multi_setopt(priv->mhandle, CURLMOPT_SOCKETDATA, self); - curl_multi_setopt(priv->mhandle, CURLMOPT_TIMERFUNCTION, _mhandle_timerfunction_cb); - curl_multi_setopt(priv->mhandle, CURLMOPT_TIMERDATA, self); - } - - G_OBJECT_CLASS(nm_http_client_parent_class)->constructed(object); -} - -NMHttpClient * -nm_http_client_new(void) -{ - return g_object_new(NM_TYPE_HTTP_CLIENT, NULL); -} - -static void -dispose(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - nm_clear_pointer(&priv->mhandle, curl_multi_cleanup); - nm_clear_pointer(&priv->source_sockets_hashtable, g_hash_table_unref); - - nm_clear_g_source_inst(&priv->mhandle_source_timeout); - - G_OBJECT_CLASS(nm_http_client_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_http_client_parent_class)->finalize(object); - - g_main_context_unref(priv->context); - - curl_global_cleanup(); -} - -static void -nm_http_client_class_init(NMHttpClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->finalize = finalize; - - nm_http_client_curl_global_init(); -} diff --git a/clients/cloud-setup/nm-http-client.h b/clients/cloud-setup/nm-http-client.h deleted file mode 100644 index 862b7338..00000000 --- a/clients/cloud-setup/nm-http-client.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NM_HTTP_CLIENT_C__ -#define __NM_HTTP_CLIENT_C__ - -/*****************************************************************************/ - -typedef struct _NMHttpClient NMHttpClient; -typedef struct _NMHttpClientClass NMHttpClientClass; - -#define NM_TYPE_HTTP_CLIENT (nm_http_client_get_type()) -#define NM_HTTP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_HTTP_CLIENT, NMHttpClient)) -#define NM_HTTP_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_HTTP_CLIENT, NMHttpClientClass)) -#define NM_IS_HTTP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_HTTP_CLIENT)) -#define NM_IS_HTTP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_HTTP_CLIENT)) -#define NM_HTTP_CLIENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_HTTP_CLIENT, NMHttpClientClass)) - -GType nm_http_client_get_type(void); - -NMHttpClient *nm_http_client_new(void); - -/*****************************************************************************/ - -GMainContext *nm_http_client_get_main_context(NMHttpClient *self); - -/*****************************************************************************/ - -void nm_http_client_get(NMHttpClient * self, - const char * uri, - int timeout_msec, - gssize max_data, - const char *const * http_headers, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean nm_http_client_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error); - -typedef gboolean (*NMHttpClientPollGetCheckFcn)(long response_code, - GBytes * response_data, - gpointer check_user_data, - GError **error); - -void nm_http_client_poll_get(NMHttpClient * self, - const char * uri, - int request_timeout_ms, - gssize request_max_data, - int poll_timeout_ms, - int ratelimit_timeout_ms, - const char *const * http_headers, - GCancellable * cancellable, - NMHttpClientPollGetCheckFcn check_fcn, - gpointer check_user_data, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean nm_http_client_poll_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error); - -/*****************************************************************************/ - -#endif /* __NM_HTTP_CLIENT_C__ */ diff --git a/clients/cloud-setup/nmcs-provider-azure.c b/clients/cloud-setup/nmcs-provider-azure.c deleted file mode 100644 index 0a5d522c..00000000 --- a/clients/cloud-setup/nmcs-provider-azure.c +++ /dev/null @@ -1,526 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nmcs-provider-azure.h" - -#include "nm-cloud-setup-utils.h" - -/*****************************************************************************/ - -#define HTTP_TIMEOUT_MS 3000 - -#define NM_AZURE_METADATA_HEADER "Metadata:true" -#define NM_AZURE_HOST "169.254.169.254" -#define NM_AZURE_BASE "http://" NM_AZURE_HOST -#define NM_AZURE_API_VERSION "?format=text&api-version=2017-04-02" -#define NM_AZURE_METADATA_URL_BASE /* $NM_AZURE_BASE/$NM_AZURE_API_VERSION */ \ - "/metadata/instance/network/interface/" - -#define _azure_uri_concat(...) \ - nmcs_utils_uri_build_concat(NM_AZURE_BASE, __VA_ARGS__, NM_AZURE_API_VERSION) -#define _azure_uri_interfaces(...) _azure_uri_concat(NM_AZURE_METADATA_URL_BASE, ##__VA_ARGS__) - -/*****************************************************************************/ - -struct _NMCSProviderAzure { - NMCSProvider parent; -}; - -struct _NMCSProviderAzureClass { - NMCSProviderClass parent; -}; - -G_DEFINE_TYPE(NMCSProviderAzure, nmcs_provider_azure, NMCS_TYPE_PROVIDER); - -/*****************************************************************************/ - -static void -_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_object GTask *task = user_data; - gs_free_error GError *get_error = NULL; - gs_free_error GError *error = NULL; - gboolean success; - - success = - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); - - if (nm_utils_error_is_cancelled(get_error)) { - g_task_return_error(task, g_steal_pointer(&get_error)); - return; - } - - if (get_error) { - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "failure to get Azure metadata: %s", - get_error->message); - g_task_return_error(task, g_steal_pointer(&error)); - return; - } - - if (!success) { - nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "failure to detect azure metadata"); - g_task_return_error(task, g_steal_pointer(&error)); - return; - } - - g_task_return_boolean(task, TRUE); -} - -static void -detect(NMCSProvider *provider, GTask *task) -{ - NMHttpClient *http_client; - gs_free char *uri = NULL; - - http_client = nmcs_provider_get_http_client(provider); - - nm_http_client_poll_get(http_client, - (uri = _azure_uri_concat("/metadata/instance")), - HTTP_TIMEOUT_MS, - 256 * 1024, - 7000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(task), - NULL, - NULL, - _detect_get_meta_data_done_cb, - task); -} - -/*****************************************************************************/ - -typedef struct { - NMCSProviderGetConfigTaskData * get_config_data; - NMCSProviderGetConfigIfaceData *iface_get_config; - gssize intern_iface_idx; - gssize extern_iface_idx; - guint n_ips_prefix_pending; - const char * hwaddr; -} AzureIfaceData; - -static void -_azure_iface_data_destroy(AzureIfaceData *iface_data) -{ - nm_g_slice_free(iface_data); -} - -static void -_get_config_fetch_done_cb(NMHttpClient * http_client, - GAsyncResult * result, - AzureIfaceData *iface_data, - gboolean is_ipv4) -{ - NMCSProviderGetConfigTaskData * get_config_data; - NMCSProviderGetConfigIfaceData *iface_get_config; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError *error = NULL; - const char * fip_str = NULL; - gsize fip_len; - - nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_done; - - fip_str = g_bytes_get_data(response, &fip_len); - nm_assert(fip_str[fip_len] == '\0'); - - iface_data->iface_get_config = - g_hash_table_lookup(get_config_data->result_dict, iface_data->hwaddr); - iface_get_config = iface_data->iface_get_config; - - if (is_ipv4) { - char tmp_addr_str[NM_UTILS_INET_ADDRSTRLEN]; - in_addr_t tmp_addr; - - if (!nmcs_utils_ipaddr_normalize_bin(AF_INET, fip_str, fip_len, NULL, &tmp_addr)) { - error = - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "ip is not a valid private ip address"); - goto out_done; - } - _LOGD("interface[%" G_GSSIZE_FORMAT "]: adding private ip %s", - iface_data->intern_iface_idx, - _nm_utils_inet4_ntop(tmp_addr, tmp_addr_str)); - iface_get_config->ipv4s_arr[iface_get_config->ipv4s_len] = tmp_addr; - iface_get_config->has_ipv4s = TRUE; - iface_get_config->ipv4s_len++; - } else { - int tmp_prefix = -1; - - if (fip_len > 0 && memchr(fip_str, '\0', fip_len - 1)) { - /* we have an embedded "\0" inside the string (except trailing). That is not - * allowed*/ - } else - tmp_prefix = _nm_utils_ascii_str_to_int64(fip_str, 10, 0, 32, -1); - - if (tmp_prefix == -1) { - _LOGD("interface[%" G_GSSIZE_FORMAT "]: invalid prefix", iface_data->intern_iface_idx); - error = - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "subnet does not give a valid prefix"); - goto out_done; - } - - _LOGD("interface[%" G_GSSIZE_FORMAT "]: adding prefix %d", - iface_data->intern_iface_idx, - tmp_prefix); - iface_get_config->cidr_prefix = tmp_prefix; - iface_get_config->has_cidr = TRUE; - } - -out_done: - if (!error) { - --iface_data->n_ips_prefix_pending; - if (iface_data->n_ips_prefix_pending > 0) - return; - } - - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_config_fetch_done_cb_private_ipv4s(GObject *source, GAsyncResult *result, gpointer user_data) -{ - _get_config_fetch_done_cb(NM_HTTP_CLIENT(source), result, user_data, TRUE); -} - -static void -_get_config_fetch_done_cb_subnet_cidr_prefix(GObject * source, - GAsyncResult *result, - gpointer user_data) -{ - _get_config_fetch_done_cb(NM_HTTP_CLIENT(source), result, user_data, FALSE); -} - -static void -_get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_bytes GBytes *response = NULL; - AzureIfaceData * iface_data = user_data; - gs_free_error GError * error = NULL; - const char * response_str = NULL; - gsize response_len; - NMCSProviderGetConfigTaskData *get_config_data; - const char * line; - gsize line_len; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_error; - - response_str = g_bytes_get_data(response, &response_len); - /* NMHttpClient guarantees that there is a trailing NUL after the data. */ - nm_assert(response_str[response_len] == 0); - - nm_assert(!iface_data->iface_get_config->has_ipv4s); - nm_assert(!iface_data->iface_get_config->ipv4s_arr); - nm_assert(!iface_data->iface_get_config->has_cidr); - - while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { - gint64 ips_prefix_idx; - - if (line_len == 0) - continue; - /* Truncate the string. It's safe to do, because we own @response an it has an - * extra NULL character after the buffer. */ - ((char *) line)[line_len] = '\0'; - - if (line[line_len - 1] == '/') - ((char *) line)[--line_len] = '\0'; - - ips_prefix_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXINT64, -1); - - if (ips_prefix_idx < 0) - continue; - - { - gs_free const char *uri = NULL; - char buf[100]; - - iface_data->n_ips_prefix_pending++; - - nm_http_client_poll_get( - NM_HTTP_CLIENT(source), - (uri = _azure_uri_interfaces(nm_sprintf_buf( - buf, - "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/%" G_GINT64_FORMAT "/privateIpAddress", - iface_data->intern_iface_idx, - ips_prefix_idx))), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_private_ipv4s, - iface_data); - } - } - - iface_data->iface_get_config->ipv4s_len = 0; - iface_data->iface_get_config->ipv4s_arr = g_new(in_addr_t, iface_data->n_ips_prefix_pending); - - { - gs_free const char *uri = NULL; - char buf[30]; - - iface_data->n_ips_prefix_pending++; - nm_http_client_poll_get( - NM_HTTP_CLIENT(source), - (uri = _azure_uri_interfaces( - nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT, iface_data->intern_iface_idx), - "/ipv4/subnet/0/prefix/")), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_subnet_cidr_prefix, - iface_data); - } - return; - -out_error: - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMCSProviderGetConfigTaskData *get_config_data; - gs_unref_bytes GBytes *response = NULL; - AzureIfaceData * iface_data = user_data; - gs_free char * v_hwaddr = NULL; - gs_free_error GError *error = NULL; - gs_free const char * uri = NULL; - char buf[100]; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_done; - - v_hwaddr = nmcs_utils_hwaddr_normalize_gbytes(response); - if (!v_hwaddr) { - _LOGI("interface[%" G_GSSIZE_FORMAT "]: invalid MAC address returned", - iface_data->intern_iface_idx); - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, - "invalid MAC address for index %" G_GSSIZE_FORMAT, - iface_data->intern_iface_idx); - goto out_done; - } - - if (!g_hash_table_lookup_extended(get_config_data->result_dict, - v_hwaddr, - (gpointer *) &iface_data->hwaddr, - (gpointer *) &iface_data->iface_get_config)) { - if (!get_config_data->any) { - _LOGD("get-config: skip fetching meta data for %s (%" G_GSSIZE_FORMAT ")", - v_hwaddr, - iface_data->intern_iface_idx); - goto out_done; - } - iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE); - g_hash_table_insert(get_config_data->result_dict, - (char *) (iface_data->hwaddr = g_steal_pointer(&v_hwaddr)), - iface_data->iface_get_config); - } else { - if (iface_data->iface_get_config->iface_idx >= 0) { - _LOGI("interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned", - iface_data->intern_iface_idx, - iface_data->hwaddr); - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, - "duplicate MAC address for index %" G_GSSIZE_FORMAT, - iface_data->intern_iface_idx); - goto out_done; - } - } - - iface_data->iface_get_config->iface_idx = iface_data->extern_iface_idx; - - _LOGD("interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s", - iface_data->intern_iface_idx, - iface_data->hwaddr); - - nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/", iface_data->intern_iface_idx); - - nm_http_client_poll_get(NM_HTTP_CLIENT(source), - (uri = _azure_uri_interfaces(buf)), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_ips_prefix_list_cb, - iface_data); - return; - -out_done: - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMCSProviderGetConfigTaskData *get_config_data; - gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError *error = NULL; - const char * response_str; - gsize response_len; - const char * line; - gsize line_len; - guint i; - gssize extern_iface_idx_cnt = 0; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = user_data; - - if (error) { - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); - return; - } - - response_str = g_bytes_get_data(response, &response_len); - /* NMHttpClient guarantees that there is a trailing NUL after the data. */ - nm_assert(response_str[response_len] == 0); - - ifaces_arr = g_ptr_array_new_with_free_func((GDestroyNotify) _azure_iface_data_destroy); - - while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { - AzureIfaceData *iface_data; - gssize intern_iface_idx; - - if (line_len == 0) - continue; - - /* Truncate the string. It's safe to do, because we own @response an it has an - * extra NULL character after the buffer. */ - ((char *) line)[line_len] = '\0'; - - if (line[line_len - 1] == '/' && line_len != 0) - ((char *) line)[--line_len] = '\0'; - - intern_iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); - if (intern_iface_idx < 0) - continue; - - iface_data = g_slice_new(AzureIfaceData); - *iface_data = (AzureIfaceData){ - .get_config_data = get_config_data, - .iface_get_config = NULL, - .intern_iface_idx = intern_iface_idx, - .extern_iface_idx = extern_iface_idx_cnt++, - .n_ips_prefix_pending = 0, - .hwaddr = NULL, - }; - g_ptr_array_add(ifaces_arr, iface_data); - } - - _LOGD("found azure interfaces: %u", ifaces_arr->len); - - if (ifaces_arr->len == 0) { - _nmcs_provider_get_config_task_maybe_return( - get_config_data, - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no Azure interfaces found")); - return; - } - - for (i = 0; i < ifaces_arr->len; ++i) { - AzureIfaceData * iface_data = ifaces_arr->pdata[i]; - gs_free const char *uri = NULL; - char buf[100]; - - _LOGD("azure interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", - iface_data->intern_iface_idx); - - nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", iface_data->intern_iface_idx); - - get_config_data->n_pending++; - nm_http_client_poll_get(NM_HTTP_CLIENT(source), - (uri = _azure_uri_interfaces(buf)), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_iface_cb, - iface_data); - } - - get_config_data->extra_data_destroy = (GDestroyNotify) g_ptr_array_unref; - get_config_data->extra_data = g_steal_pointer(&ifaces_arr); -} - -static void -get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) -{ - gs_free const char *uri = NULL; - - nm_http_client_poll_get(nmcs_provider_get_http_client(provider), - (uri = _azure_uri_interfaces()), - HTTP_TIMEOUT_MS, - 256 * 1024, - 15000, - 1000, - NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_net_ifaces_list_cb, - get_config_data); -} - -/*****************************************************************************/ - -static void -nmcs_provider_azure_init(NMCSProviderAzure *self) -{} - -static void -nmcs_provider_azure_class_init(NMCSProviderAzureClass *klass) -{ - NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass); - - provider_class->_name = "azure"; - provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_AZURE"); - provider_class->detect = detect; - provider_class->get_config = get_config; -} diff --git a/clients/cloud-setup/nmcs-provider-azure.h b/clients/cloud-setup/nmcs-provider-azure.h deleted file mode 100644 index be78768f..00000000 --- a/clients/cloud-setup/nmcs-provider-azure.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMCS_PROVIDER_AZURE_H__ -#define __NMCS_PROVIDER_AZURE_H__ - -#include "nmcs-provider.h" - -/*****************************************************************************/ - -typedef struct _NMCSProviderAzure NMCSProviderAzure; -typedef struct _NMCSProviderAzureClass NMCSProviderAzureClass; - -#define NMCS_TYPE_PROVIDER_AZURE (nmcs_provider_azure_get_type()) -#define NMCS_PROVIDER_AZURE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER_AZURE, NMCSProviderAzure)) -#define NMCS_PROVIDER_AZURE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER_AZURE, NMCSProviderAzureClass)) -#define NMCS_IS_PROVIDER_AZURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER_AZURE)) -#define NMCS_IS_PROVIDER_AZURE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER_AZURE)) -#define NMCS_PROVIDER_AZURE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER_AZURE, NMCSProviderAzureClass)) - -GType nmcs_provider_azure_get_type(void); - -/*****************************************************************************/ - -#endif /* __NMCS_PROVIDER_AZURE_H__ */ diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c deleted file mode 100644 index 1e060034..00000000 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ /dev/null @@ -1,427 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nmcs-provider-ec2.h" - -#include "nm-cloud-setup-utils.h" - -/*****************************************************************************/ - -#define HTTP_TIMEOUT_MS 3000 - -#define NM_EC2_HOST "169.254.169.254" -#define NM_EC2_BASE "http://" NM_EC2_HOST -#define NM_EC2_API_VERSION "2018-09-24" -#define NM_EC2_METADATA_URL_BASE /* $NM_EC2_BASE/$NM_EC2_API_VERSION */ \ - "/meta-data/network/interfaces/macs/" - -static const char * -_ec2_base(void) -{ - static const char *base_cached = NULL; - const char * base; - -again: - base = g_atomic_pointer_get(&base_cached); - if (G_UNLIKELY(!base)) { - /* The base URI can be set via environment variable. - * This is mainly for testing, it's not usually supposed to be configured. - * Consider this private API! */ - base = g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_EC2_HOST")); - - if (base && base[0] && !strchr(base, '/')) { - if (NM_STR_HAS_PREFIX(base, "http://") || NM_STR_HAS_PREFIX(base, "https://")) - base = g_intern_string(base); - else { - gs_free char *s = NULL; - - s = g_strconcat("http://", base, NULL); - base = g_intern_string(s); - } - } - if (!base) - base = NM_EC2_BASE; - - nm_assert(!NM_STR_HAS_SUFFIX(base, "/")); - - if (!g_atomic_pointer_compare_and_exchange(&base_cached, NULL, base)) - goto again; - } - - return base; -} - -#define _ec2_uri_concat(...) nmcs_utils_uri_build_concat(_ec2_base(), __VA_ARGS__) -#define _ec2_uri_interfaces(...) \ - _ec2_uri_concat(NM_EC2_API_VERSION, NM_EC2_METADATA_URL_BASE, ##__VA_ARGS__) - -/*****************************************************************************/ - -struct _NMCSProviderEC2 { - NMCSProvider parent; -}; - -struct _NMCSProviderEC2Class { - NMCSProviderClass parent; -}; - -G_DEFINE_TYPE(NMCSProviderEC2, nmcs_provider_ec2, NMCS_TYPE_PROVIDER); - -/*****************************************************************************/ - -static gboolean -_detect_get_meta_data_check_cb(long response_code, - GBytes * response, - gpointer check_user_data, - GError **error) -{ - return response_code == 200 && nmcs_utils_parse_get_full_line(response, "ami-id"); -} - -static void -_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_object GTask *task = user_data; - gs_free_error GError *get_error = NULL; - gs_free_error GError *error = NULL; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); - - if (nm_utils_error_is_cancelled(get_error)) { - g_task_return_error(task, g_steal_pointer(&get_error)); - return; - } - - if (get_error) { - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "failure to get EC2 metadata: %s", - get_error->message); - g_task_return_error(task, g_steal_pointer(&error)); - return; - } - - g_task_return_boolean(task, TRUE); -} - -static void -detect(NMCSProvider *provider, GTask *task) -{ - NMHttpClient *http_client; - gs_free char *uri = NULL; - - http_client = nmcs_provider_get_http_client(provider); - - nm_http_client_poll_get(http_client, - (uri = _ec2_uri_concat("latest/meta-data/")), - HTTP_TIMEOUT_MS, - 256 * 1024, - 7000, - 1000, - NULL, - g_task_get_cancellable(task), - _detect_get_meta_data_check_cb, - NULL, - _detect_get_meta_data_done_cb, - task); -} - -/*****************************************************************************/ - -static void -_get_config_fetch_done_cb(NMHttpClient *http_client, - GAsyncResult *result, - gpointer user_data, - gboolean is_local_ipv4) -{ - NMCSProviderGetConfigTaskData *get_config_data; - const char * hwaddr = NULL; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError * error = NULL; - NMCSProviderGetConfigIfaceData *config_iface_data; - in_addr_t tmp_addr; - int tmp_prefix; - - nm_utils_user_data_unpack(user_data, &get_config_data, &hwaddr); - - nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - if (error) - goto out; - - config_iface_data = g_hash_table_lookup(get_config_data->result_dict, hwaddr); - - if (is_local_ipv4) { - gs_free const char **s_addrs = NULL; - gsize i, len; - - s_addrs = nm_utils_strsplit_set_full(g_bytes_get_data(response, NULL), - "\n", - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); - len = NM_PTRARRAY_LEN(s_addrs); - - nm_assert(!config_iface_data->has_ipv4s); - nm_assert(!config_iface_data->ipv4s_arr); - config_iface_data->has_ipv4s = TRUE; - config_iface_data->ipv4s_len = 0; - if (len > 0) { - config_iface_data->ipv4s_arr = g_new(in_addr_t, len); - - for (i = 0; i < len; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, s_addrs[i], NULL, &tmp_addr)) - config_iface_data->ipv4s_arr[config_iface_data->ipv4s_len++] = tmp_addr; - } - } - } else { - if (nm_utils_parse_inaddr_prefix_bin(AF_INET, - g_bytes_get_data(response, NULL), - NULL, - &tmp_addr, - &tmp_prefix)) { - nm_assert(!config_iface_data->has_cidr); - config_iface_data->has_cidr = TRUE; - config_iface_data->cidr_prefix = tmp_prefix; - config_iface_data->cidr_addr = tmp_addr; - } - } - -out: - get_config_data->n_pending--; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_config_fetch_done_cb_subnet_ipv4_cidr_block(GObject * source, - GAsyncResult *result, - gpointer user_data) -{ - _get_config_fetch_done_cb(NM_HTTP_CLIENT(source), result, user_data, FALSE); -} - -static void -_get_config_fetch_done_cb_local_ipv4s(GObject *source, GAsyncResult *result, gpointer user_data) -{ - _get_config_fetch_done_cb(NM_HTTP_CLIENT(source), result, user_data, TRUE); -} - -typedef struct { - gssize iface_idx; - char path[0]; -} GetConfigMetadataMac; - -static void -_get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMCSProviderGetConfigTaskData *get_config_data; - gs_unref_hashtable GHashTable *response_parsed = NULL; - gs_free_error GError *error = NULL; - GetConfigMetadataMac *v_mac_data; - const char * v_hwaddr; - GHashTableIter h_iter; - NMHttpClient * http_client; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = user_data; - - response_parsed = g_steal_pointer(&get_config_data->extra_data); - get_config_data->extra_data_destroy = NULL; - - /* We ignore errors. Only if we got no response at all, it's a problem. - * Otherwise, we proceed with whatever we could fetch. */ - if (!response_parsed) { - _nmcs_provider_get_config_task_maybe_return( - get_config_data, - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "meta data for interfaces not found")); - return; - } - - http_client = nmcs_provider_get_http_client(g_task_get_source_object(get_config_data->task)); - - g_hash_table_iter_init(&h_iter, response_parsed); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &v_hwaddr, (gpointer *) &v_mac_data)) { - NMCSProviderGetConfigIfaceData *config_iface_data; - gs_free char * uri1 = NULL; - gs_free char * uri2 = NULL; - const char * hwaddr; - - if (!g_hash_table_lookup_extended(get_config_data->result_dict, - v_hwaddr, - (gpointer *) &hwaddr, - (gpointer *) &config_iface_data)) { - if (!get_config_data->any) { - _LOGD("get-config: skip fetching meta data for %s (%s)", - v_hwaddr, - v_mac_data->path); - continue; - } - config_iface_data = nmcs_provider_get_config_iface_data_new(FALSE); - g_hash_table_insert(get_config_data->result_dict, - (char *) (hwaddr = g_strdup(v_hwaddr)), - config_iface_data); - } - - nm_assert(config_iface_data->iface_idx == -1); - - config_iface_data->iface_idx = v_mac_data->iface_idx; - - _LOGD("get-config: start fetching meta data for #%" G_GSSIZE_FORMAT ", %s (%s)", - config_iface_data->iface_idx, - hwaddr, - v_mac_data->path); - - get_config_data->n_pending++; - nm_http_client_poll_get( - http_client, - (uri1 = _ec2_uri_interfaces(v_mac_data->path, - NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", - "subnet-ipv4-cidr-block")), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NULL, - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_subnet_ipv4_cidr_block, - nm_utils_user_data_pack(get_config_data, hwaddr)); - - get_config_data->n_pending++; - nm_http_client_poll_get( - http_client, - (uri2 = _ec2_uri_interfaces(v_mac_data->path, - NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", - "local-ipv4s")), - HTTP_TIMEOUT_MS, - 512 * 1024, - 10000, - 1000, - NULL, - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_local_ipv4s, - nm_utils_user_data_pack(get_config_data, hwaddr)); - } - - _nmcs_provider_get_config_task_maybe_return(get_config_data, NULL); -} - -static gboolean -_get_config_metadata_ready_check(long response_code, - GBytes * response, - gpointer check_user_data, - GError **error) -{ - NMCSProviderGetConfigTaskData *get_config_data = check_user_data; - gs_unref_hashtable GHashTable *response_parsed = NULL; - const guint8 * r_data; - const char * cur_line; - gsize r_len; - gsize cur_line_len; - GHashTableIter h_iter; - gboolean has_all; - const char * c_hwaddr; - gssize iface_idx_counter = 0; - - if (response_code != 200 || !response) { - /* we wait longer. */ - return FALSE; - } - - r_data = g_bytes_get_data(response, &r_len); - /* NMHttpClient guarantees that there is a trailing NUL after the data. */ - nm_assert(r_data[r_len] == 0); - - while (nm_utils_parse_next_line((const char **) &r_data, &r_len, &cur_line, &cur_line_len)) { - GetConfigMetadataMac *mac_data; - char * hwaddr; - - if (cur_line_len == 0) - continue; - - /* Truncate the string. It's safe to do, because we own @response an it has an - * extra NUL character after the buffer. */ - ((char *) cur_line)[cur_line_len] = '\0'; - - hwaddr = nmcs_utils_hwaddr_normalize( - cur_line, - cur_line[cur_line_len - 1u] == '/' ? (gssize)(cur_line_len - 1u) : -1); - if (!hwaddr) - continue; - - if (!response_parsed) - response_parsed = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); - - mac_data = g_malloc(sizeof(GetConfigMetadataMac) + 1u + cur_line_len); - mac_data->iface_idx = iface_idx_counter++; - memcpy(mac_data->path, cur_line, cur_line_len + 1u); - - /* here we will ignore duplicate responses. */ - g_hash_table_insert(response_parsed, hwaddr, mac_data); - } - - has_all = TRUE; - g_hash_table_iter_init(&h_iter, get_config_data->result_dict); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, NULL)) { - if (!response_parsed || !g_hash_table_contains(response_parsed, c_hwaddr)) { - has_all = FALSE; - break; - } - } - - nm_clear_pointer(&get_config_data->extra_data, g_hash_table_unref); - if (response_parsed) { - get_config_data->extra_data = g_steal_pointer(&response_parsed); - get_config_data->extra_data_destroy = (GDestroyNotify) g_hash_table_unref; - } - return has_all; -} - -static void -get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) -{ - gs_free char *uri = NULL; - - /* First we fetch the "macs/". If the caller requested some particular - * MAC addresses, then we poll until we see them. They might not yet be - * around from the start... - */ - nm_http_client_poll_get(nmcs_provider_get_http_client(provider), - (uri = _ec2_uri_interfaces()), - HTTP_TIMEOUT_MS, - 256 * 1024, - 15000, - 1000, - NULL, - get_config_data->intern_cancellable, - _get_config_metadata_ready_check, - get_config_data, - _get_config_metadata_ready_cb, - get_config_data); -} - -/*****************************************************************************/ - -static void -nmcs_provider_ec2_init(NMCSProviderEC2 *self) -{} - -static void -nmcs_provider_ec2_class_init(NMCSProviderEC2Class *klass) -{ - NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass); - - provider_class->_name = "ec2"; - provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_EC2"); - provider_class->detect = detect; - provider_class->get_config = get_config; -} diff --git a/clients/cloud-setup/nmcs-provider-ec2.h b/clients/cloud-setup/nmcs-provider-ec2.h deleted file mode 100644 index 8f8b6400..00000000 --- a/clients/cloud-setup/nmcs-provider-ec2.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMCS_PROVIDER_EC2_H__ -#define __NMCS_PROVIDER_EC2_H__ - -#include "nmcs-provider.h" - -/*****************************************************************************/ - -typedef struct _NMCSProviderEC2 NMCSProviderEC2; -typedef struct _NMCSProviderEC2Class NMCSProviderEC2Class; - -#define NMCS_TYPE_PROVIDER_EC2 (nmcs_provider_ec2_get_type()) -#define NMCS_PROVIDER_EC2(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER_EC2, NMCSProviderEC2)) -#define NMCS_PROVIDER_EC2_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER_EC2, NMCSProviderEC2Class)) -#define NMCS_IS_PROVIDER_EC2(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER_EC2)) -#define NMCS_IS_PROVIDER_EC2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER_EC2)) -#define NMCS_PROVIDER_EC2_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER_EC2, NMCSProviderEC2Class)) - -GType nmcs_provider_ec2_get_type(void); - -/*****************************************************************************/ - -#endif /* __NMCS_PROVIDER_EC2_H__ */ diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c deleted file mode 100644 index 1deaea10..00000000 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ /dev/null @@ -1,464 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nmcs-provider-gcp.h" - -#include "nm-cloud-setup-utils.h" - -/*****************************************************************************/ - -#define HTTP_TIMEOUT_MS 3000 -#define HTTP_REQ_MAX_DATA 512 * 1024 -#define HTTP_POLL_TIMEOUT_MS 10000 -#define HTTP_RATE_LIMIT_MS 1000 - -#define NM_GCP_HOST "metadata.google.internal" -#define NM_GCP_BASE "http://" NM_GCP_HOST -#define NM_GCP_API_VERSION "/v1" -#define NM_GCP_METADATA_URL_BASE NM_GCP_BASE "/computeMetadata" NM_GCP_API_VERSION "/instance" -#define NM_GCP_METADATA_URL_NET "/network-interfaces/" - -#define NM_GCP_METADATA_HEADER "Metadata-Flavor: Google" - -#define _gcp_uri_concat(...) nmcs_utils_uri_build_concat(NM_GCP_METADATA_URL_BASE, __VA_ARGS__) -#define _gcp_uri_interfaces(...) _gcp_uri_concat(NM_GCP_METADATA_URL_NET, ##__VA_ARGS__) - -/*****************************************************************************/ - -struct _NMCSProviderGCP { - NMCSProvider parent; -}; - -struct _NMCSProviderGCPClass { - NMCSProviderClass parent; -}; - -G_DEFINE_TYPE(NMCSProviderGCP, nmcs_provider_gcp, NMCS_TYPE_PROVIDER); - -/*****************************************************************************/ - -static void -_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_object GTask *task = user_data; - gs_free_error GError *get_error = NULL; - gs_free_error GError *error = NULL; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); - - if (nm_utils_error_is_cancelled(get_error)) { - g_task_return_error(task, g_steal_pointer(&get_error)); - return; - } - - if (get_error) { - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "failure to get GCP metadata: %s", - get_error->message); - g_task_return_error(task, g_steal_pointer(&error)); - return; - } - - g_task_return_boolean(task, TRUE); -} - -static void -detect(NMCSProvider *provider, GTask *task) -{ - NMHttpClient *http_client; - gs_free char *uri = NULL; - - http_client = nmcs_provider_get_http_client(provider); - - nm_http_client_poll_get(http_client, - (uri = _gcp_uri_concat("id")), - HTTP_TIMEOUT_MS, - 256 * 1024, - 7000, - 1000, - NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(task), - NULL, - NULL, - _detect_get_meta_data_done_cb, - task); -} - -/*****************************************************************************/ - -typedef struct { - NMCSProviderGetConfigTaskData * get_config_data; - NMCSProviderGetConfigIfaceData *iface_get_config; - gssize intern_iface_idx; - gssize extern_iface_idx; - guint n_fips_pending; -} GCPIfaceData; - -static void -_gcp_iface_data_destroy(GCPIfaceData *iface_data) -{ - nm_g_slice_free(iface_data); -} - -static void -_get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMCSProviderGetConfigTaskData * get_config_data; - NMCSProviderGetConfigIfaceData *iface_get_config; - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData * iface_data = user_data; - gs_free_error GError *error = NULL; - gs_free char * ipaddr = NULL; - NMIPRoute ** routes_arr; - NMIPRoute * route_new; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_done; - - ipaddr = nmcs_utils_ipaddr_normalize_gbytes(AF_INET, response); - if (!ipaddr) { - error = - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "forwarded-ip is not a valid ip address"); - goto out_done; - } - - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: adding forwarded-ip %s", - iface_data->intern_iface_idx, - ipaddr); - - iface_get_config = iface_data->iface_get_config; - routes_arr = iface_get_config->iproutes_arr; - - route_new = nm_ip_route_new(AF_INET, ipaddr, 32, NULL, 100, &error); - if (error) - goto out_done; - - nm_ip_route_set_attribute(route_new, NM_IP_ROUTE_ATTRIBUTE_TYPE, g_variant_new_string("local")); - routes_arr[iface_get_config->iproutes_len] = route_new; - ++iface_get_config->iproutes_len; - -out_done: - if (!error) { - --iface_data->n_fips_pending; - if (iface_data->n_fips_pending > 0) - return; - } - - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMCSProviderGetConfigTaskData *get_config_data; - gs_unref_ptrarray GPtrArray *uri_arr = NULL; - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData * iface_data = user_data; - gs_free_error GError *error = NULL; - const char * response_str = NULL; - gsize response_len; - const char * line; - gsize line_len; - guint i; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_error; - - response_str = g_bytes_get_data(response, &response_len); - /* NMHttpClient guarantees that there is a trailing NUL after the data. */ - nm_assert(response_str[response_len] == 0); - - uri_arr = g_ptr_array_new_with_free_func(g_free); - while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { - gint64 fip_index; - - /* Truncate the string. It's safe to do, because we own @response an it has an - * extra NUL character after the buffer. */ - ((char *) line)[line_len] = '\0'; - - fip_index = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXINT64, -1); - if (fip_index < 0) - continue; - - g_ptr_array_add(uri_arr, - g_strdup_printf("%" G_GSSIZE_FORMAT "/forwarded-ips/%" G_GINT64_FORMAT, - iface_data->intern_iface_idx, - fip_index)); - } - - iface_data->n_fips_pending = uri_arr->len; - - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found %u forwarded ips", - iface_data->intern_iface_idx, - iface_data->n_fips_pending); - - if (iface_data->n_fips_pending == 0) { - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "found no forwarded ip"); - goto out_error; - } - - iface_data->iface_get_config->iproutes_arr = g_new(NMIPRoute *, iface_data->n_fips_pending); - - for (i = 0; i < uri_arr->len; ++i) { - const char * str = uri_arr->pdata[i]; - gs_free const char *uri = NULL; - - nm_http_client_poll_get(NM_HTTP_CLIENT(source), - (uri = _gcp_uri_interfaces(str)), - HTTP_TIMEOUT_MS, - HTTP_REQ_MAX_DATA, - HTTP_POLL_TIMEOUT_MS, - HTTP_RATE_LIMIT_MS, - NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_fip_cb, - iface_data); - } - return; - -out_error: - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData * iface_data = user_data; - gs_free_error GError * error = NULL; - gs_free char * v_hwaddr = NULL; - const char * hwaddr = NULL; - gs_free const char * uri = NULL; - char sbuf[100]; - NMCSProviderGetConfigTaskData *get_config_data; - gboolean is_requested; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = iface_data->get_config_data; - - if (error) - goto out_done; - - v_hwaddr = nmcs_utils_hwaddr_normalize_gbytes(response); - if (!v_hwaddr) { - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: invalid MAC address returned", - iface_data->intern_iface_idx); - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, - "invalid MAC address for index %" G_GSSIZE_FORMAT, - iface_data->intern_iface_idx); - goto out_done; - } - - if (!g_hash_table_lookup_extended(get_config_data->result_dict, - v_hwaddr, - (gpointer *) &hwaddr, - (gpointer *) &iface_data->iface_get_config)) { - if (!get_config_data->any) { - _LOGD("get-config: skip fetching meta data for %s (%" G_GSSIZE_FORMAT ")", - v_hwaddr, - iface_data->intern_iface_idx); - goto out_done; - } - iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE); - g_hash_table_insert(get_config_data->result_dict, - (char *) (hwaddr = g_steal_pointer(&v_hwaddr)), - iface_data->iface_get_config); - is_requested = FALSE; - } else { - if (iface_data->iface_get_config->iface_idx >= 0) { - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned", - iface_data->intern_iface_idx, - hwaddr); - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, - "duplicate MAC address for index %" G_GSSIZE_FORMAT, - iface_data->intern_iface_idx); - goto out_done; - } - is_requested = TRUE; - } - - iface_data->iface_get_config->iface_idx = iface_data->extern_iface_idx; - - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a %sdevice with hwaddr %s", - iface_data->intern_iface_idx, - is_requested ? "requested " : "", - hwaddr); - - nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->intern_iface_idx); - - nm_http_client_poll_get(NM_HTTP_CLIENT(source), - (uri = _gcp_uri_interfaces(sbuf)), - HTTP_TIMEOUT_MS, - HTTP_REQ_MAX_DATA, - HTTP_POLL_TIMEOUT_MS, - HTTP_RATE_LIMIT_MS, - NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_ips_list_cb, - iface_data); - return; - -out_done: - --get_config_data->n_pending; - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); -} - -static void -_get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError * error = NULL; - NMCSProviderGetConfigTaskData *get_config_data; - const char * response_str; - gsize response_len; - const char * line; - gsize line_len; - guint i; - gssize extern_iface_idx_cnt = 0; - - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - get_config_data = user_data; - - if (error) { - _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); - return; - } - - response_str = g_bytes_get_data(response, &response_len); - /* NMHttpClient guarantees that there is a trailing NUL after the data. */ - nm_assert(response_str[response_len] == 0); - - ifaces_arr = g_ptr_array_new_with_free_func((GDestroyNotify) _gcp_iface_data_destroy); - - while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { - GCPIfaceData *iface_data; - gssize intern_iface_idx; - - if (line_len == 0) - continue; - - /* Truncate the string. It's safe to do, because we own @response an it has an - * extra NUL character after the buffer. */ - ((char *) line)[line_len] = '\0'; - if (line[line_len - 1] == '/') - ((char *) line)[--line_len] = '\0'; - - intern_iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); - if (intern_iface_idx < 0) - continue; - - iface_data = g_slice_new(GCPIfaceData); - *iface_data = (GCPIfaceData){ - .get_config_data = get_config_data, - .iface_get_config = NULL, - .intern_iface_idx = intern_iface_idx, - .extern_iface_idx = extern_iface_idx_cnt++, - .n_fips_pending = 0, - }; - g_ptr_array_add(ifaces_arr, iface_data); - } - - _LOGI("found GCP interfaces: %u", ifaces_arr->len); - - if (ifaces_arr->len == 0) { - _nmcs_provider_get_config_task_maybe_return( - get_config_data, - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no GCP interfaces found")); - return; - } - - for (i = 0; i < ifaces_arr->len; ++i) { - GCPIfaceData * data = ifaces_arr->pdata[i]; - gs_free const char *uri = NULL; - char sbuf[100]; - - _LOGD("GCP interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", - data->intern_iface_idx); - - nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->intern_iface_idx); - - get_config_data->n_pending++; - nm_http_client_poll_get(NM_HTTP_CLIENT(source), - (uri = _gcp_uri_interfaces(sbuf)), - HTTP_TIMEOUT_MS, - HTTP_REQ_MAX_DATA, - HTTP_POLL_TIMEOUT_MS, - HTTP_RATE_LIMIT_MS, - NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_config_iface_cb, - data); - } - - get_config_data->extra_data = g_steal_pointer(&ifaces_arr); - get_config_data->extra_data_destroy = (GDestroyNotify) g_ptr_array_unref; -} - -static void -get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) -{ - gs_free const char *uri = NULL; - - nm_http_client_poll_get(nmcs_provider_get_http_client(provider), - (uri = _gcp_uri_interfaces()), - HTTP_TIMEOUT_MS, - HTTP_REQ_MAX_DATA, - HTTP_POLL_TIMEOUT_MS, - HTTP_RATE_LIMIT_MS, - NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - get_config_data->intern_cancellable, - NULL, - NULL, - _get_net_ifaces_list_cb, - get_config_data); -} - -/*****************************************************************************/ - -static void -nmcs_provider_gcp_init(NMCSProviderGCP *self) -{} - -static void -nmcs_provider_gcp_class_init(NMCSProviderGCPClass *klass) -{ - NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass); - - provider_class->_name = "GCP"; - provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_GCP"); - provider_class->detect = detect; - provider_class->get_config = get_config; -} diff --git a/clients/cloud-setup/nmcs-provider-gcp.h b/clients/cloud-setup/nmcs-provider-gcp.h deleted file mode 100644 index b0329935..00000000 --- a/clients/cloud-setup/nmcs-provider-gcp.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMCS_PROVIDER_GCP_H__ -#define __NMCS_PROVIDER_GCP_H__ - -#include "nmcs-provider.h" - -/*****************************************************************************/ - -typedef struct _NMCSProviderGCP NMCSProviderGCP; -typedef struct _NMCSProviderGCPClass NMCSProviderGCPClass; - -#define NMCS_TYPE_PROVIDER_GCP (nmcs_provider_gcp_get_type()) -#define NMCS_PROVIDER_GCP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCP)) -#define NMCS_PROVIDER_GCP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) -#define NMCS_IS_PROVIDER_GCP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER_GCP)) -#define NMCS_IS_PROVIDER_GCP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER_GCP)) -#define NMCS_PROVIDER_GCP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) - -GType nmcs_provider_gcp_get_type(void); - -/*****************************************************************************/ - -#endif /* __NMCS_PROVIDER_GCP_H__ */ diff --git a/clients/cloud-setup/nmcs-provider.c b/clients/cloud-setup/nmcs-provider.c deleted file mode 100644 index c700d8e1..00000000 --- a/clients/cloud-setup/nmcs-provider.c +++ /dev/null @@ -1,288 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nmcs-provider.h" - -#include "nm-cloud-setup-utils.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_HTTP_CLIENT, ); - -typedef struct _NMCSProviderPrivate { - NMHttpClient *http_client; -} NMCSProviderPrivate; - -G_DEFINE_TYPE(NMCSProvider, nmcs_provider, G_TYPE_OBJECT); - -#define NMCS_PROVIDER_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMCSProvider, NMCS_IS_PROVIDER) - -/*****************************************************************************/ - -const char * -nmcs_provider_get_name(NMCSProvider *self) -{ - NMCSProviderClass *klass; - - g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - - klass = NMCS_PROVIDER_GET_CLASS(self); - nm_assert(klass->_name); - return klass->_name; -} - -/*****************************************************************************/ - -NMHttpClient * -nmcs_provider_get_http_client(NMCSProvider *self) -{ - g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - - return NMCS_PROVIDER_GET_PRIVATE(self)->http_client; -} - -GMainContext * -nmcs_provider_get_main_context(NMCSProvider *self) -{ - g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - - return nm_http_client_get_main_context(NMCS_PROVIDER_GET_PRIVATE(self)->http_client); -} - -/*****************************************************************************/ - -void -nmcs_provider_detect(NMCSProvider * self, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - gs_unref_object GTask *task = NULL; - const char * env; - - g_return_if_fail(NMCS_IS_PROVIDER(self)); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - - task = nm_g_task_new(self, cancellable, nmcs_provider_detect, callback, user_data); - - nmcs_wait_for_objects_register(task); - - env = g_getenv(NMCS_PROVIDER_GET_CLASS(self)->_env_provider_enabled); - if (!_nm_utils_ascii_str_to_bool(env, FALSE)) { - g_task_return_error(task, - nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "provider is disabled")); - return; - } - - NMCS_PROVIDER_GET_CLASS(self)->detect(self, g_steal_pointer(&task)); -} - -gboolean -nmcs_provider_detect_finish(NMCSProvider *self, GAsyncResult *result, GError **error) -{ - g_return_val_if_fail(NMCS_IS_PROVIDER(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nmcs_provider_detect), FALSE); - - return g_task_propagate_boolean(G_TASK(result), error); -} - -/*****************************************************************************/ - -NMCSProviderGetConfigIfaceData * -nmcs_provider_get_config_iface_data_new(gboolean was_requested) -{ - NMCSProviderGetConfigIfaceData *iface_data; - - iface_data = g_slice_new(NMCSProviderGetConfigIfaceData); - *iface_data = (NMCSProviderGetConfigIfaceData){ - .iface_idx = -1, - .was_requested = was_requested, - }; - return iface_data; -} - -static void -_iface_data_free(gpointer data) -{ - NMCSProviderGetConfigIfaceData *iface_data = data; - - g_free(iface_data->ipv4s_arr); - g_free(iface_data->iproutes_arr); - - nm_g_slice_free(iface_data); -} - -static void -_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, GError *error_take) -{ - gs_free_error GError *error = error_take; - - nm_assert(get_config_data); - nm_assert(G_IS_TASK(get_config_data->task)); - - if (!error) { - if (get_config_data->n_pending > 0) - return; - } - - g_cancellable_cancel(get_config_data->intern_cancellable); - - if (error) { - if (nm_utils_error_is_cancelled(error)) - _LOGD("get-config: cancelled"); - else - _LOGD("get-config: failed: %s", error->message); - g_task_return_error(get_config_data->task, g_steal_pointer(&error)); - } else { - _LOGD("get-config: success"); - g_task_return_pointer(get_config_data->task, - g_hash_table_ref(get_config_data->result_dict), - (GDestroyNotify) g_hash_table_unref); - } - - nm_clear_g_signal_handler(g_task_get_cancellable(get_config_data->task), - &get_config_data->extern_cancelled_id); - - if (get_config_data->extra_data_destroy) - get_config_data->extra_data_destroy(get_config_data->extra_data); - - nm_clear_pointer(&get_config_data->result_dict, g_hash_table_unref); - - nm_g_object_unref(get_config_data->intern_cancellable); - g_object_unref(get_config_data->task); - nm_g_slice_free(get_config_data); -} - -void -_nmcs_provider_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, - GError * error_take) -{ - nm_assert(!error_take || !nm_utils_error_is_cancelled(error_take)); - _get_config_task_maybe_return(get_config_data, error_take); -} - -static void -_get_config_cancelled_cb(GObject *object, gpointer user_data) -{ - _get_config_task_maybe_return(user_data, nm_utils_error_new_cancelled(FALSE, NULL)); -} - -void -nmcs_provider_get_config(NMCSProvider * self, - gboolean any, - const char *const * hwaddrs, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMCSProviderGetConfigTaskData *get_config_data; - - g_return_if_fail(NMCS_IS_PROVIDER(self)); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - - _LOGD("get-config: starting"); - - get_config_data = g_slice_new(NMCSProviderGetConfigTaskData); - *get_config_data = (NMCSProviderGetConfigTaskData){ - .task = nm_g_task_new(self, cancellable, nmcs_provider_get_config, callback, user_data), - .any = any, - .result_dict = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _iface_data_free), - }; - - nmcs_wait_for_objects_register(get_config_data->task); - - for (; hwaddrs && hwaddrs[0]; hwaddrs++) { - g_hash_table_insert(get_config_data->result_dict, - g_strdup(hwaddrs[0]), - nmcs_provider_get_config_iface_data_new(TRUE)); - } - - if (cancellable) { - gulong cancelled_id; - - cancelled_id = g_cancellable_connect(cancellable, - G_CALLBACK(_get_config_cancelled_cb), - get_config_data, - NULL); - if (cancelled_id == 0) { - /* the callback was already invoked synchronously and the task already returned. */ - return; - } - - get_config_data->extern_cancelled_id = cancelled_id; - get_config_data->intern_cancellable = g_cancellable_new(); - } - - NMCS_PROVIDER_GET_CLASS(self)->get_config(self, get_config_data); -} - -GHashTable * -nmcs_provider_get_config_finish(NMCSProvider *self, GAsyncResult *result, GError **error) -{ - g_return_val_if_fail(NMCS_IS_PROVIDER(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nmcs_provider_get_config), FALSE); - - return g_task_propagate_pointer(G_TASK(result), error); -} - -/*****************************************************************************/ - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMCSProviderPrivate *priv = NMCS_PROVIDER_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_HTTP_CLIENT: - priv->http_client = g_value_dup_object(value); - g_return_if_fail(NM_IS_HTTP_CLIENT(priv->http_client)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nmcs_provider_init(NMCSProvider *self) -{ - NMCSProviderPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NMCS_TYPE_PROVIDER, NMCSProviderPrivate); - - self->_priv = priv; -} - -static void -dispose(GObject *object) -{ - NMCSProvider * self = NMCS_PROVIDER(object); - NMCSProviderPrivate *priv = NMCS_PROVIDER_GET_PRIVATE(self); - - g_clear_object(&priv->http_client); - - G_OBJECT_CLASS(nmcs_provider_parent_class)->dispose(object); -} - -static void -nmcs_provider_class_init(NMCSProviderClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMCSProviderPrivate)); - - object_class->set_property = set_property; - object_class->dispose = dispose; - - obj_properties[PROP_HTTP_CLIENT] = - g_param_spec_object(NMCS_PROVIDER_HTTP_CLIENT, - "", - "", - NM_TYPE_HTTP_CLIENT, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/clients/cloud-setup/nmcs-provider.h b/clients/cloud-setup/nmcs-provider.h deleted file mode 100644 index 3b0c2529..00000000 --- a/clients/cloud-setup/nmcs-provider.h +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMCS_PROVIDER_H__ -#define __NMCS_PROVIDER_H__ - -/*****************************************************************************/ - -#include "nm-http-client.h" - -/*****************************************************************************/ - -typedef struct { - in_addr_t *ipv4s_arr; - gsize ipv4s_len; - - /* If the interface was seen, get_config() should set this to a - * unique, increasing, positive index. If the interface is requested, - * it is initialized to -1. */ - gssize iface_idx; - - in_addr_t cidr_addr; - guint8 cidr_prefix; - bool has_ipv4s : 1; - bool has_cidr : 1; - - NMIPRoute **iproutes_arr; - gsize iproutes_len; - - /* TRUE, if the configuration was requested via hwaddrs argument to - * nmcs_provider_get_config(). */ - bool was_requested : 1; - -} NMCSProviderGetConfigIfaceData; - -static inline gboolean -nmcs_provider_get_config_iface_data_is_valid(const NMCSProviderGetConfigIfaceData *config_data) -{ - return config_data && config_data->iface_idx >= 0 - && ((config_data->has_ipv4s && config_data->has_cidr) || config_data->iproutes_len); -} - -NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new(gboolean was_requested); - -typedef struct { - GTask *task; - - GHashTable *result_dict; - - /* this cancellable should be used for the provider implementation - * to listen for cancellation. */ - GCancellable *intern_cancellable; - - /* the provider implementation may attach extra data. */ - gpointer extra_data; - GDestroyNotify extra_data_destroy; - - gulong extern_cancelled_id; - - /* the provider implementation may use this field to track the number of pending - * operations. */ - guint n_pending; - - bool any : 1; -} NMCSProviderGetConfigTaskData; - -#define NMCS_TYPE_PROVIDER (nmcs_provider_get_type()) -#define NMCS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER, NMCSProvider)) -#define NMCS_PROVIDER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER, NMCSProviderClass)) -#define NMCS_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER)) -#define NMCS_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER)) -#define NMCS_PROVIDER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER, NMCSProviderClass)) - -#define NMCS_PROVIDER_HTTP_CLIENT "http-client" - -struct _NMCSProviderPrivate; - -typedef struct { - GObject parent; - struct _NMCSProviderPrivate *_priv; -} NMCSProvider; - -typedef struct { - GObjectClass parent; - const char * _name; - const char * _env_provider_enabled; - - void (*detect)(NMCSProvider *self, GTask *task); - - void (*get_config)(NMCSProvider *self, NMCSProviderGetConfigTaskData *get_config_data); - -} NMCSProviderClass; - -GType nmcs_provider_get_type(void); - -/*****************************************************************************/ - -const char *nmcs_provider_get_name(NMCSProvider *provider); - -NMHttpClient *nmcs_provider_get_http_client(NMCSProvider *provider); -GMainContext *nmcs_provider_get_main_context(NMCSProvider *provider); - -/*****************************************************************************/ - -void nmcs_provider_detect(NMCSProvider * provider, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean nmcs_provider_detect_finish(NMCSProvider *provider, GAsyncResult *result, GError **error); - -/*****************************************************************************/ - -void _nmcs_provider_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, - GError * error_take); - -void nmcs_provider_get_config(NMCSProvider * provider, - gboolean any, - const char *const * hwaddrs, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GHashTable * -nmcs_provider_get_config_finish(NMCSProvider *provider, GAsyncResult *result, GError **error); - -#endif /* __NMCS_PROVIDER_H__ */ diff --git a/clients/cloud-setup/tests/meson.build b/clients/cloud-setup/tests/meson.build deleted file mode 100644 index 1c5e6ec6..00000000 --- a/clients/cloud-setup/tests/meson.build +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -exe = executable( - 'test-cloud-setup-general', - 'test-cloud-setup-general.c', - dependencies: [ - libnmc_base_dep, - libnmc_dep, - libnm_cloud_setup_core_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="test"', - ], -) - -test( - 'clients/cloud-setup/tests/test-cloud-setup-general', - test_script, - args: test_args + [exe.full_path()], -) diff --git a/clients/cloud-setup/tests/test-cloud-setup-general.c b/clients/cloud-setup/tests/test-cloud-setup-general.c deleted file mode 100644 index 63f3c13d..00000000 --- a/clients/cloud-setup/tests/test-cloud-setup-general.c +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nm-cloud-setup-utils.h" -#include "nm-libnm-core-intern/nm-libnm-core-utils.h" - -#include "nm-utils/nm-test-utils.h" - -/*****************************************************************************/ - -static NMSettingIPConfig * -_ri4a_new_s_ip(const char *const *addrs) -{ - NMSettingIPConfig *s_ip; - - s_ip = NM_SETTING_IP_CONFIG(nm_setting_ip4_config_new()); - - for (; addrs && addrs[0]; addrs++) { - nm_auto_unref_ip_address NMIPAddress *a = nmtst_ip_address_new(AF_INET, addrs[0]); - - nm_setting_ip_config_add_address(s_ip, a); - } - return s_ip; -} - -static GPtrArray * -_ri4a_new_arr(const char *const *addrs) -{ - GPtrArray *arr; - - arr = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); - - for (; addrs && addrs[0]; addrs++) - g_ptr_array_add(arr, nmtst_ip_address_new(AF_INET, addrs[0])); - - return arr; -} - -static void -_test_ri4a(const char *const *addrs_before, const char *const *addrs_new) -{ - gs_unref_object NMSettingIPConfig *s_ip = NULL; - gs_unref_ptrarray GPtrArray *arr = NULL; - const gsize n = NM_PTRARRAY_LEN(addrs_new); - gboolean changed; - gsize i; - - s_ip = _ri4a_new_s_ip(addrs_before); - arr = _ri4a_new_arr(addrs_new); - - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip), - ==, - NM_PTRARRAY_LEN(addrs_before)); - g_assert_cmpint(arr->len, ==, n); - - changed = nmcs_setting_ip_replace_ipv4_addresses(s_ip, (NMIPAddress **) arr->pdata, arr->len); - - g_assert_cmpint(changed, !=, nm_utils_strv_equal(addrs_before, addrs_new)); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip), ==, n); - - for (i = 0; i < n; i++) { - NMIPAddress *a = arr->pdata[i]; - NMIPAddress *b = nm_setting_ip_config_get_address(s_ip, i); - - if (nmtst_get_rand_bool()) - NM_SWAP(&a, &b); - - g_assert(nm_ip_address_cmp_full(a, b, NM_IP_ADDRESS_CMP_FLAGS_WITH_ATTRS) == 0); - } -} - -static void -test_replace_ipv4_addresses(void) -{ - const char *const *const LISTS[] = { - NM_MAKE_STRV(), - NM_MAKE_STRV("192.168.5.1/24"), - NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24"), - NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24", "192.168.5.3/24"), - NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24", "192.168.5.3/24", "192.168.5.4/24"), - }; - int i_run; - - for (i_run = 0; i_run < 20; i_run++) { - gs_free const char **addrs_before = NULL; - gs_free const char **addrs_new = NULL; - - addrs_before = nmtst_rand_perm_strv(LISTS[nmtst_get_rand_uint32() % G_N_ELEMENTS(LISTS)]); - addrs_new = nmtst_rand_perm_strv(LISTS[nmtst_get_rand_uint32() % G_N_ELEMENTS(LISTS)]); - - _test_ri4a(addrs_before, addrs_new); - } - - _test_ri4a(NM_MAKE_STRV(), NM_MAKE_STRV()); - _test_ri4a(NM_MAKE_STRV(), NM_MAKE_STRV("192.168.5.1/24")); - _test_ri4a(NM_MAKE_STRV(), NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24")); - _test_ri4a(NM_MAKE_STRV("192.168.5.1/24"), NM_MAKE_STRV()); - _test_ri4a(NM_MAKE_STRV("192.168.5.1/24"), NM_MAKE_STRV("192.168.5.1/24")); - _test_ri4a(NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24"), NM_MAKE_STRV()); - _test_ri4a(NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24"), NM_MAKE_STRV("192.168.5.1/24")); - _test_ri4a(NM_MAKE_STRV("192.168.5.1/24", "192.168.5.2/24"), NM_MAKE_STRV("192.168.5.2/24")); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init(&argc, &argv, TRUE); - - g_test_add_func("/cloud-setup/general/replace-ipv4-addresses", test_replace_ipv4_addresses); - - return g_test_run(); -} |