diff --git a/clients/cloud-setup/nmcs-provider-azure.c b/clients/cloud-setup/nmcs-provider-azure.c index 561eb8175..a18a0d64b 100644 --- a/clients/cloud-setup/nmcs-provider-azure.c +++ b/clients/cloud-setup/nmcs-provider-azure.c @@ -94,128 +94,87 @@ detect(NMCSProvider *provider, GTask *task) /*****************************************************************************/ typedef struct { - NMCSProviderGetConfigTaskData *get_config_data; - guint n_ifaces_pending; - GError * error; -} AzureData; - -typedef struct { + NMCSProviderGetConfigTaskData * get_config_data; 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) +_azure_iface_data_destroy(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 *get_config_data = azure_data->get_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(get_config_data->task, g_steal_pointer(&azure_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(azure_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_ipv4) +_get_config_fetch_done_cb(NMHttpClient * http_client, + GAsyncResult * result, + AzureIfaceData *iface_data, + gboolean is_ipv4) { + NMCSProviderGetConfigTaskData * get_config_data; NMCSProviderGetConfigIfaceData *iface_get_config; - gs_unref_bytes GBytes *response = NULL; - 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; + gs_unref_bytes GBytes *response = NULL; + gs_free_error GError *error = NULL; + const char * fip_str = NULL; + in_addr_t tmp_addr; + int tmp_prefix; nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto done; + goto out_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(get_config_data->result_dict, iface_data->hwaddr); + iface_get_config = iface_data->iface_get_config; + iface_get_config->iface_idx = iface_data->iface_idx; - fip_str = g_bytes_get_data(response, NULL); - iface_data->iface_get_config = - g_hash_table_lookup(azure_data->get_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 out_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 (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", + if (tmp_prefix == -1) { + _LOGD("interface[%" G_GSSIZE_FORMAT "]: invalid prefix %d", iface_data->iface_idx, tmp_prefix); - iface_get_config->cidr_prefix = tmp_prefix; - iface_get_config->has_cidr = TRUE; + goto out_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)); +out_done: + if (!error) { + --iface_data->n_ips_prefix_pending; + if (iface_data->n_ips_prefix_pending > 0) + return; } + + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void @@ -235,20 +194,24 @@ _get_config_fetch_done_cb_subnet_cidr_prefix(GObject * source, 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; + gs_unref_bytes GBytes *response = NULL; + AzureIfaceData * iface_data = user_data; + gs_free_error GError * error = NULL; + const char * response_str = NULL; + gsize response_len; + NMCSProviderGetConfigTaskData *get_config_data; + const char * line; + gsize line_len; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto done; + goto out_error; response_str = g_bytes_get_data(response, &response_len); /* NMHttpClient guarantees that there is a trailing NUL after the data. */ @@ -293,7 +256,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u 10000, 1000, NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(azure_data->get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_fetch_done_cb_private_ipv4s, @@ -319,7 +282,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u 10000, 1000, NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(azure_data->get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_fetch_done_cb_subnet_cidr_prefix, @@ -327,47 +290,48 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u } return; -done: - _azure_iface_data_free(iface_data); - --azure_data->n_ifaces_pending; - _get_config_maybe_task_return(azure_data, g_steal_pointer(&error)); +out_error: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData *get_config_data; gs_unref_bytes GBytes *response = NULL; AzureIfaceData * iface_data = user_data; gs_free_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 (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto done; + goto out_done; iface_data->hwaddr = nmcs_utils_hwaddr_normalize(g_bytes_get_data(response, NULL), -1); - if (!iface_data->hwaddr) { - goto done; - } + if (!iface_data->hwaddr) + goto out_done; iface_data->iface_get_config = - g_hash_table_lookup(azure_data->get_config_data->result_dict, iface_data->hwaddr); + g_hash_table_lookup(get_config_data->result_dict, iface_data->hwaddr); if (!iface_data->iface_get_config) { - if (!iface_data->azure_data->get_config_data->any) { + if (!get_config_data->any) { _LOGD("interface[%" G_GSSIZE_FORMAT "]: ignore hwaddr %s", iface_data->iface_idx, iface_data->hwaddr); - goto done; + goto out_done; } iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE); - g_hash_table_insert(azure_data->get_config_data->result_dict, + g_hash_table_insert(get_config_data->result_dict, g_strdup(iface_data->hwaddr), iface_data->iface_get_config); } @@ -385,26 +349,25 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) 10000, 1000, NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(azure_data->get_config_data->task), + get_config_data->intern_cancellable, 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)); +out_done: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData *get_config_data; gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; gs_unref_bytes GBytes *response = NULL; gs_free_error GError *error = NULL; - AzureData * azure_data = user_data; const char * response_str; gsize response_len; const char * line; @@ -413,8 +376,13 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = user_data; + if (error) { - _get_config_maybe_task_return(azure_data, g_steal_pointer(&error)); + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); return; } @@ -422,7 +390,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat /* NMHttpClient guarantees that there is a trailing NUL after the data. */ nm_assert(response_str[response_len] == 0); - ifaces_arr = g_ptr_array_new(); + ifaces_arr = g_ptr_array_new_with_free_func((GDestroyNotify) _azure_iface_data_destroy); while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { AzureIfaceData *iface_data; @@ -444,8 +412,8 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat iface_data = g_slice_new(AzureIfaceData); *iface_data = (AzureIfaceData){ + .get_config_data = get_config_data, .iface_get_config = NULL, - .azure_data = azure_data, .iface_idx = iface_idx, .n_ips_prefix_pending = 0, .hwaddr = NULL, @@ -456,21 +424,23 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat _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)); + _nmcs_provider_get_config_task_maybe_return( + get_config_data, + nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no Azure interfaces found")); return; } for (i = 0; i < ifaces_arr->len; ++i) { - AzureIfaceData * data = ifaces_arr->pdata[i]; - gs_free const char *uri = NULL; + AzureIfaceData * iface_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); + _LOGD("azure interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", + iface_data->iface_idx); - nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", data->iface_idx); + nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", iface_data->iface_idx); - azure_data->n_ifaces_pending++; + get_config_data->n_pending++; nm_http_client_poll_get(NM_HTTP_CLIENT(source), (uri = _azure_uri_interfaces(buf)), HTTP_TIMEOUT_MS, @@ -478,25 +448,21 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat 10000, 1000, NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(azure_data->get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_iface_cb, - data); + iface_data); } + + get_config_data->extra_data_destroy = (GDestroyNotify) g_ptr_array_unref; + get_config_data->extra_data = g_steal_pointer(&ifaces_arr); } static void get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { gs_free const char *uri = NULL; - AzureData * azure_data; - - azure_data = g_slice_new(AzureData); - *azure_data = (AzureData){ - .get_config_data = get_config_data, - .n_ifaces_pending = 0, - }; nm_http_client_poll_get(nmcs_provider_get_http_client(provider), (uri = _azure_uri_interfaces()), @@ -505,11 +471,11 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat 15000, 1000, NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), - g_task_get_cancellable(get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_net_ifaces_list_cb, - azure_data); + get_config_data); } /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index 40bed1575..276479f25 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -129,124 +129,69 @@ detect(NMCSProvider *provider, GTask *task) /*****************************************************************************/ -typedef struct { - NMCSProviderGetConfigTaskData *get_config_data; - GError * error; - GCancellable * cancellable; - gulong cancelled_id; - guint n_pending; -} GetConfigIfaceData; - -static void -_get_config_task_maybe_return(GetConfigIfaceData *iface_data, GError *error_take) -{ - 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); - - nm_clear_g_cancellable(&iface_data->cancellable); - } - - 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) { - GetConfigIfaceData *iface_data; - const char * hwaddr = NULL; - gs_unref_bytes GBytes *response = NULL; - gs_free_error GError *error = NULL; + NMCSProviderGetConfigTaskData *get_config_data; + const char * hwaddr = NULL; + gs_unref_bytes GBytes *response = NULL; + gs_free_error GError * error = NULL; + NMCSProviderGetConfigIfaceData *config_iface_data; + in_addr_t tmp_addr; + int tmp_prefix; - nm_utils_user_data_unpack(user_data, &iface_data, &hwaddr); + nm_utils_user_data_unpack(user_data, &get_config_data, &hwaddr); nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); - if (!error) { - NMCSProviderGetConfigIfaceData *config_iface_data; - in_addr_t tmp_addr; - int tmp_prefix; + if (nm_utils_error_is_cancelled(error)) + return; - config_iface_data = g_hash_table_lookup(iface_data->get_config_data->result_dict, hwaddr); + if (error) + goto out; - if (is_local_ipv4) { - gs_free const char **s_addrs = NULL; - gsize i, len; + config_iface_data = g_hash_table_lookup(get_config_data->result_dict, hwaddr); - s_addrs = nm_utils_strsplit_set_full(g_bytes_get_data(response, NULL), - "\n", - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); - len = NM_PTRARRAY_LEN(s_addrs); + if (is_local_ipv4) { + gs_free const char **s_addrs = NULL; + gsize i, len; - 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); + s_addrs = nm_utils_strsplit_set_full(g_bytes_get_data(response, NULL), + "\n", + NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); + len = NM_PTRARRAY_LEN(s_addrs); - for (i = 0; i < len; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, s_addrs[i], NULL, &tmp_addr)) - config_iface_data->ipv4s_arr[config_iface_data->ipv4s_len++] = tmp_addr; - } - } - } else { - if (nm_utils_parse_inaddr_prefix_bin(AF_INET, - g_bytes_get_data(response, NULL), - NULL, - &tmp_addr, - &tmp_prefix)) { - nm_assert(!config_iface_data->has_cidr); - config_iface_data->has_cidr = TRUE; - config_iface_data->cidr_prefix = tmp_prefix; - config_iface_data->cidr_addr = tmp_addr; + nm_assert(!config_iface_data->has_ipv4s); + nm_assert(!config_iface_data->ipv4s_arr); + config_iface_data->has_ipv4s = TRUE; + config_iface_data->ipv4s_len = 0; + if (len > 0) { + config_iface_data->ipv4s_arr = g_new(in_addr_t, len); + + for (i = 0; i < len; i++) { + if (nm_utils_parse_inaddr_bin(AF_INET, s_addrs[i], NULL, &tmp_addr)) + config_iface_data->ipv4s_arr[config_iface_data->ipv4s_len++] = tmp_addr; } } + } else { + if (nm_utils_parse_inaddr_prefix_bin(AF_INET, + g_bytes_get_data(response, NULL), + NULL, + &tmp_addr, + &tmp_prefix)) { + nm_assert(!config_iface_data->has_cidr); + config_iface_data->has_cidr = TRUE; + config_iface_data->cidr_prefix = tmp_prefix; + config_iface_data->cidr_addr = tmp_addr; + } } - /* If nm_utils_error_is_cancelled(error), then our internal iface_data->cancellable - * was cancelled, because the overall request failed. From point of view of the - * caller, this does not mean that a cancellation happened. It also means, our - * request overall is already about to fail. */ - nm_assert(!nm_utils_error_is_cancelled(error) || iface_data->error); - - iface_data->n_pending--; - _get_config_task_maybe_return(iface_data, - nm_utils_error_is_cancelled(error) ? NULL - : g_steal_pointer(&error)); +out: + get_config_data->n_pending--; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void @@ -263,21 +208,6 @@ _get_config_fetch_done_cb_local_ipv4s(GObject *source, GAsyncResult *result, gpo _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) -{ - GetConfigIfaceData *iface_data = user_data; - - 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; -} GetConfigMetadataData; - typedef struct { gssize iface_idx; char path[0]; @@ -286,60 +216,33 @@ typedef struct { static void _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; + NMCSProviderGetConfigTaskData *get_config_data; + gs_unref_hashtable GHashTable *response_parsed = NULL; + gs_free_error GError *error = NULL; GetConfigMetadataMac *v_mac_data; const char * v_hwaddr; GHashTableIter h_iter; NMHttpClient * http_client; - nm_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)); + if (nm_utils_error_is_cancelled(error)) return; - } + + get_config_data = user_data; + + response_parsed = g_steal_pointer(&get_config_data->extra_data); + get_config_data->extra_data_destroy = NULL; /* We ignore errors. Only if we got no response at all, it's a problem. * Otherwise, we proceed with whatever we could fetch. */ if (!response_parsed) { - _get_config_task_maybe_return( - iface_data, + _nmcs_provider_get_config_task_maybe_return( + get_config_data, nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "meta data for interfaces not found")); return; } - 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) { - /* the callback was already invoked synchronously and the task already returned. */ - 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); @@ -373,7 +276,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us hwaddr, v_mac_data->path); - iface_data->n_pending++; + get_config_data->n_pending++; nm_http_client_poll_get( http_client, (uri1 = _ec2_uri_interfaces(v_mac_data->path, @@ -384,13 +287,13 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us 10000, 1000, NULL, - iface_data->cancellable, + get_config_data->intern_cancellable, NULL, NULL, _get_config_fetch_done_cb_subnet_ipv4_cidr_block, - nm_utils_user_data_pack(iface_data, hwaddr)); + nm_utils_user_data_pack(get_config_data, hwaddr)); - iface_data->n_pending++; + get_config_data->n_pending++; nm_http_client_poll_get( http_client, (uri2 = _ec2_uri_interfaces(v_mac_data->path, @@ -401,14 +304,14 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us 10000, 1000, NULL, - iface_data->cancellable, + get_config_data->intern_cancellable, NULL, NULL, _get_config_fetch_done_cb_local_ipv4s, - nm_utils_user_data_pack(iface_data, hwaddr)); + nm_utils_user_data_pack(get_config_data, hwaddr)); } - _get_config_task_maybe_return(iface_data, NULL); + _nmcs_provider_get_config_task_maybe_return(get_config_data, NULL); } static gboolean @@ -417,7 +320,7 @@ _get_config_metadata_ready_check(long response_code, gpointer check_user_data, GError **error) { - GetConfigMetadataData *metadata_data = check_user_data; + NMCSProviderGetConfigTaskData *get_config_data = check_user_data; gs_unref_hashtable GHashTable *response_parsed = NULL; const guint8 * r_data; const char * cur_line; @@ -465,7 +368,7 @@ _get_config_metadata_ready_check(long response_code, } has_all = TRUE; - g_hash_table_iter_init(&h_iter, metadata_data->get_config_data->result_dict); + g_hash_table_iter_init(&h_iter, get_config_data->result_dict); while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, NULL)) { if (!response_parsed || !g_hash_table_contains(response_parsed, c_hwaddr)) { has_all = FALSE; @@ -473,21 +376,18 @@ _get_config_metadata_ready_check(long response_code, } } - nm_clear_pointer(&metadata_data->response_parsed, g_hash_table_unref); - metadata_data->response_parsed = g_steal_pointer(&response_parsed); + nm_clear_pointer(&get_config_data->extra_data, g_hash_table_unref); + if (response_parsed) { + get_config_data->extra_data = g_steal_pointer(&response_parsed); + get_config_data->extra_data_destroy = (GDestroyNotify) g_hash_table_unref; + } return has_all; } static void get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { - gs_free char * uri = NULL; - GetConfigMetadataData *metadata_data; - - metadata_data = g_slice_new(GetConfigMetadataData); - *metadata_data = (GetConfigMetadataData){ - .get_config_data = get_config_data, - }; + gs_free char *uri = NULL; /* First we fetch the "macs/". If the caller requested some particular * MAC addresses, then we poll until we see them. They might not yet be @@ -500,11 +400,11 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat 15000, 1000, NULL, - g_task_get_cancellable(get_config_data->task), + get_config_data->intern_cancellable, _get_config_metadata_ready_check, - metadata_data, + get_config_data, _get_config_metadata_ready_cb, - metadata_data); + get_config_data); } /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index 45e1c3622..a8b50f98f 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -89,57 +89,22 @@ detect(NMCSProvider *provider, GTask *task) /*****************************************************************************/ typedef struct { - NMCSProviderGetConfigTaskData *get_config_data; - guint n_ifaces_pending; - GError * error; -} GCPData; - -typedef struct { + NMCSProviderGetConfigTaskData * get_config_data; 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) +_gcp_iface_data_destroy(GCPIfaceData *iface_data) { - NMCSProviderGetConfigTaskData *get_config_data = gcp_data->get_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(get_config_data->task, g_steal_pointer(&gcp_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(gcp_data); - g_object_unref(get_config_data->task); + nm_g_slice_free(iface_data); } static void _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData * get_config_data; NMCSProviderGetConfigIfaceData *iface_get_config; gs_unref_bytes GBytes *response = NULL; GCPIfaceData * iface_data = user_data; @@ -147,20 +112,22 @@ _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) 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 (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto iface_done; + goto out_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; + goto out_done; } _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: adding forwarded-ip %s", @@ -173,42 +140,46 @@ _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) route_new = nm_ip_route_new(AF_INET, fip_str, 32, NULL, 100, &error); if (error) - goto iface_done; + goto out_done; nm_ip_route_set_attribute(route_new, NM_IP_ROUTE_ATTRIBUTE_TYPE, g_variant_new_string("local")); routes_arr[iface_get_config->iproutes_len] = route_new; ++iface_get_config->iproutes_len; -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; +out_done: + if (!error) { + --iface_data->n_fips_pending; + if (iface_data->n_fips_pending > 0) + return; } - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData *get_config_data; gs_unref_ptrarray GPtrArray *uri_arr = NULL; gs_unref_bytes GBytes *response = NULL; GCPIfaceData * iface_data = user_data; gs_free_error GError *error = NULL; const char * response_str = NULL; gsize response_len; - 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 (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto fips_error; + goto out_error; response_str = g_bytes_get_data(response, &response_len); /* NMHttpClient guarantees that there is a trailing NUL after the data. */ @@ -240,7 +211,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat if (iface_data->n_fips_pending == 0) { error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "found no forwarded ip"); - goto fips_error; + goto out_error; } iface_data->iface_get_config->iproutes_arr = g_new(NMIPRoute *, iface_data->n_fips_pending); @@ -256,7 +227,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_fip_cb, @@ -264,39 +235,40 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat } 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)); +out_error: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData * iface_data = user_data; - gs_free_error GError *error = NULL; - gs_free const char * hwaddr = NULL; - gs_free const char * uri = NULL; - char sbuf[100]; - GCPData * gcp_data; - - gcp_data = iface_data->gcp_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; + char sbuf[100]; + NMCSProviderGetConfigTaskData *get_config_data; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto iface_error; + goto out_error; hwaddr = nmcs_utils_hwaddr_normalize(g_bytes_get_data(response, NULL), -1); - iface_data->iface_get_config = - g_hash_table_lookup(gcp_data->get_config_data->result_dict, hwaddr); + iface_data->iface_get_config = g_hash_table_lookup(get_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; + goto out_error; } _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s", @@ -312,17 +284,16 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->get_config_data->task), + get_config_data->intern_cancellable, 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)); +out_error: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void @@ -330,18 +301,23 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat { 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; + gs_free_error GError * error = NULL; + NMCSProviderGetConfigTaskData *get_config_data; + const char * response_str; + gsize response_len; + const char * line; + gsize line_len; + guint i; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = user_data; + if (error) { - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); return; } @@ -349,7 +325,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat /* NMHttpClient guarantees that there is a trailing NUL after the data. */ nm_assert(response_str[response_len] == 0); - ifaces_arr = g_ptr_array_new(); + ifaces_arr = g_ptr_array_new_with_free_func((GDestroyNotify) _gcp_iface_data_destroy); while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { GCPIfaceData *iface_data; @@ -370,17 +346,23 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat iface_data = g_slice_new(GCPIfaceData); *iface_data = (GCPIfaceData){ + .get_config_data = get_config_data, .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); + if (ifaces_arr->len == 0) { + _nmcs_provider_get_config_task_maybe_return( + get_config_data, + nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no GCP interfaces found")); + return; + } + for (i = 0; i < ifaces_arr->len; ++i) { GCPIfaceData * data = ifaces_arr->pdata[i]; gs_free const char *uri = NULL; @@ -390,6 +372,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->iface_idx); + get_config_data->n_pending++; nm_http_client_poll_get(NM_HTTP_CLIENT(source), (uri = _gcp_uri_interfaces(sbuf)), HTTP_TIMEOUT_MS, @@ -397,31 +380,21 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->get_config_data->task), + get_config_data->intern_cancellable, 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)); - } + get_config_data->extra_data = g_steal_pointer(&ifaces_arr); + get_config_data->extra_data_destroy = (GDestroyNotify) g_ptr_array_unref; } static void get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { gs_free const char *uri = NULL; - GCPData * gcp_data; - - gcp_data = g_slice_new(GCPData); - *gcp_data = (GCPData){ - .get_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()), @@ -430,11 +403,11 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->get_config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_net_ifaces_list_cb, - gcp_data); + get_config_data); } /*****************************************************************************/ diff --git a/clients/cloud-setup/nmcs-provider.c b/clients/cloud-setup/nmcs-provider.c index 9fac4b667..6512b76fa 100644 --- a/clients/cloud-setup/nmcs-provider.c +++ b/clients/cloud-setup/nmcs-provider.c @@ -114,18 +114,60 @@ _iface_data_free(gpointer data) } static void -_get_config_data_free(gpointer data) +_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, GError *error_take) { - NMCSProviderGetConfigTaskData *get_config_data = data; + gs_free_error GError *error = error_take; - if (get_config_data->extra_destroy) - get_config_data->extra_destroy(get_config_data->extra_data); + nm_assert(get_config_data); + nm_assert(G_IS_TASK(get_config_data->task)); + + if (!error) { + if (get_config_data->n_pending > 0) + return; + } + + g_cancellable_cancel(get_config_data->intern_cancellable); + + if (error) { + if (nm_utils_error_is_cancelled(error)) + _LOGD("get-config: cancelled"); + else + _LOGD("get-config: failed: %s", error->message); + g_task_return_error(get_config_data->task, g_steal_pointer(&error)); + } else { + _LOGD("get-config: success"); + g_task_return_pointer(get_config_data->task, + g_hash_table_ref(get_config_data->result_dict), + (GDestroyNotify) g_hash_table_unref); + } + + nm_clear_g_signal_handler(g_task_get_cancellable(get_config_data->task), + &get_config_data->extern_cancelled_id); + + if (get_config_data->extra_data_destroy) + get_config_data->extra_data_destroy(get_config_data->extra_data); nm_clear_pointer(&get_config_data->result_dict, g_hash_table_unref); + nm_g_object_unref(get_config_data->intern_cancellable); + g_object_unref(get_config_data->task); nm_g_slice_free(get_config_data); } +void +_nmcs_provider_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, + GError * error_take) +{ + nm_assert(!error_take || !nm_utils_error_is_cancelled(error_take)); + _get_config_task_maybe_return(get_config_data, error_take); +} + +static void +_get_config_cancelled_cb(GObject *object, gpointer user_data) +{ + _get_config_task_maybe_return(user_data, nm_utils_error_new_cancelled(FALSE, NULL)); +} + void nmcs_provider_get_config(NMCSProvider * self, gboolean any, @@ -139,6 +181,8 @@ nmcs_provider_get_config(NMCSProvider * self, g_return_if_fail(NMCS_IS_PROVIDER(self)); g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); + _LOGD("get-config: starting"); + get_config_data = g_slice_new(NMCSProviderGetConfigTaskData); *get_config_data = (NMCSProviderGetConfigTaskData){ .task = nm_g_task_new(self, cancellable, nmcs_provider_get_config, callback, user_data), @@ -146,8 +190,6 @@ nmcs_provider_get_config(NMCSProvider * self, .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); - nmcs_wait_for_objects_register(get_config_data->task); for (; hwaddrs && hwaddrs[0]; hwaddrs++) { @@ -156,7 +198,21 @@ nmcs_provider_get_config(NMCSProvider * self, nmcs_provider_get_config_iface_data_new(TRUE)); } - _LOGD("get-config: starting"); + if (cancellable) { + gulong cancelled_id; + + cancelled_id = g_cancellable_connect(cancellable, + G_CALLBACK(_get_config_cancelled_cb), + get_config_data, + NULL); + if (cancelled_id == 0) { + /* the callback was already invoked synchronously and the task already returned. */ + return; + } + + get_config_data->extern_cancelled_id = cancelled_id; + get_config_data->intern_cancellable = g_cancellable_new(); + } NMCS_PROVIDER_GET_CLASS(self)->get_config(self, get_config_data); } diff --git a/clients/cloud-setup/nmcs-provider.h b/clients/cloud-setup/nmcs-provider.h index a26c6a366..3edd87433 100644 --- a/clients/cloud-setup/nmcs-provider.h +++ b/clients/cloud-setup/nmcs-provider.h @@ -37,11 +37,25 @@ nmcs_provider_get_config_iface_data_is_valid(const NMCSProviderGetConfigIfaceDat NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new(gboolean was_requested); typedef struct { - GTask * task; - GHashTable * result_dict; + GTask *task; + + GHashTable *result_dict; + + /* this cancellable should be used for the provider implementation + * to listen for cancellation. */ + GCancellable *intern_cancellable; + + /* the provider implementation may attach extra data. */ gpointer extra_data; - GDestroyNotify extra_destroy; - bool any : 1; + GDestroyNotify extra_data_destroy; + + gulong extern_cancelled_id; + + /* the provider implementation may use this field to track the number of pending + * operations. */ + guint n_pending; + + bool any : 1; } NMCSProviderGetConfigTaskData; #define NMCS_TYPE_PROVIDER (nmcs_provider_get_type()) @@ -93,6 +107,9 @@ gboolean nmcs_provider_detect_finish(NMCSProvider *provider, GAsyncResult *resul /*****************************************************************************/ +void _nmcs_provider_get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, + GError * error_take); + void nmcs_provider_get_config(NMCSProvider * provider, gboolean any, const char *const * hwaddrs,