From aafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 5 Oct 2020 22:27:18 +0200 Subject: New upstream version 1.27.90 --- clients/cloud-setup/main.c | 956 ++++++++++---------- clients/cloud-setup/meson.build | 1 + clients/cloud-setup/nm-cloud-setup-utils.c | 1179 ++++++++++++------------- clients/cloud-setup/nm-cloud-setup-utils.h | 139 ++- clients/cloud-setup/nm-cloud-setup.service.in | 1 + clients/cloud-setup/nm-http-client.c | 1171 ++++++++++++------------ clients/cloud-setup/nm-http-client.h | 98 +- clients/cloud-setup/nmcs-provider-azure.c | 530 +++++++++++ clients/cloud-setup/nmcs-provider-azure.h | 28 + clients/cloud-setup/nmcs-provider-ec2.c | 887 +++++++++---------- clients/cloud-setup/nmcs-provider-ec2.h | 21 +- clients/cloud-setup/nmcs-provider-gcp.c | 802 ++++++++--------- clients/cloud-setup/nmcs-provider-gcp.h | 21 +- clients/cloud-setup/nmcs-provider.c | 250 +++--- clients/cloud-setup/nmcs-provider.h | 114 ++- 15 files changed, 3308 insertions(+), 2890 deletions(-) create mode 100644 clients/cloud-setup/nmcs-provider-azure.c create mode 100644 clients/cloud-setup/nmcs-provider-azure.h (limited to 'clients/cloud-setup') diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c index 78260b97..1baf0feb 100644 --- a/clients/cloud-setup/main.c +++ b/clients/cloud-setup/main.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -7,625 +7,599 @@ #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; + GMainLoop * main_loop; + GCancellable *cancellable; + NMCSProvider *provider_result; + guint detect_count; } ProviderDetectData; static void -_provider_detect_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_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; + 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); + success = nmcs_provider_detect_finish(provider, result, &error); - nm_assert (success != (!!error)); + nm_assert(success != (!!error)); - if (nm_utils_error_is_cancelled (error)) - return; + if (nm_utils_error_is_cancelled(error)) + return; - dd = user_data; + dd = user_data; - nm_assert (dd->detect_count > 0); - dd->detect_count--; + 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; - } + 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("no provider detected"); + goto done; + } - _LOGI ("provider %s detected", nmcs_provider_get_name (provider)); - dd->provider_result = g_steal_pointer (&provider); + _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); + g_cancellable_cancel(dd->cancellable); + g_main_loop_quit(dd->main_loop); } static void -_provider_detect_sigterm_cb (GCancellable *source, - gpointer user_data) +_provider_detect_sigterm_cb(GCancellable *source, gpointer user_data) { - ProviderDetectData *dd = 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); + 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) +_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, - }; - 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); + 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; + nm_clear_g_signal_handler(sigterm_cancellable, &cancellable_signal_id); + return dd.provider_result; } /*****************************************************************************/ static char ** -_nmc_get_hwaddrs (NMClient *nmc) +_nmc_get_hwaddrs(NMClient *nmc) { - gs_unref_ptrarray GPtrArray *hwaddrs = NULL; - const GPtrArray *devices; - char **hwaddrs_v; - gs_free char *str = NULL; - guint i; + 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); + devices = nm_client_get_devices(nmc); - for (i = 0; i < devices->len; i++) { - NMDevice *device = devices->pdata[i]; - const char *hwaddr; - char *s; + 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_IS_DEVICE_ETHERNET(device)) + continue; - if (nm_device_get_state (device) < NM_DEVICE_STATE_UNAVAILABLE) - 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; + 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; + 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) + hwaddrs = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(hwaddrs, s); + } - if (!hwaddrs) { - _LOGD ("found interfaces: none"); - return NULL; - } + 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); + 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))); + _LOGD("found interfaces: %s", (str = g_strjoinv(", ", hwaddrs_v))); - return hwaddrs_v; + return hwaddrs_v; } static NMDevice * -_nmc_get_device_by_hwaddr (NMClient *nmc, - const char *hwaddr) +_nmc_get_device_by_hwaddr(NMClient *nmc, const char *hwaddr) { - const GPtrArray *devices; - guint i; + const GPtrArray *devices; + guint i; - devices = nm_client_get_devices (nmc); + 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; + 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; + if (!NM_IS_DEVICE_ETHERNET(device)) + continue; - hwaddr_dev = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device)); - if (!hwaddr_dev) - 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; - } + s = nmcs_utils_hwaddr_normalize(hwaddr_dev, -1); + if (s && nm_streq(s, hwaddr)) + return device; + } - return NULL; + return NULL; } /*****************************************************************************/ typedef struct { - GMainLoop *main_loop; - GHashTable *config_dict; + GMainLoop * main_loop; + GHashTable *config_dict; } GetConfigData; static void -_get_config_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_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; + 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); + 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"); + 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); + 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) +_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; + 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); + hwaddrs = _nmc_get_hwaddrs(nmc); - nmcs_provider_get_config (provider, - TRUE, - (const char *const*) hwaddrs, - sigterm_cancellable, - _get_config_cb, - &data); + nmcs_provider_get_config(provider, + TRUE, + (const char *const *) hwaddrs, + sigterm_cancellable, + _get_config_cb, + &data); - g_main_loop_run (main_loop); + g_main_loop_run(main_loop); - return data.config_dict; + return data.config_dict; } /*****************************************************************************/ static gboolean -_nmc_skip_connection (NMConnection *connection) +_nmc_skip_connection(NMConnection *connection) { - NMSettingUser *s_user; - const char *v; + 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; + 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)); + 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); + 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) +_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]); - - if (addrs_new->len) { - addrs_changed = nmcs_setting_ip_replace_ipv4_addresses (s_ip, - (NMIPAddress **) addrs_new->pdata, - addrs_new->len); - } - - if (routes_new->len) { - routes_changed = nmcs_setting_ip_replace_ipv4_routes (s_ip, - (NMIPRoute **) routes_new->pdata, - routes_new->len); - } - - if (rules_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; + 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) +_config_data_get_num_valid(GHashTable *config_dict) { - const NMCSProviderGetConfigIfaceData *config_data; - GHashTableIter h_iter; - guint n = 0; + 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++; - } + 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; + return n; } static gboolean -_config_one (GCancellable *sigterm_cancellable, - NMClient *nmc, - gboolean is_single_nic, - const char *hwaddr, - const NMCSProviderGetConfigIfaceData *config_data) +_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; + 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; + 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) +_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; + 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); + 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; - } + 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; + return any_changes; } /*****************************************************************************/ static gboolean -sigterm_handler (gpointer user_data) +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; + 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) +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)); + 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); + 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 (); - } + 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); + nm_clear_g_source_inst(&sigterm_source); + g_clear_object(&sigterm_cancellable); - return 0; + return 0; } diff --git a/clients/cloud-setup/meson.build b/clients/cloud-setup/meson.build index 805d4681..c29d73df 100644 --- a/clients/cloud-setup/meson.build +++ b/clients/cloud-setup/meson.build @@ -29,6 +29,7 @@ sources = files( 'nm-http-client.c', 'nmcs-provider-ec2.c', 'nmcs-provider-gcp.c', + 'nmcs-provider-azure.c', 'nmcs-provider.c', ) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index ff059e7a..0820ed59 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -6,91 +6,96 @@ #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) +_nm_logging_enabled_init(const char *level_str) { - NMLogLevel level; + NMLogLevel level; - if (!_nm_log_parse_level (level_str, &level)) - level = LOGL_WARN; - else if (level == _LOGL_KEEP) - level = LOGL_WARN; + if (!_nm_log_parse_level(level_str, &level)) + level = LOGL_WARN; + else if (level == _LOGL_KEEP) + level = LOGL_WARN; - _nm_logging_configured_level = level; + _nm_logging_configured_level = level; } void -_nm_log_impl_cs (NMLogLevel level, - const char *fmt, - ...) +_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 = ""; break; - case LOGL_DEBUG: level_str = ""; break; - case LOGL_INFO: level_str = " "; break; - case LOGL_WARN: level_str = " "; break; - default: - nm_assert (level == LOGL_ERR); - level_str = ""; - 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); + 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 = ""; + break; + case LOGL_DEBUG: + level_str = ""; + break; + case LOGL_INFO: + level_str = " "; + break; + case LOGL_WARN: + level_str = " "; + break; + default: + nm_assert(level == LOGL_ERR); + level_str = ""; + 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) -{ -} +_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp, + gint64 offset_sec, + gboolean is_boottime) +{} /*****************************************************************************/ -G_LOCK_DEFINE_STATIC (_wait_for_objects_lock); +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) +_wait_for_objects_maybe_quit_mainloops_with_lock(void) { - GSList *iter; + GSList *iter; - if (!_wait_for_objects_list) { - for (iter = _wait_for_objects_iterate_loops; iter; iter = iter->next) - g_main_loop_quit (iter->data); - } + 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) +_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); + 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); } /** @@ -102,55 +107,53 @@ _wait_for_objects_weak_cb (gpointer data, * @target gets destroyed, which means that it gets completely unreferenced. */ gpointer -nmcs_wait_for_objects_register (gpointer target) +nmcs_wait_for_objects_register(gpointer target) { - g_return_val_if_fail (G_IS_OBJECT (target), NULL); + 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_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; + g_object_weak_ref(target, _wait_for_objects_weak_cb, NULL); + return target; } typedef struct { - GMainLoop *loop; - gboolean got_timeout; + GMainLoop *loop; + gboolean got_timeout; } WaitForObjectsData; static gboolean -_wait_for_objects_iterate_until_done_timeout_cb (gpointer user_data) +_wait_for_objects_iterate_until_done_timeout_cb(gpointer user_data) { - WaitForObjectsData *data = user_data; + WaitForObjectsData *data = user_data; - data->got_timeout = TRUE; - g_main_loop_quit (data->loop); - return G_SOURCE_CONTINUE; + 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) +_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; + /* 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; } /** @@ -168,211 +171,204 @@ _wait_for_objects_iterate_until_done_idle_cb (gpointer user_data) * 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) +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; + 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; + 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) +_poll_task_data_free(gpointer data) { - PollTaskData *poll_task_data = 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); + 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); + g_main_context_unref(poll_task_data->context); - nm_g_slice_free (poll_task_data); + nm_g_slice_free(poll_task_data); } static void -_poll_return (PollTaskData *poll_task_data, - gboolean success, - GError *error_take) +_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_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); + 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, success); + 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); + g_object_unref(poll_task_data->task); } -static gboolean _poll_start_cb (gpointer user_data); +static gboolean _poll_start_cb(gpointer user_data); static void -_poll_done_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_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, TRUE, 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); + 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) +_poll_start_cb(gpointer user_data) { - PollTaskData *poll_task_data = user_data; + PollTaskData *poll_task_data = user_data; - nm_clear_g_source_inst (&poll_task_data->source_next_poll); + nm_clear_g_source_inst(&poll_task_data->source_next_poll); - poll_task_data->last_poll_start_ms = nm_utils_get_monotonic_timestamp_msec (); + 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() */ + 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); + 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; + return G_SOURCE_CONTINUE; } static gboolean -_poll_timeout_cb (gpointer user_data) +_poll_timeout_cb(gpointer user_data) { - PollTaskData *poll_task_data = user_data; + PollTaskData *poll_task_data = user_data; - _poll_return (poll_task_data, FALSE, nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "timeout expired")); - return G_SOURCE_CONTINUE; + _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) +_poll_cancelled_cb(GObject *object, gpointer user_data) { - PollTaskData *poll_task_data = user_data; - GError *error = NULL; - - _LOGD (">> poll cancelled"); - 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, FALSE, error); + 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 (but no error set). + * 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 (asynchrnous) probe. A probe must be completed + * @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(). @@ -388,63 +384,62 @@ _poll_cancelled_cb (GObject *object, gpointer user_data) * 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) +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; - } + 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; + } } /** @@ -459,378 +454,376 @@ nmcs_utils_poll (int poll_timeout_ms, * %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 without error set. + * 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) +nmcs_utils_poll_finish(GAsyncResult *result, gpointer *probe_user_data, GError **error) { - GTask *task; - PollTaskData *poll_task_data; + 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); + 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); + 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); - } + 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); + return g_task_propagate_boolean(task, error); } /*****************************************************************************/ char * -nmcs_utils_hwaddr_normalize (const char *hwaddr, gssize len) +nmcs_utils_hwaddr_normalize(const char *hwaddr, gssize len) { - gs_free char *hwaddr_clone = NULL; - guint8 buf[ETH_ALEN]; - - nm_assert (len >= -1); - - if (len < 0) { - if (!hwaddr) - return NULL; - } else { - if (len == 0) - return NULL; - nm_assert (hwaddr); - hwaddr = nm_strndup_a (300, hwaddr, len, &hwaddr_clone); - } - - if (!nm_utils_hwaddr_aton (hwaddr, buf, sizeof (buf))) - return NULL; - - return nm_utils_hwaddr_ntoa (buf, sizeof (buf)); + gs_free char *hwaddr_clone = NULL; + guint8 buf[ETH_ALEN]; + + nm_assert(len >= -1); + + if (len < 0) { + if (!hwaddr) + return NULL; + } else { + if (len == 0) + return NULL; + nm_assert(hwaddr); + hwaddr = nm_strndup_a(300, hwaddr, len, &hwaddr_clone); + } + /* 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(hwaddr, + FALSE, + FALSE, + FALSE, + ":-", + sizeof(buf), + buf, + sizeof(buf), + NULL)) + return NULL; + + return nm_utils_hwaddr_ntoa(buf, sizeof(buf)); } /*****************************************************************************/ const char * -nmcs_utils_parse_memmem (GBytes *mem, const char *needle) +nmcs_utils_parse_memmem(GBytes *mem, const char *needle) { - const char *mem_data; - gsize mem_size; + const char *mem_data; + gsize mem_size; - g_return_val_if_fail (mem, NULL); - g_return_val_if_fail (needle, NULL); + 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)); + 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) +nmcs_utils_parse_get_full_line(GBytes *mem, const char *needle) { - const char *mem_data; - gsize mem_size; - gsize c; - gsize l; + const char *mem_data; + gsize mem_size; + gsize c; + gsize l; - const char *line; + const char *line; - line = nmcs_utils_parse_memmem (mem, needle); - if (!line) - return NULL; + line = nmcs_utils_parse_memmem(mem, needle); + if (!line) + return NULL; - mem_data = g_bytes_get_data (mem, &mem_size); + 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; - } + 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); + 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; - } + 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; + return line; } /*****************************************************************************/ char * -nmcs_utils_uri_build_concat_v (const char *base, - const char **components, - gsize n_components) +nmcs_utils_uri_build_concat_v(const char *base, const char **components, gsize n_components) { - GString *uri; - - nm_assert (base); - nm_assert (base[0]); - nm_assert (!NM_STR_HAS_SUFFIX (base, "/")); - - uri = g_string_sized_new (100); - - g_string_append (uri, 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 - g_string_append_c (uri, '/'); - - while (n_components > 0) { - if (!components[0]) { - /* we allow NULL, to indicate nothing to append*/ - } else - g_string_append (uri, components[0]); - components++; - n_components--; - } - - return g_string_free (uri, FALSE); + 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) +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 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) +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 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) +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; + 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; + 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) +_nmcs_device_get_applied_connection_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - DeviceGetAppliedConnectionData *data = 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); + 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) +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; + 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; + GMainLoop *main_loop; + GError * error; } DeviceReapplyData; static void -_nmcs_device_reapply_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_nmcs_device_reapply_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - DeviceReapplyData *data = user_data; + DeviceReapplyData *data = user_data; - nm_device_reapply_finish (NM_DEVICE (source), - result, - &data->error); - g_main_loop_quit (data->main_loop); + 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) +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; + 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 index 7c3e267a..6980e752 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.h +++ b/clients/cloud-setup/nm-cloud-setup-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_CLOUD_SETUP_UTILS_H__ #define __NM_CLOUD_SETUP_UTILS_H__ @@ -9,119 +9,114 @@ /* 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"" +#define NMCS_ENV_VARIABLE(var) "" var "" /*****************************************************************************/ extern volatile NMLogLevel _nm_logging_configured_level; static inline gboolean -nm_logging_enabled (NMLogLevel level) +nm_logging_enabled(NMLogLevel level) { - return level >= _nm_logging_configured_level; + return level >= _nm_logging_configured_level; } -void _nm_logging_enabled_init (const char *level_str); +void _nm_logging_enabled_init(const char *level_str); -void _nm_log_impl_cs (NMLogLevel level, - const char *fmt, - ...) _nm_printf (2, 3); +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 _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 +#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 + #define NM_DIST_VERSION VERSION #endif /*****************************************************************************/ -gpointer nmcs_wait_for_objects_register (gpointer target); +gpointer nmcs_wait_for_objects_register(gpointer target); -gboolean nmcs_wait_for_objects_iterate_until_done (GMainContext *context, - int timeout_msec); +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); +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); +char *nmcs_utils_hwaddr_normalize(const char *hwaddr, gssize len); /*****************************************************************************/ -const char *nmcs_utils_parse_memmem (GBytes *mem, const char *needle); +const char *nmcs_utils_parse_memmem(GBytes *mem, const char *needle); -const char *nmcs_utils_parse_get_full_line (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); +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__)) +#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_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_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); +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); +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 index 9866acd8..57f9e931 100644 --- a/clients/cloud-setup/nm-cloud-setup.service.in +++ b/clients/cloud-setup/nm-cloud-setup.service.in @@ -13,6 +13,7 @@ ExecStart=@libexecdir@/nm-cloud-setup # the provider. #Environment=NM_CLOUD_SETUP_EC2=yes #Environment=NM_CLOUD_SETUP_GCP=yes +#Environment=NM_CLOUD_SETUP_AZURE=yes CapabilityBoundingSet= LockPersonality=yes diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index b4260ffe..221e8c71 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -7,780 +7,795 @@ #include #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; + GMainContext *context; + CURLM * mhandle; + GSource * mhandle_source_timeout; + GHashTable * source_sockets_hashtable; } NMHttpClientPrivate; struct _NMHttpClient { - GObject parent; - NMHttpClientPrivate _priv; + GObject parent; + NMHttpClientPrivate _priv; }; struct _NMHttpClientClass { - GObjectClass parent; + GObjectClass parent; }; -G_DEFINE_TYPE (NMHttpClient, nm_http_client, G_TYPE_OBJECT); +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 +#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); +G_LOCK_DEFINE_STATIC(_my_curl_initalized_lock); static bool _my_curl_initialized = FALSE; -__attribute__((destructor)) -static void -_my_curl_global_cleanup (void) +__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); + 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) +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); + 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) +nm_http_client_get_main_context(NMHttpClient *self) { - g_return_val_if_fail (NM_IS_HTTP_CLIENT (self), NULL); + g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), NULL); - return NM_HTTP_CLIENT_GET_PRIVATE (self)->context; + return NM_HTTP_CLIENT_GET_PRIVATE(self)->context; } /*****************************************************************************/ static GSource * -_source_attach (NMHttpClient *self, - GSource *source) +_source_attach(NMHttpClient *self, GSource *source) { - return nm_g_source_attach (source, NM_HTTP_CLIENT_GET_PRIVATE (self)->context); + return nm_g_source_attach(source, NM_HTTP_CLIENT_GET_PRIVATE(self)->context); } /*****************************************************************************/ typedef struct { - long response_code; - GBytes *response_data; + long response_code; + GBytes *response_data; } GetResult; static void -_get_result_free (gpointer data) +_get_result_free(gpointer data) { - GetResult *get_result = data; + GetResult *get_result = data; - g_bytes_unref (get_result->response_data); - nm_g_slice_free (get_result); + 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; - GString *recv_data; - struct curl_slist *headers; - gssize max_data; - gulong cancellable_id; + 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) +_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); + 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)); - } + curl_multi_remove_handle(priv->mhandle, edata->ehandle); + curl_easy_cleanup(g_steal_pointer(&edata->ehandle)); + } } static void -_ehandle_free (EHandleData *edata) +_ehandle_free(EHandleData *edata) { - nm_assert (!edata->ehandle); - nm_assert (!edata->timeout_source); + nm_assert(!edata->ehandle); + nm_assert(!edata->timeout_source); - g_object_unref (edata->task); + g_object_unref(edata->task); - if (edata->recv_data) - g_string_free (edata->recv_data, TRUE); - if (edata->headers) - curl_slist_free_all (edata->headers); - g_free (edata->url); - nm_g_slice_free (edata); + 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) +_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 (edata->recv_data->str, 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 = g_string_free_to_bytes (g_steal_pointer (&edata->recv_data)), - }; - - g_task_return_pointer (edata->task, get_result, _get_result_free); - - _ehandle_free (edata); + 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) +_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; - - g_string_append_len (edata->recv_data, ptr, nconsume); - return nconsume; + 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) +_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; + _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) +_get_cancelled_cb(GObject *object, gpointer user_data) { - EHandleData *edata = user_data; - GError *error = NULL; + 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); + 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) +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 = g_string_sized_new (NM_MIN (max_data, 245)), - .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; - } + 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) +nm_http_client_get_finish(NMHttpClient *self, + GAsyncResult *result, + long * out_response_code, + GBytes ** out_response_data, + GError ** error) { - GetResult *get_result; + 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); - 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); - get_result = g_task_propagate_pointer (G_TASK (result), error); - if (!get_result) { - NM_SET_OUT (out_response_code, -1); - NM_SET_OUT (out_response_data, NULL); - return FALSE; - } + nm_assert(!error || (!!get_result) == (!*error)); - NM_SET_OUT (out_response_code, get_result->response_code); + if (!get_result) { + NM_SET_OUT(out_response_code, -1); + NM_SET_OUT(out_response_data, NULL); + return FALSE; + } - /* 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)); + NM_SET_OUT(out_response_code, get_result->response_code); - _get_result_free (get_result); + /* 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)); - return TRUE; + _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; + 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) +_poll_get_data_free(gpointer data) { - PollGetData *poll_get_data = data; + PollGetData *poll_get_data = data; - g_free (poll_get_data->uri); + 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_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); + 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) +_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); + 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) +_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); - - if (!success) { - if (nm_utils_error_is_cancelled (local_error)) { - g_propagate_error (error, g_steal_pointer (&local_error)); - return TRUE; - } - 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) - return FALSE; - - poll_get_data->response_code = response_code; - poll_get_data->response_data = g_steal_pointer (&response_data); - return TRUE; + 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) +_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; + PollGetData * poll_get_data = user_data; + gs_free_error GError *error = NULL; + gboolean success; + + success = nmcs_utils_poll_finish(result, NULL, &error); - 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, success); + 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); + 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_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); + 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) +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; + 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); - 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); - task = G_TASK (result); + success = g_task_propagate_boolean(task, &local_error); - success = g_task_propagate_boolean (task, &local_error); - if ( local_error - || !success) { - 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; - } + nm_assert((!!success) == (!local_error)); - poll_get_data = g_task_get_task_data (task); + 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; + } - 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)); + poll_get_data = g_task_get_task_data(task); - return TRUE; + 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) +_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); - } + 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) +_mhandle_socket_cb(int fd, GIOCondition condition, gpointer user_data) { - int ev_bitmask = 0; + 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; + 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; + _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) +_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; + 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_timeout_cb(gpointer user_data) { - _mhandle_action (user_data, CURL_SOCKET_TIMEOUT, 0); - return G_SOURCE_REMOVE; + _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) +_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; + 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) +nm_http_client_init(NMHttpClient *self) { - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (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); + 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) +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 * 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) +nm_http_client_new(void) { - return g_object_new (NM_TYPE_HTTP_CLIENT, NULL); + return g_object_new(NM_TYPE_HTTP_CLIENT, NULL); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMHttpClient *self = NM_HTTP_CLIENT (object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); + 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_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); + nm_clear_g_source_inst(&priv->mhandle_source_timeout); - G_OBJECT_CLASS (nm_http_client_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_http_client_parent_class)->dispose(object); } static void -finalize (GObject *object) +finalize(GObject *object) { - NMHttpClient *self = NM_HTTP_CLIENT (object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); + 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_OBJECT_CLASS(nm_http_client_parent_class)->finalize(object); - g_main_context_unref (priv->context); + g_main_context_unref(priv->context); - curl_global_cleanup (); + curl_global_cleanup(); } static void -nm_http_client_class_init (NMHttpClientClass *klass) +nm_http_client_class_init(NMHttpClientClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->finalize = finalize; + object_class->constructed = constructed; + object_class->dispose = dispose; + object_class->finalize = finalize; - nm_http_client_curl_global_init (); + nm_http_client_curl_global_init(); } diff --git a/clients/cloud-setup/nm-http-client.h b/clients/cloud-setup/nm-http-client.h index ef7c984a..fc465e35 100644 --- a/clients/cloud-setup/nm-http-client.h +++ b/clients/cloud-setup/nm-http-client.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_HTTP_CLIENT_C__ #define __NM_HTTP_CLIENT_C__ @@ -8,61 +8,63 @@ 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)) +#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); +GType nm_http_client_get_type(void); -NMHttpClient *nm_http_client_new (void); +NMHttpClient *nm_http_client_new(void); /*****************************************************************************/ -GMainContext *nm_http_client_get_main_context (NMHttpClient *self); +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); +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); /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider-azure.c b/clients/cloud-setup/nmcs-provider-azure.c new file mode 100644 index 00000000..1a80327c --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-azure.c @@ -0,0 +1,530 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "nm-default.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 *config_data; + guint n_ifaces_pending; + GError * error; +} AzureData; + +typedef struct { + NMCSProviderGetConfigIfaceData *iface_get_config; + AzureData * azure_data; + gssize iface_idx; + guint n_ips_prefix_pending; + char * hwaddr; +} AzureIfaceData; + +static void +_azure_iface_data_free(AzureIfaceData *iface_data) +{ + g_free(iface_data->hwaddr); + nm_g_slice_free(iface_data); +} + +static void +_get_config_maybe_task_return(AzureData *azure_data, GError *error_take) +{ + NMCSProviderGetConfigTaskData *config_data = azure_data->config_data; + + if (error_take) { + if (!azure_data->error) + azure_data->error = error_take; + else if (!nm_utils_error_is_cancelled(azure_data->error) + && nm_utils_error_is_cancelled(error_take)) { + nm_clear_error(&azure_data->error); + azure_data->error = error_take; + } else + g_error_free(error_take); + } + + if (azure_data->n_ifaces_pending > 0) + return; + + if (azure_data->error) { + if (nm_utils_error_is_cancelled(azure_data->error)) + _LOGD("get-config: cancelled"); + else + _LOGD("get-config: failed: %s", azure_data->error->message); + g_task_return_error(config_data->task, g_steal_pointer(&azure_data->error)); + } else { + _LOGD("get-config: success"); + g_task_return_pointer(config_data->task, + g_hash_table_ref(config_data->result_dict), + (GDestroyNotify) g_hash_table_unref); + } + + nm_g_slice_free(azure_data); + g_object_unref(config_data->task); +} + +static void +_get_config_fetch_done_cb(NMHttpClient *http_client, + GAsyncResult *result, + gpointer user_data, + gboolean is_ipv4) +{ + NMCSProviderGetConfigIfaceData *iface_get_config; + gs_unref_bytes GBytes *response = NULL; + AzureIfaceData * iface_data = user_data; + gs_free_error GError *error = NULL; + const char * fip_str = NULL; + AzureData * azure_data; + + azure_data = iface_data->azure_data; + + nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); + + if (error) + goto done; + + if (!error) { + in_addr_t tmp_addr; + int tmp_prefix; + + fip_str = g_bytes_get_data(response, NULL); + iface_data->iface_get_config = + g_hash_table_lookup(azure_data->config_data->result_dict, iface_data->hwaddr); + iface_get_config = iface_data->iface_get_config; + iface_get_config->iface_idx = iface_data->iface_idx; + + if (is_ipv4) { + if (!nm_utils_parse_inaddr_bin(AF_INET, fip_str, NULL, &tmp_addr)) { + error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, + "ip is not a valid private ip address"); + goto done; + } + _LOGD("interface[%" G_GSSIZE_FORMAT "]: adding private ip %s", + iface_data->iface_idx, + fip_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 { + 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 %d", + iface_data->iface_idx, + tmp_prefix); + goto done; + } + _LOGD("interface[%" G_GSSIZE_FORMAT "]: adding prefix %d", + iface_data->iface_idx, + tmp_prefix); + iface_get_config->cidr_prefix = tmp_prefix; + iface_get_config->has_cidr = TRUE; + } + } + +done: + --iface_data->n_ips_prefix_pending; + if (iface_data->n_ips_prefix_pending == 0) { + _azure_iface_data_free(iface_data); + --azure_data->n_ifaces_pending; + _get_config_maybe_task_return(azure_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; + AzureData * azure_data; + const char * line; + gsize line_len; + + azure_data = iface_data->azure_data; + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (error) + goto done; + + 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_data 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->iface_idx, + ips_prefix_idx))), + HTTP_TIMEOUT_MS, + 512 * 1024, + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), + g_task_get_cancellable(azure_data->config_data->task), + 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->iface_idx), + "/ipv4/subnet/0/prefix/")), + HTTP_TIMEOUT_MS, + 512 * 1024, + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), + g_task_get_cancellable(azure_data->config_data->task), + NULL, + NULL, + _get_config_fetch_done_cb_subnet_cidr_prefix, + iface_data); + } + return; + +done: + _azure_iface_data_free(iface_data); + --azure_data->n_ifaces_pending; + _get_config_maybe_task_return(azure_data, g_steal_pointer(&error)); +} + +static void +_get_config_iface_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; + gs_free const char * uri = NULL; + char buf[100]; + AzureData * azure_data; + + azure_data = iface_data->azure_data; + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (error) + goto done; + + iface_data->hwaddr = nmcs_utils_hwaddr_normalize(g_bytes_get_data(response, NULL), -1); + + if (!iface_data->hwaddr) { + goto done; + } + + iface_data->iface_get_config = + g_hash_table_lookup(azure_data->config_data->result_dict, iface_data->hwaddr); + + if (!iface_data->iface_get_config) { + if (!iface_data->azure_data->config_data->any) { + _LOGD("interface[%" G_GSSIZE_FORMAT "]: ignore hwaddr %s", + iface_data->iface_idx, + iface_data->hwaddr); + goto done; + } + iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE); + g_hash_table_insert(azure_data->config_data->result_dict, + g_strdup(iface_data->hwaddr), + iface_data->iface_get_config); + } + + _LOGD("interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s", + iface_data->iface_idx, + iface_data->hwaddr); + + nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/", iface_data->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), + g_task_get_cancellable(azure_data->config_data->task), + NULL, + NULL, + _get_config_ips_prefix_list_cb, + iface_data); + return; + +done: + nm_g_slice_free(iface_data); + --azure_data->n_ifaces_pending; + _get_config_maybe_task_return(azure_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; + AzureData * azure_data = user_data; + const char * response_str; + 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 (error) { + _get_config_maybe_task_return(azure_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(); + + while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { + AzureIfaceData *iface_data; + gssize iface_idx; + + if (line_len == 0) + continue; + + /* Truncate the string. It's safe to do, because we own @response_data 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'; + + iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); + if (iface_idx < 0) + continue; + + iface_data = g_slice_new(AzureIfaceData); + *iface_data = (AzureIfaceData){ + .iface_get_config = NULL, + .azure_data = azure_data, + .iface_idx = iface_idx, + .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) { + error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no Azure interfaces found"); + _get_config_maybe_task_return(azure_data, g_steal_pointer(&error)); + return; + } + + for (i = 0; i < ifaces_arr->len; ++i) { + AzureIfaceData * data = ifaces_arr->pdata[i]; + gs_free const char *uri = NULL; + char buf[100]; + + _LOGD("azure interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", data->iface_idx); + + nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", data->iface_idx); + + azure_data->n_ifaces_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), + g_task_get_cancellable(azure_data->config_data->task), + NULL, + NULL, + _get_config_iface_cb, + data); + } +} + +static void +get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) +{ + gs_free const char *uri = NULL; + AzureData * azure_data; + + azure_data = g_slice_new(AzureData); + *azure_data = (AzureData){ + .config_data = get_config_data, + .n_ifaces_pending = 0, + }; + + 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), + g_task_get_cancellable(get_config_data->task), + NULL, + NULL, + _get_net_ifaces_list_cb, + azure_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 new file mode 100644 index 00000000..849e94c1 --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-azure.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#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 index 3b5f6d36..fb82914f 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -10,550 +10,509 @@ #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/" +#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) +_ec2_base(void) { - static const char *base_cached = NULL; - const char *base; + 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; + 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__) +#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; + NMCSProvider parent; }; struct _NMCSProviderEC2Class { - NMCSProviderClass parent; + NMCSProviderClass parent; }; -G_DEFINE_TYPE (NMCSProviderEC2, nmcs_provider_ec2, NMCS_TYPE_PROVIDER); +G_DEFINE_TYPE(NMCSProviderEC2, nmcs_provider_ec2, NMCS_TYPE_PROVIDER); /*****************************************************************************/ static gboolean -_detect_get_meta_data_check_cb (long response_code, - GBytes *response_data, - gpointer check_user_data, - GError **error) +_detect_get_meta_data_check_cb(long response_code, + GBytes * response_data, + gpointer check_user_data, + GError **error) { - return response_code == 200 - && nmcs_utils_parse_get_full_line (response_data, "ami-id"); + return response_code == 200 && nmcs_utils_parse_get_full_line(response_data, "ami-id"); } static void -_detect_get_meta_data_done_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_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 EC2 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 EC2 metadata"); - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - - g_task_return_boolean (task, TRUE); + 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) +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); + 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); } /*****************************************************************************/ typedef struct { - NMCSProviderGetConfigTaskData *get_config_data; - GCancellable *cancellable; - gulong cancelled_id; - guint n_pending; + NMCSProviderGetConfigTaskData *get_config_data; + GError * error; + GCancellable * cancellable; + gulong cancelled_id; + guint n_pending; } GetConfigIfaceData; static void -_get_config_task_return (GetConfigIfaceData *iface_data, - GError *error_take) +_get_config_task_maybe_return(GetConfigIfaceData *iface_data, GError *error_take) { - NMCSProviderGetConfigTaskData *get_config_data = iface_data->get_config_data; - - nm_clear_g_cancellable_disconnect (g_task_get_cancellable (get_config_data->task), - &iface_data->cancelled_id); - - nm_clear_g_cancellable (&iface_data->cancellable); - - nm_g_slice_free (iface_data); - - if (error_take) { - if (nm_utils_error_is_cancelled (error_take)) - _LOGD ("get-config: cancelled"); - else - _LOGD ("get-config: failed: %s", error_take->message); - g_task_return_error (get_config_data->task, error_take); - } 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); - } - - g_object_unref (get_config_data->task); + NMCSProviderGetConfigTaskData *get_config_data = iface_data->get_config_data; + + if (error_take) { + if (!iface_data->error) + iface_data->error = error_take; + else if (!nm_utils_error_is_cancelled(iface_data->error) + && nm_utils_error_is_cancelled(error_take)) { + nm_clear_error(&iface_data->error); + iface_data->error = error_take; + } else + g_error_free(error_take); + } + + if (iface_data->n_pending > 0) + return; + + nm_clear_g_cancellable_disconnect(g_task_get_cancellable(get_config_data->task), + &iface_data->cancelled_id); + + nm_clear_g_cancellable(&iface_data->cancellable); + + if (iface_data->error) { + if (nm_utils_error_is_cancelled(iface_data->error)) + _LOGD("get-config: cancelled"); + else + _LOGD("get-config: failed: %s", iface_data->error->message); + g_task_return_error(get_config_data->task, g_steal_pointer(&iface_data->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_g_slice_free(iface_data); + g_object_unref(get_config_data->task); } static void -_get_config_fetch_done_cb (NMHttpClient *http_client, - GAsyncResult *result, - gpointer user_data, - gboolean is_local_ipv4) +_get_config_fetch_done_cb(NMHttpClient *http_client, + GAsyncResult *result, + gpointer user_data, + gboolean is_local_ipv4) { - GetConfigIfaceData *iface_data; - NMCSProviderGetConfigTaskData *get_config_data; - const char *hwaddr = NULL; - gs_unref_bytes GBytes *response_data = NULL; - gs_free_error GError *error = NULL; - gboolean success; - NMCSProviderGetConfigIfaceData *config_iface_data; - - nm_utils_user_data_unpack (user_data, &iface_data, &hwaddr); - - success = nm_http_client_poll_get_finish (http_client, - result, - NULL, - &response_data, - &error); - if (nm_utils_error_is_cancelled (error)) - return; - - get_config_data = iface_data->get_config_data; - - config_iface_data = g_hash_table_lookup (get_config_data->result_dict, hwaddr); - - if (success) { - in_addr_t tmp_addr; - int tmp_prefix; - - 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_data, 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_data, 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; - } - } - } - - if (--iface_data->n_pending > 0) - return; - - _get_config_task_return (iface_data, NULL); + GetConfigIfaceData *iface_data; + const char * hwaddr = NULL; + gs_unref_bytes GBytes *response_data = NULL; + gs_free_error GError *error = NULL; + + nm_utils_user_data_unpack(user_data, &iface_data, &hwaddr); + + nm_http_client_poll_get_finish(http_client, result, NULL, &response_data, &error); + + if (!error) { + NMCSProviderGetConfigIfaceData *config_iface_data; + in_addr_t tmp_addr; + int tmp_prefix; + + config_iface_data = g_hash_table_lookup(iface_data->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_data, 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_data, 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; + } + } + } + + iface_data->n_pending--; + _get_config_task_maybe_return(iface_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_subnet_ipv4_cidr_block(GObject * source, + GAsyncResult *result, + gpointer user_data) { - _get_config_fetch_done_cb (NM_HTTP_CLIENT (source), result, user_data, FALSE); + _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_local_ipv4s(GObject *source, GAsyncResult *result, gpointer user_data) { - _get_config_fetch_done_cb (NM_HTTP_CLIENT (source), result, user_data, TRUE); + _get_config_fetch_done_cb(NM_HTTP_CLIENT(source), result, user_data, TRUE); } static void -_get_config_fetch_cancelled_cb (GObject *object, gpointer user_data) +_get_config_fetch_cancelled_cb(GObject *object, gpointer user_data) { - GetConfigIfaceData *iface_data = user_data; + GetConfigIfaceData *iface_data = user_data; - if (iface_data->cancelled_id == 0) - return; + if (iface_data->cancelled_id == 0) + return; - nm_clear_g_signal_handler (g_task_get_cancellable (iface_data->get_config_data->task), - &iface_data->cancelled_id); - _get_config_task_return (iface_data, - nm_utils_error_new_cancelled (FALSE, NULL)); + nm_clear_g_signal_handler(g_task_get_cancellable(iface_data->get_config_data->task), + &iface_data->cancelled_id); + _get_config_task_maybe_return(iface_data, nm_utils_error_new_cancelled(FALSE, NULL)); } typedef struct { - NMCSProviderGetConfigTaskData *get_config_data; - GHashTable *response_parsed; + NMCSProviderGetConfigTaskData *get_config_data; + GHashTable * response_parsed; } GetConfigMetadataData; typedef struct { - gssize iface_idx; - char path[0]; + gssize iface_idx; + char path[0]; } GetConfigMetadataMac; static void -_get_config_metadata_ready_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - GetConfigMetadataData *metadata_data = user_data; - GetConfigIfaceData *iface_data; - NMCSProviderGetConfigTaskData *get_config_data = metadata_data->get_config_data; - gs_unref_hashtable GHashTable *response_parsed = g_steal_pointer (&metadata_data->response_parsed); - gs_free_error GError *error = NULL; - GCancellable *cancellable; - GetConfigMetadataMac *v_mac_data; - const char *v_hwaddr; - GHashTableIter h_iter; - NMHttpClient *http_client; - - nm_g_slice_free (metadata_data); - - nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - NULL, - &error); - - iface_data = g_slice_new (GetConfigIfaceData); - *iface_data = (GetConfigIfaceData) { - .get_config_data = get_config_data, - .n_pending = 0, - }; - - if (nm_utils_error_is_cancelled (error)) { - _get_config_task_return (iface_data, g_steal_pointer (&error)); - return; - } - - /* 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) { - _get_config_task_return (iface_data, - nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "meta data for interfaces not found")); - return; - } - - cancellable = g_task_get_cancellable (get_config_data->task); - if (cancellable) { - gulong cancelled_id; - - cancelled_id = g_cancellable_connect (cancellable, - G_CALLBACK (_get_config_fetch_cancelled_cb), - iface_data, - NULL); - if (cancelled_id == 0) { - _get_config_task_return (iface_data, - nm_utils_error_new_cancelled (FALSE, NULL)); - return; - } - - iface_data->cancelled_id = cancelled_id; - } - - iface_data->cancellable = g_cancellable_new (); - - 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); - - iface_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, - iface_data->cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_subnet_ipv4_cidr_block, - nm_utils_user_data_pack (iface_data, hwaddr)); - - iface_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, - iface_data->cancellable, - NULL, - NULL, - _get_config_fetch_done_cb_local_ipv4s, - nm_utils_user_data_pack (iface_data, hwaddr)); - } - - if (iface_data->n_pending == 0) - _get_config_task_return (iface_data, NULL); + GetConfigMetadataData * metadata_data = user_data; + GetConfigIfaceData * iface_data; + NMCSProviderGetConfigTaskData *get_config_data = metadata_data->get_config_data; + gs_unref_hashtable GHashTable *response_parsed = + g_steal_pointer(&metadata_data->response_parsed); + gs_free_error GError *error = NULL; + GCancellable * cancellable; + GetConfigMetadataMac *v_mac_data; + const char * v_hwaddr; + GHashTableIter h_iter; + NMHttpClient * http_client; + + nm_g_slice_free(metadata_data); + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); + + iface_data = g_slice_new(GetConfigIfaceData); + *iface_data = (GetConfigIfaceData){ + .get_config_data = get_config_data, + .n_pending = 0, + }; + + if (nm_utils_error_is_cancelled(error)) { + _get_config_task_maybe_return(iface_data, g_steal_pointer(&error)); + return; + } + + /* 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) { + _get_config_task_maybe_return( + iface_data, + nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "meta data for interfaces not found")); + return; + } + + cancellable = g_task_get_cancellable(get_config_data->task); + if (cancellable) { + gulong cancelled_id; + + cancelled_id = g_cancellable_connect(cancellable, + G_CALLBACK(_get_config_fetch_cancelled_cb), + iface_data, + NULL); + if (cancelled_id == 0) { + _get_config_task_maybe_return(iface_data, nm_utils_error_new_cancelled(FALSE, NULL)); + return; + } + + iface_data->cancelled_id = cancelled_id; + } + + iface_data->cancellable = g_cancellable_new(); + + 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); + + iface_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, + iface_data->cancellable, + NULL, + NULL, + _get_config_fetch_done_cb_subnet_ipv4_cidr_block, + nm_utils_user_data_pack(iface_data, hwaddr)); + + iface_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, + iface_data->cancellable, + NULL, + NULL, + _get_config_fetch_done_cb_local_ipv4s, + nm_utils_user_data_pack(iface_data, hwaddr)); + } + + _get_config_task_maybe_return(iface_data, NULL); } static gboolean -_get_config_metadata_ready_check (long response_code, - GBytes *response_data, - gpointer check_user_data, - GError **error) +_get_config_metadata_ready_check(long response_code, + GBytes * response_data, + gpointer check_user_data, + GError **error) { - GetConfigMetadataData *metadata_data = check_user_data; - gs_unref_hashtable GHashTable *response_parsed = NULL; - const guint8 *r_data; - gsize r_len; - GHashTableIter h_iter; - gboolean has_all; - const char *c_hwaddr; - gssize iface_idx_counter = 0; - - if ( response_code != 200 - || !response_data) { - /* we wait longer. */ - return FALSE; - } - - r_data = g_bytes_get_data (response_data, &r_len); - - while (r_len > 0) { - const guint8 *p_eol; - const char *p_start; - gsize p_start_l; - gsize p_start_l_2; - char *hwaddr; - GetConfigMetadataMac *mac_data; - - p_start = (const char *) r_data; - - p_eol = memchr (r_data, '\n', r_len); - if (p_eol) { - p_start_l = (p_eol - r_data); - r_len -= p_start_l + 1; - r_data = &p_eol[1]; - } else { - p_start_l = r_len; - r_data = &r_data[r_len]; - r_len = 0; - } - - if (p_start_l == 0) - continue; - - p_start_l_2 = p_start_l; - if (p_start[p_start_l_2 - 1] == '/') { - /* trim the trailing "/". */ - p_start_l_2--; - } - - hwaddr = nmcs_utils_hwaddr_normalize (p_start, p_start_l_2); - 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) + 1 + p_start_l); - mac_data->iface_idx = iface_idx_counter++; - memcpy (mac_data->path, p_start, p_start_l); - mac_data->path[p_start_l] = '\0'; - - g_hash_table_insert (response_parsed, hwaddr, mac_data); - } - - has_all = TRUE; - g_hash_table_iter_init (&h_iter, metadata_data->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 (&metadata_data->response_parsed, g_hash_table_unref); - metadata_data->response_parsed = g_steal_pointer (&response_parsed); - return has_all; + GetConfigMetadataData *metadata_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_data) { + /* we wait longer. */ + return FALSE; + } + + r_data = g_bytes_get_data(response_data, &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_data 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); + + g_hash_table_insert(response_parsed, hwaddr, mac_data); + } + + has_all = TRUE; + g_hash_table_iter_init(&h_iter, metadata_data->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(&metadata_data->response_parsed, g_hash_table_unref); + metadata_data->response_parsed = g_steal_pointer(&response_parsed); + return has_all; } static void -get_config (NMCSProvider *provider, - NMCSProviderGetConfigTaskData *get_config_data) +get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { - gs_free char *uri = NULL; - GetConfigMetadataData *metadata_data; - - metadata_data = g_slice_new (GetConfigMetadataData); - *metadata_data = (GetConfigMetadataData) { - .get_config_data = get_config_data, - }; - - /* 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, - g_task_get_cancellable (get_config_data->task), - _get_config_metadata_ready_check, - metadata_data, - _get_config_metadata_ready_cb, - metadata_data); + gs_free char * uri = NULL; + GetConfigMetadataData *metadata_data; + + metadata_data = g_slice_new(GetConfigMetadataData); + *metadata_data = (GetConfigMetadataData){ + .get_config_data = get_config_data, + }; + + /* 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, + g_task_get_cancellable(get_config_data->task), + _get_config_metadata_ready_check, + metadata_data, + _get_config_metadata_ready_cb, + metadata_data); } /*****************************************************************************/ static void -nmcs_provider_ec2_init (NMCSProviderEC2 *self) -{ -} +nmcs_provider_ec2_init(NMCSProviderEC2 *self) +{} static void -nmcs_provider_ec2_class_init (NMCSProviderEC2Class *klass) +nmcs_provider_ec2_class_init(NMCSProviderEC2Class *klass) { - NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS (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; + 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 index 763c3af8..b5f178f5 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.h +++ b/clients/cloud-setup/nmcs-provider-ec2.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NMCS_PROVIDER_EC2_H__ #define __NMCS_PROVIDER_EC2_H__ @@ -10,14 +10,17 @@ 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); +#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); /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index ba4016dd..b4398fb8 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -9,7 +9,7 @@ /*****************************************************************************/ #define HTTP_TIMEOUT_MS 3000 -#define HTTP_REQ_MAX_DATA 512*1024 +#define HTTP_REQ_MAX_DATA 512 * 1024 #define HTTP_POLL_TIMEOUT_MS 10000 #define HTTP_RATE_LIMIT_MS 1000 @@ -19,502 +19,436 @@ #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 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__) +#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; + NMCSProvider parent; }; struct _NMCSProviderGCPClass { - NMCSProviderClass parent; + NMCSProviderClass parent; }; -G_DEFINE_TYPE (NMCSProviderGCP, nmcs_provider_gcp, NMCS_TYPE_PROVIDER); +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) +_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 GCP 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 GCP metadata"); - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - - g_task_return_boolean (task, TRUE); + 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) +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); + 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 *config_data; - guint n_ifaces_pending; - GError *error; - bool success:1; + NMCSProviderGetConfigTaskData *config_data; + guint n_ifaces_pending; + GError * error; } GCPData; typedef struct { - NMCSProviderGetConfigIfaceData *iface_get_config; - GCPData *gcp_data; - gssize iface_idx; - guint n_fips_pending; + NMCSProviderGetConfigIfaceData *iface_get_config; + GCPData * gcp_data; + gssize iface_idx; + guint n_fips_pending; } GCPIfaceData; static void -_get_config_maybe_task_return (GCPData *gcp_data, - GError *error_take) +_get_config_maybe_task_return(GCPData *gcp_data, GError *error_take) { - NMCSProviderGetConfigTaskData *config_data = gcp_data->config_data; - gs_free_error GError *gcp_error = NULL; - - if (error_take) { - nm_clear_error (&gcp_data->error); - gcp_data->error = error_take; - } - - if (gcp_data->n_ifaces_pending) - return; - - gcp_error = gcp_data->error; - - if (!gcp_data->success) { - nm_assert (gcp_error); - - if (nm_utils_error_is_cancelled (gcp_error)) - _LOGD ("get-config: cancelled"); - else - _LOGD ("get-config: failed: %s", gcp_error->message); - g_task_return_error (config_data->task, g_steal_pointer (&gcp_error)); - } else { - _LOGD ("get-config: success"); - g_task_return_pointer (config_data->task, - g_hash_table_ref (config_data->result_dict), - (GDestroyNotify) g_hash_table_unref); - } - - nm_g_slice_free (gcp_data); - g_object_unref (config_data->task); + NMCSProviderGetConfigTaskData *config_data = gcp_data->config_data; + + if (error_take) { + if (!gcp_data->error) + gcp_data->error = error_take; + else if (!nm_utils_error_is_cancelled(gcp_data->error) + && nm_utils_error_is_cancelled(error_take)) { + nm_clear_error(&gcp_data->error); + gcp_data->error = error_take; + } else + g_error_free(error_take); + } + + if (gcp_data->n_ifaces_pending > 0) + return; + + if (gcp_data->error) { + if (nm_utils_error_is_cancelled(gcp_data->error)) + _LOGD("get-config: cancelled"); + else + _LOGD("get-config: failed: %s", gcp_data->error->message); + g_task_return_error(config_data->task, g_steal_pointer(&gcp_data->error)); + } else { + _LOGD("get-config: success"); + g_task_return_pointer(config_data->task, + g_hash_table_ref(config_data->result_dict), + (GDestroyNotify) g_hash_table_unref); + } + + nm_g_slice_free(gcp_data); + g_object_unref(config_data->task); } static void -_get_config_fip_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - NMCSProviderGetConfigIfaceData *iface_get_config; - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData *iface_data = user_data; - gs_free_error GError *error = NULL; - const char *fip_str = NULL; - NMIPRoute **routes_arr; - NMIPRoute *route_new; - GCPData *gcp_data; - - gcp_data = iface_data->gcp_data; - - nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - &response, - &error); - - if (error) - goto iface_done; - - fip_str = g_bytes_get_data (response, NULL); - if (!nm_utils_ipaddr_valid (AF_INET, fip_str)) { - error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "forwarded-ip is not a valid ip address"); - goto iface_done; - } - - _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: adding forwarded-ip %s", - iface_data->iface_idx, - fip_str); - - iface_get_config = iface_data->iface_get_config; - iface_get_config->iface_idx = iface_data->iface_idx; - routes_arr = iface_get_config->iproutes_arr; - - route_new = nm_ip_route_new (AF_INET, - fip_str, - 32, - NULL, - 100, - &error); - if (error) - goto iface_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; - gcp_data->success = TRUE; + NMCSProviderGetConfigIfaceData *iface_get_config; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData * iface_data = user_data; + gs_free_error GError *error = NULL; + const char * fip_str = NULL; + NMIPRoute ** routes_arr; + NMIPRoute * route_new; + GCPData * gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (error) + goto iface_done; + + fip_str = g_bytes_get_data(response, NULL); + if (!nm_utils_ipaddr_valid(AF_INET, fip_str)) { + error = + nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "forwarded-ip is not a valid ip address"); + goto iface_done; + } + + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: adding forwarded-ip %s", + iface_data->iface_idx, + fip_str); + + iface_get_config = iface_data->iface_get_config; + iface_get_config->iface_idx = iface_data->iface_idx; + routes_arr = iface_get_config->iproutes_arr; + + route_new = nm_ip_route_new(AF_INET, fip_str, 32, NULL, 100, &error); + if (error) + goto iface_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; iface_done: - --iface_data->n_fips_pending; - if (iface_data->n_fips_pending == 0) { - nm_g_slice_free (iface_data); - --gcp_data->n_ifaces_pending; - _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); - } + --iface_data->n_fips_pending; + if (iface_data->n_fips_pending == 0) { + nm_g_slice_free(iface_data); + --gcp_data->n_ifaces_pending; + } + + _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); } static void -_get_config_ips_list_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_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; - GCPData *gcp_data; - const char *line; - gsize line_len; - guint i; - - gcp_data = iface_data->gcp_data; - - nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - &response, - &error); - - if (error) - goto fips_error; - - - uri_arr = g_ptr_array_new_with_free_func (g_free); - response_str = g_bytes_get_data (response, &response_len); - - while (nm_utils_parse_next_line (&response_str, - &response_len, - &line, - &line_len)) { - nm_auto_free_gstring GString *gstr = NULL; - gint64 fip_index; - - gstr = g_string_new_len (line, line_len); - fip_index = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXINT64, -1); - - if (fip_index < 0) { - continue; - } - - g_string_printf (gstr, - "%"G_GSSIZE_FORMAT"/forwarded-ips/%"G_GINT64_FORMAT, - iface_data->iface_idx, - fip_index); - g_ptr_array_add (uri_arr, g_string_free (g_steal_pointer (&gstr), FALSE)); - } - - iface_data->n_fips_pending = uri_arr->len; - - _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found %u forwarded ips", - iface_data->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 fips_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), - g_task_get_cancellable (gcp_data->config_data->task), - NULL, - NULL, - _get_config_fip_cb, - iface_data); - } - return; + 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; + GCPData * gcp_data; + const char * line; + gsize line_len; + guint i; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (error) + goto fips_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_data 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->iface_idx, + fip_index)); + } + + iface_data->n_fips_pending = uri_arr->len; + + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found %u forwarded ips", + iface_data->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 fips_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), + g_task_get_cancellable(gcp_data->config_data->task), + NULL, + NULL, + _get_config_fip_cb, + iface_data); + } + return; fips_error: - nm_g_slice_free (iface_data); - --gcp_data->n_ifaces_pending; - _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + nm_g_slice_free(iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); } static void -_get_config_iface_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_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 const char *hwaddr = NULL; - gs_free const char *uri = NULL; - gs_free char *str = NULL; - GCPData *gcp_data; - - gcp_data = iface_data->gcp_data; - - nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - &response, - &error); - - if (error) - goto iface_error; - - hwaddr = nmcs_utils_hwaddr_normalize (g_bytes_get_data (response, NULL), -1); - iface_data->iface_get_config = g_hash_table_lookup (gcp_data->config_data->result_dict, - hwaddr); - if (!iface_data->iface_get_config) { - _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: did not find a matching device", - iface_data->iface_idx); - error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "no matching hwaddr found for GCP interface"); - goto iface_error; - } - - _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found a matching device with hwaddr %s", - iface_data->iface_idx, - hwaddr); - - str = g_strdup_printf ("%"G_GSSIZE_FORMAT"/forwarded-ips/", - iface_data->iface_idx); - - 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), - g_task_get_cancellable (gcp_data->config_data->task), - NULL, - NULL, - _get_config_ips_list_cb, - iface_data); - return; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData * iface_data = user_data; + gs_free_error GError *error = NULL; + gs_free const char * hwaddr = NULL; + gs_free const char * uri = NULL; + char sbuf[100]; + GCPData * gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (error) + goto iface_error; + + hwaddr = nmcs_utils_hwaddr_normalize(g_bytes_get_data(response, NULL), -1); + iface_data->iface_get_config = g_hash_table_lookup(gcp_data->config_data->result_dict, hwaddr); + if (!iface_data->iface_get_config) { + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: did not find a matching device", + iface_data->iface_idx); + error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, + "no matching hwaddr found for GCP interface"); + goto iface_error; + } + + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s", + iface_data->iface_idx, + hwaddr); + + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->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), + g_task_get_cancellable(gcp_data->config_data->task), + NULL, + NULL, + _get_config_ips_list_cb, + iface_data); + return; iface_error: - nm_g_slice_free (iface_data); - --gcp_data->n_ifaces_pending; - _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + nm_g_slice_free(iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); } static void -_get_net_ifaces_list_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +_get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; - nm_auto_free_gstring GString *gstr = NULL; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError *error = NULL; - GCPData *gcp_data = user_data; - const char *response_str; - const char *token_start; - const char *token_end; - 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 (error) { - _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); - return; - } - - response_str = g_bytes_get_data (response, &response_len); - ifaces_arr = g_ptr_array_new (); - gstr = g_string_new (NULL); - - while (nm_utils_parse_next_line (&response_str, - &response_len, - &line, - &line_len)) { - GCPIfaceData *iface_data; - gssize iface_idx; - - token_start = line; - token_end = memchr (token_start, '/', line_len); - - if (!token_end) - continue; - - g_string_truncate (gstr, 0); - g_string_append_len (gstr, token_start, token_end - token_start); - iface_idx = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXSSIZE, -1); - - if (iface_idx < 0) - continue; - - iface_data = g_slice_new (GCPIfaceData); - *iface_data = (GCPIfaceData) { - .iface_get_config = NULL, - .gcp_data = gcp_data, - .iface_idx = iface_idx, - .n_fips_pending = 0, - }; - g_ptr_array_add (ifaces_arr, iface_data); - } - - gcp_data->n_ifaces_pending = ifaces_arr->len; - _LOGI ("found GCP interfaces: %u", ifaces_arr->len); - - for (i = 0; i < ifaces_arr->len; ++i) { - GCPIfaceData *data = ifaces_arr->pdata[i]; - gs_free const char *uri = NULL; - - _LOGD ("GCP interface[%"G_GSSIZE_FORMAT"]: retrieving configuration", - data->iface_idx); - - g_string_printf (gstr, "%"G_GSSIZE_FORMAT"/mac", data->iface_idx); - - nm_http_client_poll_get (NM_HTTP_CLIENT (source), - (uri = _gcp_uri_interfaces (gstr->str)), - HTTP_TIMEOUT_MS, - HTTP_REQ_MAX_DATA, - HTTP_POLL_TIMEOUT_MS, - HTTP_RATE_LIMIT_MS, - NM_MAKE_STRV (NM_GCP_METADATA_HEADER), - g_task_get_cancellable (gcp_data->config_data->task), - NULL, - NULL, - _get_config_iface_cb, - data); - - } - - if (ifaces_arr->len == 0) { - error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "no GCP interfaces found"); - _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); - } + gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; + gs_unref_bytes GBytes *response = NULL; + gs_free_error GError *error = NULL; + GCPData * gcp_data = user_data; + const char * response_str; + 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 (error) { + _get_config_maybe_task_return(gcp_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(); + + while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { + GCPIfaceData *iface_data; + gssize iface_idx; + + if (line_len == 0) + continue; + + /* Truncate the string. It's safe to do, because we own @response_data 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'; + + iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); + if (iface_idx < 0) + continue; + + iface_data = g_slice_new(GCPIfaceData); + *iface_data = (GCPIfaceData){ + .iface_get_config = NULL, + .gcp_data = gcp_data, + .iface_idx = iface_idx, + .n_fips_pending = 0, + }; + g_ptr_array_add(ifaces_arr, iface_data); + } + + gcp_data->n_ifaces_pending = ifaces_arr->len; + _LOGI("found GCP interfaces: %u", ifaces_arr->len); + + 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->iface_idx); + + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->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), + g_task_get_cancellable(gcp_data->config_data->task), + NULL, + NULL, + _get_config_iface_cb, + data); + } + + if (ifaces_arr->len == 0) { + error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no GCP interfaces found"); + _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); + } } - static void -get_config (NMCSProvider *provider, - NMCSProviderGetConfigTaskData *get_config_data) +get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { - gs_free const char *uri = NULL; - GCPData *gcp_data; - - gcp_data = g_slice_new (GCPData); - *gcp_data = (GCPData) { - .config_data = get_config_data, - .n_ifaces_pending = 0, - .error = NULL, - .success = FALSE, - - }; - - 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), - g_task_get_cancellable (gcp_data->config_data->task), - NULL, - NULL, - _get_net_ifaces_list_cb, - gcp_data); + gs_free const char *uri = NULL; + GCPData * gcp_data; + + gcp_data = g_slice_new(GCPData); + *gcp_data = (GCPData){ + .config_data = get_config_data, + .n_ifaces_pending = 0, + .error = 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), + g_task_get_cancellable(gcp_data->config_data->task), + NULL, + NULL, + _get_net_ifaces_list_cb, + gcp_data); } /*****************************************************************************/ static void -nmcs_provider_gcp_init (NMCSProviderGCP *self) -{ -} +nmcs_provider_gcp_init(NMCSProviderGCP *self) +{} static void -nmcs_provider_gcp_class_init (NMCSProviderGCPClass *klass) +nmcs_provider_gcp_class_init(NMCSProviderGCPClass *klass) { - NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS (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; + 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 index b0d3ec7d..4ead2191 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.h +++ b/clients/cloud-setup/nmcs-provider-gcp.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NMCS_PROVIDER_GCP_H__ #define __NMCS_PROVIDER_GCP_H__ @@ -10,14 +10,17 @@ 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); +#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); /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider.c b/clients/cloud-setup/nmcs-provider.c index bc21d876..e9e79a35 100644 --- a/clients/cloud-setup/nmcs-provider.c +++ b/clients/cloud-setup/nmcs-provider.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -8,239 +8,225 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( - PROP_HTTP_CLIENT, -); +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_HTTP_CLIENT, ); typedef struct _NMCSProviderPrivate { - NMHttpClient *http_client; + NMHttpClient *http_client; } NMCSProviderPrivate; -G_DEFINE_TYPE (NMCSProvider, nmcs_provider, G_TYPE_OBJECT); +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) +nmcs_provider_get_name(NMCSProvider *self) { - NMCSProviderClass *klass; + NMCSProviderClass *klass; - g_return_val_if_fail (NMCS_IS_PROVIDER (self), NULL); + g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - klass = NMCS_PROVIDER_GET_CLASS (self); - nm_assert (klass->_name); - return klass->_name; + klass = NMCS_PROVIDER_GET_CLASS(self); + nm_assert(klass->_name); + return klass->_name; } /*****************************************************************************/ NMHttpClient * -nmcs_provider_get_http_client (NMCSProvider *self) +nmcs_provider_get_http_client(NMCSProvider *self) { - g_return_val_if_fail (NMCS_IS_PROVIDER (self), NULL); + g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - return NMCS_PROVIDER_GET_PRIVATE (self)->http_client; + return NMCS_PROVIDER_GET_PRIVATE(self)->http_client; } GMainContext * -nmcs_provider_get_main_context (NMCSProvider *self) +nmcs_provider_get_main_context(NMCSProvider *self) { - g_return_val_if_fail (NMCS_IS_PROVIDER (self), NULL); + g_return_val_if_fail(NMCS_IS_PROVIDER(self), NULL); - return nm_http_client_get_main_context (NMCS_PROVIDER_GET_PRIVATE (self)->http_client); + 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) +nmcs_provider_detect(NMCSProvider * self, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - gs_unref_object GTask *task = NULL; - const char *env; + 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)); + 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); + task = nm_g_task_new(self, cancellable, nmcs_provider_detect, callback, user_data); - nmcs_wait_for_objects_register (task); + 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; - } + 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)); + NMCS_PROVIDER_GET_CLASS(self)->detect(self, g_steal_pointer(&task)); } gboolean -nmcs_provider_detect_finish (NMCSProvider *self, - GAsyncResult *result, - GError **error) +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); + 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); + return g_task_propagate_boolean(G_TASK(result), error); } /*****************************************************************************/ NMCSProviderGetConfigIfaceData * -nmcs_provider_get_config_iface_data_new (gboolean was_requested) +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; + 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) +_iface_data_free(gpointer data) { - NMCSProviderGetConfigIfaceData *iface_data = data; + NMCSProviderGetConfigIfaceData *iface_data = data; - g_free (iface_data->ipv4s_arr); - g_free (iface_data->iproutes_arr); + g_free(iface_data->ipv4s_arr); + g_free(iface_data->iproutes_arr); - nm_g_slice_free (iface_data); + nm_g_slice_free(iface_data); } static void -_get_config_data_free (gpointer data) +_get_config_data_free(gpointer data) { - NMCSProviderGetConfigTaskData *get_config_data = data; + NMCSProviderGetConfigTaskData *get_config_data = data; - if (get_config_data->extra_destroy) - get_config_data->extra_destroy (get_config_data->extra_data); + if (get_config_data->extra_destroy) + get_config_data->extra_destroy(get_config_data->extra_data); - nm_clear_pointer (&get_config_data->result_dict, g_hash_table_unref); + nm_clear_pointer(&get_config_data->result_dict, g_hash_table_unref); - nm_g_slice_free (get_config_data); + nm_g_slice_free(get_config_data); } void -nmcs_provider_get_config (NMCSProvider *self, - gboolean any, - const char *const*hwaddrs, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +nmcs_provider_get_config(NMCSProvider * self, + gboolean any, + const char *const * hwaddrs, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - NMCSProviderGetConfigTaskData *get_config_data; + NMCSProviderGetConfigTaskData *get_config_data; - g_return_if_fail (NMCS_IS_PROVIDER (self)); - g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail(NMCS_IS_PROVIDER(self)); + g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - 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), - }; + 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), + }; - g_task_set_task_data (get_config_data->task, get_config_data, _get_config_data_free); + g_task_set_task_data(get_config_data->task, get_config_data, _get_config_data_free); - nmcs_wait_for_objects_register (get_config_data->task); + 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)); - } + 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)); + } - _LOGD ("get-config: starting"); + _LOGD("get-config: starting"); - NMCS_PROVIDER_GET_CLASS (self)->get_config (self, get_config_data); + NMCS_PROVIDER_GET_CLASS(self)->get_config(self, get_config_data); } GHashTable * -nmcs_provider_get_config_finish (NMCSProvider *self, - GAsyncResult *result, - GError **error) +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); + 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); + return g_task_propagate_pointer(G_TASK(result), error); } /*****************************************************************************/ static void -set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +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; - } + 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) +nmcs_provider_init(NMCSProvider *self) { - NMCSProviderPrivate *priv; + NMCSProviderPrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NMCS_TYPE_PROVIDER, NMCSProviderPrivate); + priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NMCS_TYPE_PROVIDER, NMCSProviderPrivate); - self->_priv = priv; + self->_priv = priv; } static void -dispose (GObject *object) +dispose(GObject *object) { - NMCSProvider *self = NMCS_PROVIDER (object); - NMCSProviderPrivate *priv = NMCS_PROVIDER_GET_PRIVATE (self); + NMCSProvider * self = NMCS_PROVIDER(object); + NMCSProviderPrivate *priv = NMCS_PROVIDER_GET_PRIVATE(self); - g_clear_object (&priv->http_client); + g_clear_object(&priv->http_client); - G_OBJECT_CLASS (nmcs_provider_parent_class)->dispose (object); + G_OBJECT_CLASS(nmcs_provider_parent_class)->dispose(object); } static void -nmcs_provider_class_init (NMCSProviderClass *klass) +nmcs_provider_class_init(NMCSProviderClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); - g_type_class_add_private (object_class, sizeof (NMCSProviderPrivate)); + g_type_class_add_private(object_class, sizeof(NMCSProviderPrivate)); - object_class->set_property = set_property; - object_class->dispose = dispose; + 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); + 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); + 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 index e5950f93..876b0a37 100644 --- a/clients/cloud-setup/nmcs-provider.h +++ b/clients/cloud-setup/nmcs-provider.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NMCS_PROVIDER_H__ #define __NMCS_PROVIDER_H__ @@ -10,103 +10,97 @@ /*****************************************************************************/ typedef struct { - in_addr_t *ipv4s_arr; - gsize ipv4s_len; - gssize iface_idx; - in_addr_t cidr_addr; - guint8 cidr_prefix; - bool has_ipv4s:1; - bool has_cidr:1; + in_addr_t *ipv4s_arr; + gsize ipv4s_len; + 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; + NMIPRoute **iproutes_arr; + gsize iproutes_len; - /* TRUE, if the configuration was requested via hwaddrs argument to - * nmcs_provider_get_config(). */ - bool was_requested:1; + /* 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) +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); + 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); +NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new(gboolean was_requested); typedef struct { - GTask *task; - GHashTable *result_dict; - gpointer extra_data; - GDestroyNotify extra_destroy; - bool any:1; + GTask * task; + GHashTable * result_dict; + gpointer extra_data; + GDestroyNotify extra_destroy; + 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_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; + GObject parent; + struct _NMCSProviderPrivate *_priv; } NMCSProvider; typedef struct { - GObjectClass parent; - const char *_name; - const char *_env_provider_enabled; + GObjectClass parent; + const char * _name; + const char * _env_provider_enabled; - void (*detect) (NMCSProvider *self, - GTask *task); + void (*detect)(NMCSProvider *self, GTask *task); - void (*get_config) (NMCSProvider *self, - NMCSProviderGetConfigTaskData *get_config_data); + void (*get_config)(NMCSProvider *self, NMCSProviderGetConfigTaskData *get_config_data); } NMCSProviderClass; -GType nmcs_provider_get_type (void); +GType nmcs_provider_get_type(void); /*****************************************************************************/ -const char *nmcs_provider_get_name (NMCSProvider *provider); +const char *nmcs_provider_get_name(NMCSProvider *provider); -NMHttpClient *nmcs_provider_get_http_client (NMCSProvider *provider); -GMainContext *nmcs_provider_get_main_context (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); +void nmcs_provider_detect(NMCSProvider * provider, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer user_data); -gboolean nmcs_provider_detect_finish (NMCSProvider *provider, - GAsyncResult *result, - GError **error); +gboolean nmcs_provider_detect_finish(NMCSProvider *provider, GAsyncResult *result, GError **error); /*****************************************************************************/ -void nmcs_provider_get_config (NMCSProvider *provider, - gboolean any, - const char *const*hwaddrs, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +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); +GHashTable * +nmcs_provider_get_config_finish(NMCSProvider *provider, GAsyncResult *result, GError **error); #endif /* __NMCS_PROVIDER_H__ */ -- cgit 1.3.0-6-gf8a5