cloud-setup: move common code for get_config() to base class and improve cancellation
First note that all three provider implementations are very similar. That is why NMCSProvider's implementation does already some work that is common to all implementations. For example, it provides the NMCSProviderGetConfigTaskData structure to help tracking the data of the request. Also note that the GCP/Azure implementations didn't handle the cancellation correctly. They always would pass g_task_get_cancellable(get_config_data->task) to the asynchronous requests. That is the GCancellable provider by the caller. That is fine when there is only one async operation ongoing. But that is not the case, we have parallel HTTP requests. Then, when an error happened, the overall get_config() operations fails and the still pending requests should all be aborted. However, we must not cancel the GCancellable of the user (because that is not owned by us). The correct solution is to use an internal cancellable in those cases. Anyway. Since all of this is similar, we can extend the base class to handle things for us. This also gets the cancellation right by having a "get_config_data->intern_cancellable".
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user