mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 20:30:08 +01:00
manager: track pending authorizations for activating connections
We cannot just fire off asynchronous actions without keeping a handle to them. Otherwise, it's impossible for NMManager to know which asynchronous operations are pending, and more importantly: it cannot cancel them. One day, I want that we do a clean shutdown, where NetworkManager stops all pending operations, and cleans up everything. That implies, that every operation is cancellable in a timely manner. Rework pending nm_active_connection_authorize() calls to be tracked in a list, so that they are still reachable to NMManager. Note that currently NMManager does not yet try to cancel these operations ever. However, it would now be possible to do so.
This commit is contained in:
parent
dc2004ddfb
commit
f4fc62bad8
1 changed files with 185 additions and 39 deletions
224
src/nm-manager.c
224
src/nm-manager.c
|
|
@ -29,6 +29,8 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nm-utils/nm-c-list.h"
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "vpn/nm-vpn-manager.h"
|
||||
|
|
@ -73,6 +75,32 @@ typedef struct {
|
|||
const char *hw_prop;
|
||||
} RadioState;
|
||||
|
||||
typedef enum {
|
||||
ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_INTERNAL,
|
||||
ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_USER,
|
||||
ASYNC_OP_TYPE_AC_AUTH_ADD_AND_ACTIVATE,
|
||||
} AsyncOpType;
|
||||
|
||||
typedef struct {
|
||||
CList async_op_lst;
|
||||
NMManager *self;
|
||||
AsyncOpType async_op_type;
|
||||
union {
|
||||
struct {
|
||||
NMActiveConnection *active;
|
||||
union {
|
||||
struct {
|
||||
GDBusMethodInvocation *invocation;
|
||||
} activate_user;
|
||||
struct {
|
||||
GDBusMethodInvocation *invocation;
|
||||
NMConnection *connection;
|
||||
} add_and_activate;
|
||||
};
|
||||
} ac_auth;
|
||||
};
|
||||
} AsyncOpData;
|
||||
|
||||
enum {
|
||||
DEVICE_ADDED,
|
||||
INTERNAL_DEVICE_ADDED,
|
||||
|
|
@ -122,7 +150,7 @@ typedef struct {
|
|||
GArray *capabilities;
|
||||
|
||||
CList active_connections_lst_head;
|
||||
GSList *authorizing_connections;
|
||||
CList async_op_lst_head;
|
||||
guint ac_cleanup_id;
|
||||
NMActiveConnection *primary_connection;
|
||||
NMActiveConnection *activating_connection;
|
||||
|
|
@ -331,6 +359,22 @@ static NMActiveConnection *active_connection_find_first (NMManager *self,
|
|||
|
||||
static NMConnectivity *concheck_get_mgr (NMManager *self);
|
||||
|
||||
static void _internal_activation_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
gboolean success,
|
||||
const char *error_desc);
|
||||
static void _add_and_activate_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
NMConnection *connection,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean success,
|
||||
const char *error_desc);
|
||||
static void _activation_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean success,
|
||||
const char *error_desc);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
|
||||
|
|
@ -404,6 +448,104 @@ concheck_get_mgr (NMManager *self)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static AsyncOpData *
|
||||
_async_op_data_new_authorize_activate_internal (NMManager *self, NMActiveConnection *active_take)
|
||||
{
|
||||
AsyncOpData *async_op_data;
|
||||
|
||||
async_op_data = g_slice_new0 (AsyncOpData);
|
||||
async_op_data->async_op_type = ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_INTERNAL;
|
||||
async_op_data->self = g_object_ref (self);
|
||||
async_op_data->ac_auth.active = active_take;
|
||||
c_list_link_tail (&NM_MANAGER_GET_PRIVATE (self)->async_op_lst_head, &async_op_data->async_op_lst);
|
||||
return async_op_data;
|
||||
}
|
||||
|
||||
static AsyncOpData *
|
||||
_async_op_data_new_ac_auth_activate_user (NMManager *self,
|
||||
NMActiveConnection *active_take,
|
||||
GDBusMethodInvocation *invocation_take)
|
||||
{
|
||||
AsyncOpData *async_op_data;
|
||||
|
||||
async_op_data = g_slice_new0 (AsyncOpData);
|
||||
async_op_data->async_op_type = ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_USER;
|
||||
async_op_data->self = g_object_ref (self);
|
||||
async_op_data->ac_auth.active = active_take;
|
||||
async_op_data->ac_auth.activate_user.invocation = invocation_take;
|
||||
c_list_link_tail (&NM_MANAGER_GET_PRIVATE (self)->async_op_lst_head, &async_op_data->async_op_lst);
|
||||
return async_op_data;
|
||||
}
|
||||
|
||||
static AsyncOpData *
|
||||
_async_op_data_new_ac_auth_add_and_activate (NMManager *self,
|
||||
NMActiveConnection *active_take,
|
||||
GDBusMethodInvocation *invocation_take,
|
||||
NMConnection *connection_take)
|
||||
{
|
||||
AsyncOpData *async_op_data;
|
||||
|
||||
async_op_data = g_slice_new0 (AsyncOpData);
|
||||
async_op_data->async_op_type = ASYNC_OP_TYPE_AC_AUTH_ADD_AND_ACTIVATE;
|
||||
async_op_data->self = g_object_ref (self);
|
||||
async_op_data->ac_auth.active = active_take;
|
||||
async_op_data->ac_auth.add_and_activate.invocation = invocation_take;
|
||||
async_op_data->ac_auth.add_and_activate.connection = connection_take;
|
||||
c_list_link_tail (&NM_MANAGER_GET_PRIVATE (self)->async_op_lst_head, &async_op_data->async_op_lst);
|
||||
return async_op_data;
|
||||
}
|
||||
|
||||
static void
|
||||
_async_op_complete_ac_auth_cb (NMActiveConnection *active,
|
||||
gboolean success,
|
||||
const char *error_desc,
|
||||
gpointer user_data)
|
||||
{
|
||||
AsyncOpData *async_op_data = user_data;
|
||||
|
||||
nm_assert (async_op_data);
|
||||
nm_assert (NM_IS_MANAGER (async_op_data->self));
|
||||
nm_assert (nm_c_list_contains_entry (&NM_MANAGER_GET_PRIVATE (async_op_data->self)->async_op_lst_head, async_op_data, async_op_lst));
|
||||
nm_assert (NM_IS_ACTIVE_CONNECTION (active));
|
||||
nm_assert (active == async_op_data->ac_auth.active);
|
||||
|
||||
c_list_unlink (&async_op_data->async_op_lst);
|
||||
|
||||
switch (async_op_data->async_op_type) {
|
||||
case ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_INTERNAL:
|
||||
_internal_activation_auth_done (async_op_data->self,
|
||||
async_op_data->ac_auth.active,
|
||||
success,
|
||||
error_desc);
|
||||
break;
|
||||
case ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_USER:
|
||||
_activation_auth_done (async_op_data->self,
|
||||
async_op_data->ac_auth.active,
|
||||
async_op_data->ac_auth.activate_user.invocation,
|
||||
success,
|
||||
error_desc);
|
||||
break;
|
||||
case ASYNC_OP_TYPE_AC_AUTH_ADD_AND_ACTIVATE:
|
||||
_add_and_activate_auth_done (async_op_data->self,
|
||||
async_op_data->ac_auth.active,
|
||||
async_op_data->ac_auth.add_and_activate.connection,
|
||||
async_op_data->ac_auth.add_and_activate.invocation,
|
||||
success,
|
||||
error_desc);
|
||||
g_object_unref (async_op_data->ac_auth.add_and_activate.connection);
|
||||
break;
|
||||
default:
|
||||
nm_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref (async_op_data->ac_auth.active);
|
||||
g_object_unref (async_op_data->self);
|
||||
g_slice_free (AsyncOpData, async_op_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
guint32 aspired_metric;
|
||||
|
|
@ -4095,18 +4237,16 @@ _new_active_connection (NMManager *self,
|
|||
}
|
||||
|
||||
static void
|
||||
_internal_activation_auth_done (NMActiveConnection *active,
|
||||
_internal_activation_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
gboolean success,
|
||||
const char *error_desc,
|
||||
gpointer user_data)
|
||||
const char *error_desc)
|
||||
{
|
||||
_nm_unused gs_unref_object NMActiveConnection *active_to_free = active;
|
||||
NMManager *self = user_data;
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMActiveConnection *ac;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active);
|
||||
nm_assert (NM_IS_ACTIVE_CONNECTION (active));
|
||||
|
||||
if (!success)
|
||||
goto fail;
|
||||
|
|
@ -4181,7 +4321,7 @@ nm_manager_activate_connection (NMManager *self,
|
|||
{
|
||||
NMManagerPrivate *priv;
|
||||
NMActiveConnection *active;
|
||||
GSList *iter;
|
||||
AsyncOpData *async_op_data;
|
||||
|
||||
g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
|
||||
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL);
|
||||
|
|
@ -4203,9 +4343,12 @@ nm_manager_activate_connection (NMManager *self,
|
|||
* otherwise race and cause the device to disconnect and reconnect repeatedly.
|
||||
* In particular, this allows the master and multiple slaves to concurrently auto-activate
|
||||
* while all the slaves would use the same active-connection. */
|
||||
for (iter = priv->authorizing_connections; iter; iter = g_slist_next (iter)) {
|
||||
active = iter->data;
|
||||
c_list_for_each_entry (async_op_data, &priv->async_op_lst_head, async_op_lst) {
|
||||
|
||||
if (async_op_data->async_op_type != ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_INTERNAL)
|
||||
continue;
|
||||
|
||||
active = async_op_data->ac_auth.active;
|
||||
if ( connection == nm_active_connection_get_settings_connection (active)
|
||||
&& nm_streq0 (nm_active_connection_get_specific_object (active), specific_object)
|
||||
&& nm_active_connection_get_device (active) == device
|
||||
|
|
@ -4228,8 +4371,11 @@ nm_manager_activate_connection (NMManager *self,
|
|||
if (!active)
|
||||
return NULL;
|
||||
|
||||
priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active);
|
||||
nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self);
|
||||
nm_active_connection_authorize (active,
|
||||
NULL,
|
||||
_async_op_complete_ac_auth_cb,
|
||||
_async_op_data_new_authorize_activate_internal (self,
|
||||
active));
|
||||
return active;
|
||||
}
|
||||
|
||||
|
|
@ -4359,19 +4505,15 @@ validate_activation_request (NMManager *self,
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_activation_auth_done (NMActiveConnection *active,
|
||||
_activation_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean success,
|
||||
const char *error_desc,
|
||||
gpointer user_data)
|
||||
const char *error_desc)
|
||||
{
|
||||
NMManager *self;
|
||||
GDBusMethodInvocation *context;
|
||||
GError *error = NULL;
|
||||
NMAuthSubject *subject;
|
||||
NMSettingsConnection *connection;
|
||||
_nm_unused gs_unref_object NMActiveConnection *active_free = active;
|
||||
|
||||
nm_utils_user_data_pack (user_data, &self, &context);
|
||||
|
||||
subject = nm_active_connection_get_subject (active);
|
||||
connection = nm_active_connection_get_settings_connection (active);
|
||||
|
|
@ -4389,7 +4531,7 @@ _activation_auth_done (NMActiveConnection *active,
|
|||
nm_settings_connection_autoconnect_blocked_reason_set (connection,
|
||||
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
|
||||
FALSE);
|
||||
g_dbus_method_invocation_return_value (context,
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(o)",
|
||||
nm_dbus_object_get_path (NM_DBUS_OBJECT (active))));
|
||||
nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, NULL,
|
||||
|
|
@ -4403,7 +4545,7 @@ fail:
|
|||
NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN,
|
||||
error->message);
|
||||
|
||||
g_dbus_method_invocation_take_error (context, error);
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4493,8 +4635,10 @@ impl_manager_activate_connection (NMDBusObject *obj,
|
|||
* is unsuitable for a coordinated shutdown. */
|
||||
nm_active_connection_authorize (g_steal_pointer (&active),
|
||||
NULL,
|
||||
_activation_auth_done,
|
||||
nm_utils_user_data_pack (self, invocation));
|
||||
_async_op_complete_ac_auth_cb,
|
||||
_async_op_data_new_ac_auth_activate_user (self,
|
||||
active,
|
||||
invocation));
|
||||
return;
|
||||
|
||||
error:
|
||||
|
|
@ -4564,19 +4708,16 @@ activation_add_done (NMSettings *settings,
|
|||
}
|
||||
|
||||
static void
|
||||
_add_and_activate_auth_done (NMActiveConnection *active,
|
||||
_add_and_activate_auth_done (NMManager *self,
|
||||
NMActiveConnection *active,
|
||||
NMConnection *connection,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean success,
|
||||
const char *error_desc,
|
||||
gpointer user_data)
|
||||
const char *error_desc)
|
||||
{
|
||||
NMManager *self;
|
||||
NMManagerPrivate *priv;
|
||||
GDBusMethodInvocation *context;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
nm_utils_user_data_unpack (user_data, &self, &context, &connection);
|
||||
|
||||
if (!success) {
|
||||
error = g_error_new_literal (NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
|
|
@ -4587,8 +4728,7 @@ _add_and_activate_auth_done (NMActiveConnection *active,
|
|||
NULL,
|
||||
nm_active_connection_get_subject (active),
|
||||
error->message);
|
||||
g_dbus_method_invocation_take_error (context, error);
|
||||
g_object_unref (active);
|
||||
g_dbus_method_invocation_take_error (invocation, error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4597,10 +4737,10 @@ _add_and_activate_auth_done (NMActiveConnection *active,
|
|||
nm_settings_add_connection_dbus (priv->settings,
|
||||
connection,
|
||||
FALSE,
|
||||
context,
|
||||
invocation,
|
||||
activation_add_done,
|
||||
nm_utils_user_data_pack (self,
|
||||
active /* pass on the reference in @active to the callback */));
|
||||
g_object_ref (active)));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4692,10 +4832,13 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
|
|||
goto error;
|
||||
|
||||
nm_active_connection_authorize (active, connection,
|
||||
_add_and_activate_auth_done,
|
||||
nm_utils_user_data_pack (self, invocation, connection));
|
||||
_async_op_complete_ac_auth_cb,
|
||||
_async_op_data_new_ac_auth_add_and_activate (self,
|
||||
active,
|
||||
invocation,
|
||||
connection));
|
||||
|
||||
/* we passed the pointers on to the callback of authorize. */
|
||||
/* we passed the pointers on to _async_op_data_new_ac_auth_add_and_activate() */
|
||||
g_steal_pointer (&connection);
|
||||
g_steal_pointer (&active);
|
||||
return;
|
||||
|
|
@ -6551,6 +6694,7 @@ nm_manager_init (NMManager *self)
|
|||
c_list_init (&priv->link_cb_lst);
|
||||
c_list_init (&priv->devices_lst_head);
|
||||
c_list_init (&priv->active_connections_lst_head);
|
||||
c_list_init (&priv->async_op_lst_head);
|
||||
c_list_init (&priv->delete_volatile_connection_lst_head);
|
||||
|
||||
priv->platform = g_object_ref (NM_PLATFORM_GET);
|
||||
|
|
@ -6798,6 +6942,8 @@ dispose (GObject *object)
|
|||
CList *iter, *iter_safe;
|
||||
NMActiveConnection *ac, *ac_safe;
|
||||
|
||||
nm_assert (c_list_is_empty (&priv->async_op_lst_head));
|
||||
|
||||
g_signal_handlers_disconnect_by_func (priv->platform,
|
||||
G_CALLBACK (platform_link_cb),
|
||||
self);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue