libnm: implement nm_client_activate_connection()/nm_client_add_and_activate_connection*() by using GDBusConnection directly

We still need the bits in "nm-manager.c", to wait until the
NMActiveConnection instance is ready. This is now done by
nm_manager_complete_active_connection().
This commit is contained in:
Thomas Haller 2019-10-03 16:30:25 +02:00
parent eaddc22775
commit 90d0ae0faf
3 changed files with 298 additions and 395 deletions

View file

@ -1108,22 +1108,32 @@ nm_client_get_activating_connection (NMClient *client)
}
static void
activate_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
activate_connection_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *simple = user_data;
NMActiveConnection *ac;
NMClient *self;
gs_unref_object GTask *task = user_data;
gs_unref_variant GVariant *ret = NULL;
const char *v_active_connection;
GError *error = NULL;
ac = nm_manager_activate_connection_finish (NM_MANAGER (object), result, &error);
if (ac)
g_simple_async_result_set_op_res_gpointer (simple, ac, g_object_unref);
else
g_simple_async_result_take_error (simple, error);
ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
if (!ret) {
g_dbus_error_strip_remote_error (error);
g_task_return_error (task, error);
return;
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
self = g_task_get_source_object (task);
g_variant_get (ret, "(&o)", &v_active_connection);
nm_manager_wait_for_active_connection (NM_CLIENT_GET_PRIVATE (self)->manager,
v_active_connection,
NULL,
NULL,
g_steal_pointer (&task));
}
/**
@ -1168,27 +1178,39 @@ nm_client_activate_connection_async (NMClient *client,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
GError *error = NULL;
const char *arg_connection = NULL;
const char *arg_device = NULL;
g_return_if_fail (NM_IS_CLIENT (client));
if (device)
g_return_if_fail (NM_IS_DEVICE (device));
if (connection)
g_return_if_fail (NM_IS_CONNECTION (connection));
if (!_nm_client_check_nm_running (client, &error)) {
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
return;
if (connection) {
g_return_if_fail (NM_IS_CONNECTION (connection));
arg_connection = nm_connection_get_path (connection);
g_return_if_fail (arg_connection);
}
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
nm_client_activate_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
nm_manager_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager,
connection, device, specific_object,
cancellable, activate_cb, simple);
if (device) {
g_return_if_fail (NM_IS_DEVICE (device));
arg_device = nm_object_get_path (NM_OBJECT (device));
g_return_if_fail (arg_device);
}
_nm_object_dbus_call (client,
nm_client_activate_connection_async,
cancellable,
callback,
user_data,
NM_DBUS_PATH,
NM_DBUS_INTERFACE,
"ActivateConnection",
g_variant_new ("(ooo)",
arg_connection ?: "/",
arg_device ?: "/",
specific_object ?: "/"),
G_VARIANT_TYPE ("(o)"),
G_DBUS_CALL_FLAGS_NONE,
NM_DBUS_DEFAULT_TIMEOUT_MSEC,
activate_connection_cb);
}
/**
@ -1207,37 +1229,153 @@ nm_client_activate_connection_finish (NMClient *client,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
nm_auto_free_activate_result _NMActivateResult *r = NULL;
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 (nm_g_task_is_valid (result, client, nm_client_activate_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
r = g_task_propagate_pointer (G_TASK (result), error);
if (!r)
return NULL;
else
return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
return g_steal_pointer (&r->active);
}
static void
add_activate_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
_add_and_activate_connection_done (GObject *object,
GAsyncResult *result,
gboolean use_add_and_activate_v2,
GTask *task_take)
{
gs_unref_object GSimpleAsyncResult *simple = user_data;
gs_unref_variant GVariant *result_data = NULL;
gs_unref_object NMActiveConnection *ac = NULL;
_nm_unused gs_unref_object GTask *task = task_take;
NMClient *self;
gs_unref_variant GVariant *ret = NULL;
GError *error = NULL;
const char *v_path;
const char *v_active_connection;
gs_unref_variant GVariant *v_result = NULL;
ac = nm_manager_add_and_activate_connection_finish (NM_MANAGER (object), result, &result_data, &error);
if (ac) {
g_simple_async_result_set_op_res_gpointer (simple,
_nm_activate_result_new (ac, result_data),
(GDestroyNotify) _nm_activate_result_free);
} else
g_simple_async_result_take_error (simple, error);
ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
if (!ret) {
g_dbus_error_strip_remote_error (error);
g_task_return_error (task, error);
return;
}
g_simple_async_result_complete (simple);
self = g_task_get_source_object (task);
if (use_add_and_activate_v2) {
g_variant_get (ret,
"(&o&o@a{sv})",
&v_path,
&v_active_connection,
&v_result);
} else {
g_variant_get (ret,
"(&o&o)",
&v_path,
&v_active_connection);
}
nm_manager_wait_for_active_connection (NM_CLIENT_GET_PRIVATE (self)->manager,
v_active_connection,
v_path,
g_steal_pointer (&v_result),
g_steal_pointer (&task));
}
static void
_add_and_activate_connection_v1_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
_add_and_activate_connection_done (object, result, FALSE, user_data);
}
static void
_add_and_activate_connection_v2_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
_add_and_activate_connection_done (object, result, TRUE, user_data);
}
static void
_add_and_activate_connection (NMClient *client,
gboolean is_v2,
NMConnection *partial,
NMDevice *device,
const char *specific_object,
GVariant *options,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GVariant *arg_connection = NULL;
gboolean use_add_and_activate_v2 = FALSE;
const char *arg_device = NULL;
gpointer source_tag;
g_return_if_fail (NM_IS_CLIENT (client));
g_return_if_fail (!partial || NM_IS_CONNECTION (partial));
if (device) {
g_return_if_fail (NM_IS_DEVICE (device));
arg_device = nm_object_get_path (NM_OBJECT (device));
g_return_if_fail (arg_device);
}
if (partial)
arg_connection = nm_connection_to_dbus (partial, NM_CONNECTION_SERIALIZE_ALL);
if (!arg_connection)
arg_connection = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
if (is_v2) {
if (!options)
options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
use_add_and_activate_v2 = TRUE;
source_tag = nm_client_add_and_activate_connection2;
} else {
if (options) {
if (g_variant_n_children (options) > 0)
use_add_and_activate_v2 = TRUE;
else
nm_clear_pointer (&options, nm_g_variant_unref_floating);
}
source_tag = nm_client_add_and_activate_connection_async;
}
if (use_add_and_activate_v2) {
_nm_object_dbus_call (client,
source_tag,
cancellable,
callback,
user_data,
NM_DBUS_PATH,
NM_DBUS_INTERFACE,
"AddAndActivateConnection2",
g_variant_new ("(@a{sa{sv}}oo@a{sv})",
arg_connection,
arg_device ?: "/",
specific_object ?: "/",
options),
G_VARIANT_TYPE ("(ooa{sv})"),
G_DBUS_CALL_FLAGS_NONE,
NM_DBUS_DEFAULT_TIMEOUT_MSEC,
_add_and_activate_connection_v2_cb);
} else {
_nm_object_dbus_call (client,
source_tag,
cancellable,
callback,
user_data,
NM_DBUS_PATH,
NM_DBUS_INTERFACE,
"AddAndActivateConnection",
g_variant_new ("(@a{sa{sv}}oo)",
arg_connection,
arg_device ?: "/",
specific_object ?: "/"),
G_VARIANT_TYPE ("(oo)"),
G_DBUS_CALL_FLAGS_NONE,
NM_DBUS_DEFAULT_TIMEOUT_MSEC,
_add_and_activate_connection_v1_cb);
}
}
/**
@ -1254,6 +1392,7 @@ add_activate_cb (GObject *object,
* path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
* get using nm_object_get_path(), and which will be used to complete the
* details of the newly added connection.
* If the variant is floating, it will be consumed.
* @cancellable: a #GCancellable, or %NULL
* @callback: callback to be called when the activation has started
* @user_data: caller-specific data passed to @callback
@ -1278,32 +1417,15 @@ nm_client_add_and_activate_connection_async (NMClient *client,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
GError *error = NULL;
g_return_if_fail (NM_IS_CLIENT (client));
g_return_if_fail (NM_IS_DEVICE (device));
if (partial)
g_return_if_fail (NM_IS_CONNECTION (partial));
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_and_activate_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager,
partial,
device,
specific_object,
NULL,
FALSE,
cancellable,
add_activate_cb,
simple);
_add_and_activate_connection (client,
FALSE,
partial,
device,
specific_object,
NULL,
cancellable,
callback,
user_data);
}
/**
@ -1325,17 +1447,15 @@ nm_client_add_and_activate_connection_finish (NMClient *client,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
_NMActivateResult *r;
nm_auto_free_activate_result _NMActivateResult *r = NULL;
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 (nm_g_task_is_valid (result, client, nm_client_add_and_activate_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
r = g_task_propagate_pointer (G_TASK (result), error);
if (!r)
return NULL;
r = g_simple_async_result_get_op_res_gpointer (simple);
return g_object_ref (r->active);
return g_steal_pointer (&r->active);
}
/**
@ -1391,32 +1511,15 @@ nm_client_add_and_activate_connection2 (NMClient *client,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
GError *error = NULL;
g_return_if_fail (NM_IS_CLIENT (client));
g_return_if_fail (NM_IS_DEVICE (device));
if (partial)
g_return_if_fail (NM_IS_CONNECTION (partial));
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_and_activate_connection2);
if (cancellable)
g_simple_async_result_set_check_cancellable (simple, cancellable);
nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager,
partial,
device,
specific_object,
options,
TRUE,
cancellable,
add_activate_cb,
simple);
_add_and_activate_connection (client,
TRUE,
partial,
device,
specific_object,
options,
cancellable,
callback,
user_data);
}
/**
@ -1442,20 +1545,18 @@ nm_client_add_and_activate_connection2_finish (NMClient *client,
GVariant **out_result,
GError **error)
{
GSimpleAsyncResult *simple;
_NMActivateResult *r;
nm_auto_free_activate_result _NMActivateResult *r = NULL;
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 (nm_g_task_is_valid (result, client, nm_client_add_and_activate_connection2), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error)) {
r = g_task_propagate_pointer (G_TASK (result), error);
if (!r) {
NM_SET_OUT (out_result, NULL);
return NULL;
}
r = g_simple_async_result_get_op_res_gpointer (simple);
NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output));
return g_object_ref (r->active);
NM_SET_OUT (out_result, g_steal_pointer (&r->add_and_activate_output));
return g_steal_pointer (&r->active);
}
/**

View file

@ -58,7 +58,7 @@ typedef struct {
/* Activations waiting for their NMActiveConnection
* to appear and then their callback to be called.
*/
CList pending_activations;
CList wait_for_active_connection_lst_head;
gboolean networking_enabled;
gboolean wireless_enabled;
@ -170,7 +170,7 @@ nm_manager_init (NMManager *manager)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
c_list_init (&priv->pending_activations);
c_list_init (&priv->wait_for_active_connection_lst_head);
priv->state = NM_STATE_UNKNOWN;
priv->connectivity = NM_CONNECTIVITY_UNKNOWN;
@ -850,10 +850,8 @@ typedef enum {
typedef struct {
CList lst;
NMManager *manager;
GSimpleAsyncResult *simple;
GCancellable *cancellable;
GTask *task;
char *active_path;
char *new_connection_path;
GVariant *add_and_activate_output;
gulong cancelled_id;
ActivateType activate_type;
@ -871,7 +869,7 @@ _nm_activate_result_new (NMActiveConnection *active,
r = g_slice_new (_NMActivateResult);
*r = (_NMActivateResult) {
.active = g_object_ref (active),
.add_and_activate_output = nm_g_variant_ref (add_and_activate_output),
.add_and_activate_output = g_steal_pointer (&add_and_activate_output),
};
return r;
}
@ -879,7 +877,7 @@ _nm_activate_result_new (NMActiveConnection *active,
void
_nm_activate_result_free (_NMActivateResult *result)
{
g_object_unref (result->active);
nm_g_object_unref (result->active);
nm_g_variant_unref (result->add_and_activate_output);
g_slice_free (_NMActivateResult, result);
}
@ -889,27 +887,27 @@ activate_info_complete (ActivateInfo *info,
NMActiveConnection *active,
GError *error)
{
nm_assert (info);
nm_assert (info->task);
nm_assert (G_IS_TASK (info->task));
nm_assert ((!error) != (!active));
nm_clear_g_signal_handler (info->cancellable, &info->cancelled_id);
c_list_unlink_stale (&info->lst);
if (active) {
g_simple_async_result_set_op_res_gpointer (info->simple,
_nm_activate_result_new (active,
info->add_and_activate_output),
(GDestroyNotify) _nm_activate_result_free);
} else
g_simple_async_result_set_from_error (info->simple, error);
nm_clear_g_signal_handler (g_task_get_cancellable (info->task), &info->cancelled_id);
g_simple_async_result_complete (info->simple);
if (error)
g_task_return_error (info->task, error);
else {
g_task_return_pointer (info->task,
_nm_activate_result_new (active,
g_steal_pointer (&info->add_and_activate_output)),
(GDestroyNotify) _nm_activate_result_free);
}
nm_g_variant_unref (info->add_and_activate_output);
g_free (info->active_path);
g_free (info->new_connection_path);
g_object_unref (info->simple);
nm_g_object_unref (info->cancellable);
g_object_unref (info->task);
g_slice_free (ActivateInfo, info);
}
@ -931,15 +929,14 @@ find_active_connection_by_path (NMManager *self, const char *ac_path)
}
static void
recheck_pending_activations (NMManager *self)
_wait_for_active_connections_check (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
CList *iter, *safe;
CList *iter;
NMActiveConnection *candidate;
const GPtrArray *devices;
NMDevice *device;
GDBusObjectManager *object_manager = NULL;
GError *error;
GDBusObjectManager *object_manager;
object_manager = _nm_object_get_dbus_object_manager (NM_OBJECT (self));
@ -948,23 +945,23 @@ recheck_pending_activations (NMManager *self)
* device have both updated their properties to point to each other, and
* call the pending connection's callback.
*/
c_list_for_each_safe (iter, safe, &priv->pending_activations) {
again:
c_list_for_each (iter, &priv->wait_for_active_connection_lst_head) {
ActivateInfo *info = c_list_entry (iter, ActivateInfo, lst);
gs_unref_object GDBusObject *dbus_obj = NULL;
if (!info->active_path)
continue;
nm_assert (info->active_path);
/* Check that the object manager still knows about the object.
* It could be that it vanished before we even learned its name. */
dbus_obj = g_dbus_object_manager_get_object (object_manager, info->active_path);
if (!dbus_obj) {
error = g_error_new_literal (NM_CLIENT_ERROR,
NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
_("Active connection removed before it was initialized"));
activate_info_complete (info, NULL, error);
g_clear_error (&error);
break;
activate_info_complete (info,
NULL,
g_error_new_literal (NM_CLIENT_ERROR,
NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
_("Active connection removed before it was initialized")));
goto again;
}
candidate = find_active_connection_by_path (self, info->active_path);
@ -983,246 +980,72 @@ recheck_pending_activations (NMManager *self)
}
activate_info_complete (info, candidate, NULL);
break;
goto again;
}
}
static void
activation_cancelled (GCancellable *cancellable,
gpointer user_data)
_wait_for_active_connection_cancelled_cb (GCancellable *cancellable,
gpointer user_data)
{
ActivateInfo *info = user_data;
GError *error = NULL;
gs_free_error GError *error = NULL;
if (!g_cancellable_set_error_if_cancelled (cancellable, &error))
return;
activate_info_complete (info, NULL, error);
g_clear_error (&error);
}
static void
activate_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
ActivateInfo *info = user_data;
GError *error = NULL;
if (nmdbus_manager_call_activate_connection_finish (NMDBUS_MANAGER (object),
&info->active_path,
result, &error)) {
if (info->cancellable) {
info->cancelled_id = g_signal_connect (info->cancellable, "cancelled",
G_CALLBACK (activation_cancelled), info);
}
recheck_pending_activations (info->manager);
} else {
g_dbus_error_strip_remote_error (error);
activate_info_complete (info, NULL, error);
g_clear_error (&error);
}
activate_info_complete (info, NULL, g_steal_pointer (&error));
}
void
nm_manager_activate_connection_async (NMManager *manager,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
nm_manager_wait_for_active_connection (NMManager *self,
const char *active_path,
const char *connection_path,
GVariant *add_and_activate_output_take,
GTask *task_take)
{
NMManagerPrivate *priv;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
gs_unref_object GTask *task = task_take;
gs_unref_variant GVariant *add_and_activate_output = add_and_activate_output_take;
ActivateInfo *info;
GCancellable *cancellable;
g_return_if_fail (NM_IS_MANAGER (manager));
if (device)
g_return_if_fail (NM_IS_DEVICE (device));
if (connection)
g_return_if_fail (NM_IS_CONNECTION (connection));
nm_assert (NM_IS_MANAGER (self));
nm_assert (active_path);
nm_assert (G_IS_TASK (task));
priv = NM_MANAGER_GET_PRIVATE (manager);
/* FIXME: there is no timeout for how long we wait. But this entire
* code will be reworked, also that we have a suitable GMainContext
* where we can schedule the timeout (we shouldn't use g_main_context_default()). */
info = g_slice_new0 (ActivateInfo);
info->activate_type = ACTIVATE_TYPE_ACTIVATE_CONNECTION;
info->manager = manager;
info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
nm_manager_activate_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (info->simple, cancellable);
info->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
info = g_slice_new (ActivateInfo);
*info = (ActivateInfo) {
.manager = g_object_ref (self),
.task = g_steal_pointer (&task),
.active_path = g_strdup (active_path),
.add_and_activate_output = g_steal_pointer (&add_and_activate_output),
};
c_list_link_tail (&priv->wait_for_active_connection_lst_head, &info->lst);
c_list_link_tail (&priv->pending_activations, &info->lst);
nmdbus_manager_call_activate_connection (priv->proxy,
connection ? nm_connection_get_path (connection) : "/",
device ? nm_object_get_path (NM_OBJECT (device)) : "/",
specific_object ?: "/",
cancellable,
activate_cb, info);
}
NMActiveConnection *
nm_manager_activate_connection_finish (NMManager *manager,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
_NMActivateResult *r;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_activate_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
r = g_simple_async_result_get_op_res_gpointer (simple);
return g_object_ref (r->active);
}
static void
add_activate_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
ActivateInfo *info = user_data;
gs_free_error GError *error = NULL;
gboolean success;
nm_assert (info);
nm_assert (!info->active_path);
nm_assert (!info->add_and_activate_output);
if (info->activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION) {
success = nmdbus_manager_call_add_and_activate_connection_finish (NMDBUS_MANAGER (object),
NULL,
&info->active_path,
result,
&error);
} else {
success = nmdbus_manager_call_add_and_activate_connection2_finish (NMDBUS_MANAGER (object),
NULL,
&info->active_path,
&info->add_and_activate_output,
result,
&error);
}
if (!success) {
g_dbus_error_strip_remote_error (error);
activate_info_complete (info, NULL, error);
return;
}
if (info->cancellable) {
info->cancelled_id = g_signal_connect (info->cancellable, "cancelled",
G_CALLBACK (activation_cancelled), info);
}
recheck_pending_activations (info->manager);
}
void
nm_manager_add_and_activate_connection_async (NMManager *manager,
NMConnection *partial,
NMDevice *device,
const char *specific_object,
GVariant *options,
gboolean force_v2,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
NMManagerPrivate *priv;
GVariant *dict = NULL;
ActivateInfo *info;
ActivateType activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION;
g_return_if_fail (NM_IS_MANAGER (manager));
g_return_if_fail (NM_IS_DEVICE (device));
if (partial)
g_return_if_fail (NM_IS_CONNECTION (partial));
priv = NM_MANAGER_GET_PRIVATE (manager);
info = g_slice_new0 (ActivateInfo);
info->manager = manager;
info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
nm_manager_add_and_activate_connection_async);
if (cancellable)
g_simple_async_result_set_check_cancellable (info->simple, cancellable);
info->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
c_list_link_tail (&priv->pending_activations, &info->lst);
if (partial)
dict = nm_connection_to_dbus (partial, NM_CONNECTION_SERIALIZE_ALL);
if (!dict)
dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
if (force_v2) {
if (!options)
options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2;
} else {
if (options) {
if (g_variant_n_children (options) > 0)
activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2;
else
nm_g_variant_unref_floating (options);
cancellable = g_task_get_cancellable (info->task);
if (cancellable) {
info->cancelled_id = g_signal_connect (cancellable,
"cancelled",
G_CALLBACK (_wait_for_active_connection_cancelled_cb),
info);
if (g_cancellable_is_cancelled (cancellable)) {
_wait_for_active_connection_cancelled_cb (cancellable, info);
return;
}
}
info->activate_type = activate_type;
if (activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2) {
nmdbus_manager_call_add_and_activate_connection2 (priv->proxy,
dict,
nm_object_get_path (NM_OBJECT (device)),
specific_object ?: "/",
options,
cancellable,
add_activate_cb,
info);
} else {
nmdbus_manager_call_add_and_activate_connection (priv->proxy,
dict,
nm_object_get_path (NM_OBJECT (device)),
specific_object ?: "/",
cancellable,
add_activate_cb,
info);
}
}
NMActiveConnection *
nm_manager_add_and_activate_connection_finish (NMManager *manager,
GAsyncResult *result,
GVariant **out_result,
GError **error)
{
GSimpleAsyncResult *simple;
_NMActivateResult *r;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_add_and_activate_connection_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error)) {
NM_SET_OUT (out_result, NULL);
return NULL;
}
r = g_simple_async_result_get_op_res_gpointer (simple);
NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output));
return g_object_ref (r->active);
_wait_for_active_connections_check (self);
}
static void
device_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
NMManager *self = user_data;
recheck_pending_activations (self);
_wait_for_active_connections_check (user_data);
}
static void
@ -1241,9 +1064,7 @@ device_removed (NMManager *self, NMDevice *device)
static void
ac_devices_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
NMManager *self = user_data;
recheck_pending_activations (self);
_wait_for_active_connections_check (user_data);
}
static void
@ -1251,14 +1072,14 @@ active_connection_added (NMManager *self, NMActiveConnection *ac)
{
g_signal_connect_object (ac, "notify::" NM_ACTIVE_CONNECTION_DEVICES,
G_CALLBACK (ac_devices_changed), self, 0);
recheck_pending_activations (self);
_wait_for_active_connections_check (self);
}
static void
active_connection_removed (NMManager *self, NMActiveConnection *ac)
{
g_signal_handlers_disconnect_by_func (ac, G_CALLBACK (ac_devices_changed), self);
recheck_pending_activations (self);
_wait_for_active_connections_check (self);
}
static void
@ -1767,6 +1588,8 @@ dispose (GObject *object)
NMManager *manager = NM_MANAGER (object);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (object);
nm_assert (c_list_is_empty (&priv->wait_for_active_connection_lst_head));
nm_clear_g_cancellable (&priv->perm_call_cancellable);
if (priv->devices) {
@ -1786,11 +1609,6 @@ dispose (GObject *object)
g_clear_object (&priv->proxy);
/* Each activation should hold a ref on @manager, so if we're being disposed,
* there shouldn't be any pending.
*/
g_warn_if_fail (c_list_is_empty (&priv->pending_activations));
g_hash_table_destroy (priv->permissions);
priv->permissions = NULL;

View file

@ -155,30 +155,11 @@ const GPtrArray *nm_manager_get_active_connections (NMManager *manager);
NMActiveConnection *nm_manager_get_primary_connection (NMManager *manager);
NMActiveConnection *nm_manager_get_activating_connection (NMManager *manager);
void nm_manager_activate_connection_async (NMManager *manager,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
NMActiveConnection *nm_manager_activate_connection_finish (NMManager *manager,
GAsyncResult *result,
GError **error);
void nm_manager_add_and_activate_connection_async (NMManager *manager,
NMConnection *partial,
NMDevice *device,
const char *specific_object,
GVariant *options,
gboolean force_v2,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
NMActiveConnection *nm_manager_add_and_activate_connection_finish (NMManager *manager,
GAsyncResult *result,
GVariant **out_result,
GError **error);
void nm_manager_wait_for_active_connection (NMManager *self,
const char *active_path,
const char *connection_path,
GVariant *add_and_activate_output_take,
GTask *task_take);
const GPtrArray *nm_manager_get_checkpoints (NMManager *manager);
void nm_manager_checkpoint_create (NMManager *manager,
@ -229,6 +210,9 @@ _NMActivateResult *_nm_activate_result_new (NMActiveConnection *active,
void _nm_activate_result_free (_NMActivateResult *result);
NM_AUTO_DEFINE_FCN0 (_NMActivateResult *, _nm_auto_free_activate_result, _nm_activate_result_free)
#define nm_auto_free_activate_result nm_auto(_nm_auto_free_activate_result)
/*****************************************************************************/
void nm_manager_reload (NMManager *manager,