summaryrefslogtreecommitdiff
path: root/libnm
diff options
context:
space:
mode:
Diffstat (limited to 'libnm')
-rw-r--r--libnm/libnm.ver3
-rw-r--r--libnm/nm-client.c174
-rw-r--r--libnm/nm-client.h16
-rw-r--r--libnm/nm-remote-settings.c257
-rw-r--r--libnm/nm-remote-settings.h23
5 files changed, 348 insertions, 125 deletions
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 7118bf2bc8..fb5c06b6e6 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1611,6 +1611,8 @@ global:
libnm_1_20_0 {
global:
+ nm_client_add_connection2;
+ nm_client_add_connection2_finish;
nm_client_connectivity_check_get_uri;
nm_device_modem_get_apn;
nm_device_modem_get_device_id;
@@ -1622,4 +1624,5 @@ global:
nm_setting_ovs_dpdk_get_devargs;
nm_setting_ovs_dpdk_get_type;
nm_setting_ovs_dpdk_new;
+ nm_settings_add_connection2_flags_get_type;
} libnm_1_18_0;
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index a95540ed19..c39f62675b 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -1631,23 +1631,55 @@ nm_client_get_connection_by_uuid (NMClient *client, const char *uuid)
return nm_remote_settings_get_connection_by_uuid (NM_CLIENT_GET_PRIVATE (client)->settings, uuid);
}
+typedef struct {
+ NMRemoteConnection *connection;
+ GVariant *results;
+} AddConnection2CbData;
+
static void
-add_connection_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+add_connection2_cb_data_destroy (gpointer user_data)
{
- GSimpleAsyncResult *simple = user_data;
- NMRemoteConnection *conn;
- GError *error = NULL;
+ AddConnection2CbData *data = user_data;
- conn = nm_remote_settings_add_connection_finish (NM_REMOTE_SETTINGS (object), result, &error);
- if (conn)
- g_simple_async_result_set_op_res_gpointer (simple, conn, g_object_unref);
- else
- g_simple_async_result_take_error (simple, error);
+ g_object_unref (data->connection);
+ nm_g_variant_unref (data->results);
+ nm_g_slice_free (data);
+}
+
+static void
+add_connection2_cb (NMRemoteSettings *self,
+ NMRemoteConnection *connection,
+ GVariant *results,
+ GError *error,
+ gpointer user_data)
+{
+ gs_unref_object GSimpleAsyncResult *simple = user_data;
+
+ if (error) {
+ g_simple_async_result_take_error (simple,
+ g_error_new_literal (error->domain,
+ error->code,
+ error->message));
+ } else if (g_simple_async_result_get_source_tag (simple) == nm_client_add_connection_async) {
+ g_simple_async_result_set_op_res_gpointer (simple,
+ g_object_ref (connection),
+ g_object_unref);
+ } else {
+ AddConnection2CbData *data;
+
+ nm_assert (g_simple_async_result_get_source_tag (simple) == nm_client_add_connection2);
+
+ data = g_slice_new (AddConnection2CbData);
+ *data = (AddConnection2CbData) {
+ .connection = g_object_ref (connection),
+ .results = nm_g_variant_ref (results),
+ };
+ g_simple_async_result_set_op_res_gpointer (simple,
+ data,
+ add_connection2_cb_data_destroy);
+ }
g_simple_async_result_complete (simple);
- g_object_unref (simple);
}
/**
@@ -1698,9 +1730,17 @@ nm_client_add_connection_async (NMClient *client,
nm_client_add_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
- nm_remote_settings_add_connection_async (NM_CLIENT_GET_PRIVATE (client)->settings,
- connection, save_to_disk,
- cancellable, add_connection_cb, simple);
+
+ nm_remote_settings_add_connection2 (NM_CLIENT_GET_PRIVATE (client)->settings,
+ nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
+ save_to_disk
+ ? NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK
+ : NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY,
+ NULL,
+ TRUE,
+ cancellable,
+ add_connection2_cb,
+ simple);
}
/**
@@ -1722,13 +1762,111 @@ nm_client_add_connection_finish (NMClient *client,
GSimpleAsyncResult *simple;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
- g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_add_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
- else
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/**
+ * nm_client_add_connection2:
+ * @client: the %NMClient
+ * @settings: the "a{sa{sv}}" #GVariant with the content of the setting.
+ * @flags: the %NMSettingsAddConnection2Flags argument.
+ * @args: (allow-none): the "a{sv}" #GVariant with extra argument or %NULL
+ * for no extra arguments.
+ * @ignore_out_result: this function wraps AddConnection2(), which has an
+ * additional result "a{sv}" output parameter. By setting this to %TRUE,
+ * you signal that you are not interested in that output parameter.
+ * This allows the function to fall back to AddConnection() and AddConnectionUnsaved(),
+ * which is interesting if you run against an older server version that does
+ * not yet provide AddConnection2(). By setting this to %FALSE, the function
+ * under the hood always calls AddConnection2().
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: (scope async): callback to be called when the add operation completes
+ * @user_data: (closure): caller-specific data passed to @callback
+ *
+ * Call AddConnection2() D-Bus API asynchronously.
+ *
+ * Since: 1.20
+ **/
+void
+nm_client_add_connection2 (NMClient *client,
+ GVariant *settings,
+ NMSettingsAddConnection2Flags flags,
+ GVariant *args,
+ gboolean ignore_out_result,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ g_return_if_fail (NM_IS_CLIENT (client));
+ g_return_if_fail (g_variant_is_of_type (settings, G_VARIANT_TYPE ("a{sa{sv}}")));
+ g_return_if_fail (!args || g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
+
+ if (!_nm_client_check_nm_running (client, &error)) {
+ g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
+ return;
+ }
+
+ simple = g_simple_async_result_new (G_OBJECT (client),
+ callback,
+ user_data,
+ nm_client_add_connection2);
+ if (cancellable)
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ nm_remote_settings_add_connection2 (NM_CLIENT_GET_PRIVATE (client)->settings,
+ settings,
+ flags,
+ args,
+ ignore_out_result,
+ cancellable,
+ add_connection2_cb,
+ simple);
+}
+
+/**
+ * nm_client_add_connection2_finish:
+ * @client: the #NMClient
+ * @result: the #GAsyncResult
+ * @out_result: (allow-none) (transfer full) (out): the output #GVariant
+ * from AddConnection2().
+ * If you care about the output result, then the "ignore_out_result"
+ * parameter of nm_client_add_connection2() must not be set to %TRUE.
+ * @error: (allow-none): the error argument.
+ *
+ * Returns: (transfer full): on success, a pointer to the added
+ * #NMRemoteConnection.
+ *
+ * Since: 1.20
+ */
+NMRemoteConnection *
+nm_client_add_connection2_finish (NMClient *client,
+ GAsyncResult *result,
+ GVariant **out_result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AddConnection2CbData *data;
+
+ g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_add_connection2), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error)) {
+ NM_SET_OUT (out_result, NULL);
+ return NULL;
+ }
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ NM_SET_OUT (out_result, g_variant_ref (data->results));
+ return g_object_ref (data->connection);
}
/**
diff --git a/libnm/nm-client.h b/libnm/nm-client.h
index f3835864c8..ec7022ff6b 100644
--- a/libnm/nm-client.h
+++ b/libnm/nm-client.h
@@ -389,6 +389,22 @@ NMRemoteConnection *nm_client_add_connection_finish (NMClient *client,
GAsyncResult *result,
GError **error);
+NM_AVAILABLE_IN_1_20
+void nm_client_add_connection2 (NMClient *client,
+ GVariant *settings,
+ NMSettingsAddConnection2Flags flags,
+ GVariant *args,
+ gboolean ignore_out_result,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+NM_AVAILABLE_IN_1_20
+NMRemoteConnection *nm_client_add_connection2_finish (NMClient *client,
+ GAsyncResult *result,
+ GVariant **out_result,
+ GError **error);
+
gboolean nm_client_load_connections (NMClient *client,
char **filenames,
char ***failures,
diff --git a/libnm/nm-remote-settings.c b/libnm/nm-remote-settings.c
index 6b1d4c264e..916884ea08 100644
--- a/libnm/nm-remote-settings.c
+++ b/libnm/nm-remote-settings.c
@@ -22,6 +22,7 @@
#include "nm-remote-settings.h"
+#include "c-list/src/c-list.h"
#include "nm-dbus-interface.h"
#include "nm-connection.h"
#include "nm-client.h"
@@ -43,7 +44,7 @@ typedef struct {
GPtrArray *visible_connections;
/* AddConnectionInfo objects that are waiting for the connection to become initialized */
- GSList *add_list;
+ CList add_lst_head;
char *hostname;
gboolean can_modify;
@@ -70,51 +71,78 @@ static guint signals[LAST_SIGNAL] = { 0 };
/*****************************************************************************/
typedef struct {
+ CList add_lst;
NMRemoteSettings *self;
- GSimpleAsyncResult *simple;
+ NMRemoteSettingAddConnection2Callback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
char *path;
- gboolean saved;
+ GVariant *results;
+ gulong cancellable_id;
+ NMSettingsAddConnection2Flags flags;
+ bool ignore_out_result:1;
} AddConnectionInfo;
static AddConnectionInfo *
-add_connection_info_find (NMRemoteSettings *self, const char *path)
+_add_connection_info_find (NMRemoteSettings *self, const char *path)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
- GSList *iter;
-
- for (iter = priv->add_list; iter; iter = g_slist_next (iter)) {
- AddConnectionInfo *info = iter->data;
+ AddConnectionInfo *info;
- if (!g_strcmp0 (info->path, path))
+ c_list_for_each_entry (info, &priv->add_lst_head, add_lst) {
+ if (nm_streq0 (info->path, path))
return info;
}
-
return NULL;
}
static void
-add_connection_info_complete (NMRemoteSettings *self,
- AddConnectionInfo *info,
- NMRemoteConnection *connection,
- GError *error)
+_add_connection_info_complete (AddConnectionInfo *info,
+ NMRemoteConnection *connection,
+ GError *error_take)
{
- NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ nm_assert (info);
+
+ c_list_unlink_stale (&info->add_lst);
+
+ nm_clear_g_signal_handler (info->cancellable, &info->cancellable_id);
+
+ if ( info->cancellable
+ && !nm_utils_error_is_cancelled (error_take, FALSE)) {
+ GError *error2 = NULL;
+
+ if (g_cancellable_set_error_if_cancelled (info->cancellable, &error2)) {
+ g_clear_error (&error_take);
+ error_take = error2;
+ connection = NULL;
+ }
+ }
+
+ info->callback (info->self,
+ connection,
+ connection ? info->results : NULL,
+ error_take,
+ info->user_data);
- g_return_if_fail (info != NULL);
+ g_clear_error (&error_take);
- if (connection) {
- g_simple_async_result_set_op_res_gpointer (info->simple,
- g_object_ref (connection),
- g_object_unref);
- } else
- g_simple_async_result_set_from_error (info->simple, error);
- g_simple_async_result_complete (info->simple);
+ g_object_unref (info->self);
+ nm_g_object_unref (info->cancellable);
+ nm_clear_g_free (&info->path);
+ nm_g_variant_unref (info->results);
- g_object_unref (info->simple);
- priv->add_list = g_slist_remove (priv->add_list, info);
+ nm_g_slice_free (info);
+}
- g_free (info->path);
- g_slice_free (AddConnectionInfo, info);
+static void
+_add_connection_info_cancelled (GCancellable *cancellable,
+ AddConnectionInfo *info)
+{
+ _add_connection_info_complete (info,
+ NULL,
+ g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ "Operation was cancelled"));
}
typedef const char * (*ConnectionStringGetter) (NMConnection *);
@@ -216,7 +244,7 @@ connection_added (NMRemoteSettings *self,
NMRemoteConnection *remote)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
- AddConnectionInfo *addinfo;
+ AddConnectionInfo *info;
const char *path;
if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL,
@@ -233,26 +261,27 @@ connection_added (NMRemoteSettings *self,
g_signal_stop_emission (self, signals[CONNECTION_ADDED], 0);
path = nm_connection_get_path (NM_CONNECTION (remote));
- addinfo = add_connection_info_find (self, path);
- if (addinfo)
- add_connection_info_complete (self, addinfo, remote, NULL);
+ info = _add_connection_info_find (self, path);
+ if (info)
+ _add_connection_info_complete (info, remote, NULL);
}
static void
-object_creation_failed (NMObject *object, const char *failed_path)
+object_creation_failed (NMObject *object,
+ const char *failed_path)
{
NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
- AddConnectionInfo *addinfo;
- GError *add_error;
-
- addinfo = add_connection_info_find (self, failed_path);
- if (addinfo) {
- add_error = g_error_new_literal (NM_CLIENT_ERROR,
- NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
- _("Connection removed before it was initialized"));
- add_connection_info_complete (self, addinfo, NULL, add_error);
- g_error_free (add_error);
- }
+ AddConnectionInfo *info;
+
+ info = _add_connection_info_find (self, failed_path);
+ if (!info)
+ return;
+
+ _add_connection_info_complete (info,
+ NULL,
+ g_error_new_literal (NM_CLIENT_ERROR,
+ NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
+ _("Connection removed before it was initialized")));
}
const GPtrArray *
@@ -269,83 +298,114 @@ add_connection_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
AddConnectionInfo *info = user_data;
GError *error = NULL;
- if (info->saved) {
+ if ( info->ignore_out_result
+ && info->flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK) {
nmdbus_settings_call_add_connection_finish (NMDBUS_SETTINGS (proxy),
&info->path,
- result, &error);
- } else {
+ result,
+ &error);
+ } else if ( info->ignore_out_result
+ && info->flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY) {
nmdbus_settings_call_add_connection_unsaved_finish (NMDBUS_SETTINGS (proxy),
&info->path,
- result, &error);
+ result,
+ &error);
+ } else {
+ nmdbus_settings_call_add_connection2_finish (NMDBUS_SETTINGS (proxy),
+ &info->path,
+ &info->results,
+ result,
+ &error);
+ if (info->ignore_out_result) {
+ /* despite we have the result, the caller didn't ask for it.
+ * Through it away, so we consistently don't return a result. */
+ nm_clear_pointer (&info->results, g_variant_unref);
+ }
}
if (error) {
g_dbus_error_strip_remote_error (error);
- add_connection_info_complete (info->self, info, NULL, error);
- g_clear_error (&error);
+ _add_connection_info_complete (info, NULL, error);
+ return;
}
/* On success, we still have to wait until the connection is fully
* initialized before calling the callback.
*/
+ if (info->cancellable) {
+ gulong id;
+
+ id = g_cancellable_connect (info->cancellable,
+ G_CALLBACK (_add_connection_info_cancelled),
+ info,
+ NULL);
+ if (id == 0) {
+ /* the callback was invoked synchronously, which destroyed @info.
+ * We must not touch @info anymore. */
+ } else
+ info->cancellable_id = id;
+ }
}
void
-nm_remote_settings_add_connection_async (NMRemoteSettings *settings,
- NMConnection *connection,
- gboolean save_to_disk,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+nm_remote_settings_add_connection2 (NMRemoteSettings *self,
+ GVariant *settings,
+ NMSettingsAddConnection2Flags flags,
+ GVariant *args,
+ gboolean ignore_out_result,
+ GCancellable *cancellable,
+ NMRemoteSettingAddConnection2Callback callback,
+ gpointer user_data)
{
NMRemoteSettingsPrivate *priv;
AddConnectionInfo *info;
- GVariant *new_settings;
- g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
- g_return_if_fail (NM_IS_CONNECTION (connection));
-
- priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
-
- info = g_slice_new0 (AddConnectionInfo);
- info->self = settings;
- info->simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
- nm_remote_settings_add_connection_async);
- if (cancellable)
- g_simple_async_result_set_check_cancellable (info->simple, cancellable);
- info->saved = save_to_disk;
-
- new_settings = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
-
- if (save_to_disk) {
+ nm_assert (NM_IS_REMOTE_SETTINGS (self));
+ nm_assert (g_variant_is_of_type (settings, G_VARIANT_TYPE ("a{sa{sv}}")));
+ nm_assert (!args || g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")));
+ nm_assert (callback);
+
+ priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+
+ info = g_slice_new (AddConnectionInfo);
+ *info = (AddConnectionInfo) {
+ .self = g_object_ref (self),
+ .cancellable = nm_g_object_ref (cancellable),
+ .flags = flags,
+ .ignore_out_result = ignore_out_result,
+ .callback = callback,
+ .user_data = user_data,
+ };
+ c_list_link_tail (&priv->add_lst_head, &info->add_lst);
+
+ /* Although AddConnection2() being capable to handle also AddConnection() and
+ * AddConnectionUnsaved() variants, we prefer to use the old D-Bus methods when
+ * they are sufficient. The reason is that libnm should avoid hard dependencies
+ * on 1.20 API whenever possible. */
+ if ( ignore_out_result
+ && flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK) {
nmdbus_settings_call_add_connection (priv->proxy,
- new_settings,
- NULL,
- add_connection_done, info);
- } else {
+ settings,
+ cancellable,
+ add_connection_done,
+ info);
+ } else if ( ignore_out_result
+ && flags == NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY) {
nmdbus_settings_call_add_connection_unsaved (priv->proxy,
- new_settings,
- NULL,
- add_connection_done, info);
+ settings,
+ cancellable,
+ add_connection_done,
+ info);
+ } else {
+ nmdbus_settings_call_add_connection2 (priv->proxy,
+ settings,
+ flags,
+ args
+ ?: g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0),
+ cancellable,
+ add_connection_done,
+ info);
}
-
- priv->add_list = g_slist_append (priv->add_list, info);
-}
-
-NMRemoteConnection *
-nm_remote_settings_add_connection_finish (NMRemoteSettings *settings,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
-
- g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_add_connection_async), NULL);
-
- simple = G_SIMPLE_ASYNC_RESULT (result);
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
- else
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
}
gboolean
@@ -606,6 +666,7 @@ nm_remote_settings_init (NMRemoteSettings *self)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ c_list_init (&priv->add_lst_head);
priv->all_connections = g_ptr_array_new ();
priv->visible_connections = g_ptr_array_new ();
}
@@ -664,7 +725,7 @@ dispose (GObject *object)
{
NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
- int i;
+ guint i;
if (priv->all_connections) {
for (i = 0; i < priv->all_connections->len; i++)
diff --git a/libnm/nm-remote-settings.h b/libnm/nm-remote-settings.h
index ac0008a942..bd89cf8c68 100644
--- a/libnm/nm-remote-settings.h
+++ b/libnm/nm-remote-settings.h
@@ -73,15 +73,20 @@ NMRemoteConnection *nm_remote_settings_get_connection_by_path (NMRemoteSettings
NMRemoteConnection *nm_remote_settings_get_connection_by_uuid (NMRemoteSettings *settings,
const char *uuid);
-void nm_remote_settings_add_connection_async (NMRemoteSettings *settings,
- NMConnection *connection,
- gboolean save_to_disk,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-NMRemoteConnection *nm_remote_settings_add_connection_finish (NMRemoteSettings *settings,
- GAsyncResult *result,
- GError **error);
+typedef void (*NMRemoteSettingAddConnection2Callback) (NMRemoteSettings *self,
+ NMRemoteConnection *connection,
+ GVariant *results,
+ GError *error,
+ gpointer user_data);
+
+void nm_remote_settings_add_connection2 (NMRemoteSettings *self,
+ GVariant *settings,
+ NMSettingsAddConnection2Flags flags,
+ GVariant *args,
+ gboolean ignore_out_result,
+ GCancellable *cancellable,
+ NMRemoteSettingAddConnection2Callback callback,
+ gpointer user_data);
gboolean nm_remote_settings_load_connections (NMRemoteSettings *settings,
char **filenames,