core: separate active and applied connection
Clone the connection upon activation. This makes it safe for the user to modify the original connection while it is activated. This involves several changes: - NMActiveConnection gets @settings_connection and @applied_connection. To support add-and-activate, we constructing a NMActiveConnection with no connection set. Previously, we would set the "connection" field to a temporary NMConnection. Now NMManager piggybacks this temporary connection as object-data (TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE). - get rid of the functions nm_active_connection_get_connection_type() and nm_active_connection_get_connection_uuid(). From their names it is unclear whether this returns the settings or applied connection. The (few) callers should figure that out themselves. - rename nm_active_connection_get_id() to nm_active_connection_get_settings_connection_id(). This function is only used internally for logging. - dispatcher calls now get two connections as well. The applied-connection is used for the connection data, while the settings-connection is used for the connection path. - needs special handling for properties that apply immediately when changed (nm_device_reapply_settings_immediately()). Co-Authored-By: Thomas Haller <thaller@redhat.com> https://bugzilla.gnome.org/show_bug.cgi?id=724041
This commit is contained in:

committed by
Thomas Haller

parent
c9b3617c35
commit
06da353242
@@ -25,9 +25,11 @@
|
||||
#include "nm-dbus-interface.h"
|
||||
#include "nm-device.h"
|
||||
#include "nm-settings-connection.h"
|
||||
#include "nm-simple-connection.h"
|
||||
#include "nm-auth-utils.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-core-internal.h"
|
||||
|
||||
#include "nmdbus-active-connection.h"
|
||||
|
||||
@@ -39,7 +41,8 @@ G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_EXPORT
|
||||
NMActiveConnectionPrivate))
|
||||
|
||||
typedef struct {
|
||||
NMConnection *connection;
|
||||
NMSettingsConnection *settings_connection;
|
||||
NMConnection *applied_connection;
|
||||
char *specific_object;
|
||||
NMDevice *device;
|
||||
|
||||
@@ -82,7 +85,7 @@ enum {
|
||||
PROP_VPN,
|
||||
PROP_MASTER,
|
||||
|
||||
PROP_INT_CONNECTION,
|
||||
PROP_INT_SETTINGS_CONNECTION,
|
||||
PROP_INT_DEVICE,
|
||||
PROP_INT_SUBJECT,
|
||||
PROP_INT_MASTER,
|
||||
@@ -173,7 +176,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
|
||||
|
||||
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|
||||
|| old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
||||
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection),
|
||||
nm_settings_connection_update_timestamp (priv->settings_connection,
|
||||
(guint64) time (NULL), TRUE);
|
||||
}
|
||||
|
||||
@@ -206,53 +209,120 @@ nm_active_connection_set_state (NMActiveConnection *self,
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_active_connection_get_id (NMActiveConnection *self)
|
||||
nm_active_connection_get_settings_connection_id (NMActiveConnection *self)
|
||||
{
|
||||
NMSettingsConnection *con;
|
||||
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
||||
|
||||
return nm_connection_get_id (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection);
|
||||
con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
|
||||
return con
|
||||
? nm_connection_get_id (NM_CONNECTION (con))
|
||||
: NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_active_connection_get_uuid (NMActiveConnection *self)
|
||||
NMSettingsConnection *
|
||||
_nm_active_connection_get_settings_connection (NMActiveConnection *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
||||
|
||||
return nm_connection_get_uuid (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection);
|
||||
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
|
||||
}
|
||||
|
||||
NMSettingsConnection *
|
||||
nm_active_connection_get_settings_connection (NMActiveConnection *self)
|
||||
{
|
||||
NMSettingsConnection *con;
|
||||
|
||||
con = _nm_active_connection_get_settings_connection (self);
|
||||
|
||||
/* Only call this function on an active-connection that is already
|
||||
* fully set-up (i.e. that has a settings-connection). Other uses
|
||||
* indicate a bug. */
|
||||
g_return_val_if_fail (con, NULL);
|
||||
return con;
|
||||
}
|
||||
|
||||
NMConnection *
|
||||
nm_active_connection_get_connection (NMActiveConnection *self)
|
||||
nm_active_connection_get_applied_connection (NMActiveConnection *self)
|
||||
{
|
||||
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection;
|
||||
}
|
||||
NMConnection *con;
|
||||
|
||||
const char *
|
||||
nm_active_connection_get_connection_type (NMActiveConnection *self)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
||||
|
||||
if (priv->connection == NULL)
|
||||
return NULL;
|
||||
con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection;
|
||||
|
||||
return nm_connection_get_connection_type (priv->connection);
|
||||
/* Only call this function on an active-connection that is already
|
||||
* fully set-up (i.e. that has a settings-connection). Other uses
|
||||
* indicate a bug. */
|
||||
g_return_val_if_fail (con, NULL);
|
||||
return con;
|
||||
}
|
||||
|
||||
void
|
||||
nm_active_connection_set_connection (NMActiveConnection *self,
|
||||
NMConnection *connection)
|
||||
nm_active_connection_set_settings_connection (NMActiveConnection *self,
|
||||
NMSettingsConnection *connection)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
NMActiveConnectionPrivate *priv;
|
||||
|
||||
/* Can't change connection after the ActiveConnection is exported over D-Bus */
|
||||
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
||||
|
||||
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
|
||||
g_return_if_fail (!priv->settings_connection);
|
||||
g_return_if_fail (!priv->applied_connection);
|
||||
|
||||
/* Can't change connection after the ActiveConnection is exported over D-Bus.
|
||||
*
|
||||
* Later, we want to change the settings-connection of an activated connection.
|
||||
* When doing that, this changes the assumption that the settings-connection
|
||||
* never changes (once it's set). That has effects for NMVpnConnection and
|
||||
* NMActivationRequest.
|
||||
* For example, we'd have to cancel all pending seret requests. */
|
||||
g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));
|
||||
g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection));
|
||||
|
||||
if (priv->connection)
|
||||
g_object_unref (priv->connection);
|
||||
priv->connection = g_object_ref (connection);
|
||||
priv->settings_connection = g_object_ref (connection);
|
||||
priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection));
|
||||
nm_connection_clear_secrets (priv->applied_connection);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, NMSettingCompareFlags compare_flags)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
||||
|
||||
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
g_return_val_if_fail (priv->settings_connection, FALSE);
|
||||
|
||||
return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
|
||||
priv->applied_connection,
|
||||
compare_flags);
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
void
|
||||
nm_active_connection_clear_secrets (NMActiveConnection *self)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv;
|
||||
|
||||
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
||||
|
||||
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
|
||||
priv->applied_connection,
|
||||
NM_SETTING_COMPARE_FLAG_NONE))
|
||||
nm_connection_clear_secrets ((NMConnection *) priv->settings_connection);
|
||||
nm_connection_clear_secrets (priv->applied_connection);
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
const char *
|
||||
nm_active_connection_get_specific_object (NMActiveConnection *self)
|
||||
{
|
||||
@@ -572,7 +642,7 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m
|
||||
}
|
||||
|
||||
_LOGD ("master ActiveConnection is [%p] %s",
|
||||
master, nm_active_connection_get_id (master));
|
||||
master, nm_active_connection_get_settings_connection_id (master));
|
||||
|
||||
priv->master = g_object_ref (master);
|
||||
g_signal_connect (priv->master,
|
||||
@@ -667,6 +737,9 @@ done:
|
||||
/**
|
||||
* nm_active_connection_authorize:
|
||||
* @self: the #NMActiveConnection
|
||||
* @initial_connection: (allow-none): for add-and-activate, there
|
||||
* is no @settings_connection available when creating the active connection.
|
||||
* Instead pass an alternative connection.
|
||||
* @result_func: function to be called on success or error
|
||||
* @user_data1: pointer passed to @result_func
|
||||
* @user_data2: additional pointer passed to @result_func
|
||||
@@ -677,16 +750,29 @@ done:
|
||||
*/
|
||||
void
|
||||
nm_active_connection_authorize (NMActiveConnection *self,
|
||||
NMConnection *initial_connection,
|
||||
NMActiveConnectionAuthResultFunc result_func,
|
||||
gpointer user_data1,
|
||||
gpointer user_data2)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
const char *wifi_permission = NULL;
|
||||
NMConnection *con;
|
||||
|
||||
g_return_if_fail (result_func != NULL);
|
||||
g_return_if_fail (priv->chain == NULL);
|
||||
|
||||
if (initial_connection) {
|
||||
g_return_if_fail (NM_IS_CONNECTION (initial_connection));
|
||||
g_return_if_fail (!priv->settings_connection);
|
||||
g_return_if_fail (!priv->applied_connection);
|
||||
con = initial_connection;
|
||||
} else {
|
||||
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection));
|
||||
g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection));
|
||||
con = priv->applied_connection;
|
||||
}
|
||||
|
||||
priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self);
|
||||
g_assert (priv->chain);
|
||||
|
||||
@@ -694,7 +780,7 @@ nm_active_connection_authorize (NMActiveConnection *self,
|
||||
nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
|
||||
|
||||
/* Shared wifi connections require special permissions too */
|
||||
wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection);
|
||||
wifi_permission = nm_utils_get_shared_wifi_permission (con);
|
||||
if (wifi_permission) {
|
||||
priv->wifi_shared_permission = wifi_permission;
|
||||
nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE);
|
||||
@@ -717,24 +803,32 @@ static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
NMActiveConnection *self = (NMActiveConnection *) object;
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
|
||||
|
||||
G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
|
||||
g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject);
|
||||
|
||||
_LOGD ("constructed (%s)", G_OBJECT_TYPE_NAME (self));
|
||||
|
||||
g_return_if_fail (priv->subject);
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec)
|
||||
const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
|
||||
const char *tmp;
|
||||
NMSettingsConnection *con;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_INT_CONNECTION:
|
||||
g_warn_if_fail (priv->connection == NULL);
|
||||
priv->connection = g_value_dup_object (value);
|
||||
case PROP_INT_SETTINGS_CONNECTION:
|
||||
/* construct-only */
|
||||
con = g_value_get_object (value);
|
||||
if (con) {
|
||||
priv->settings_connection = g_object_ref (con);
|
||||
priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (con));
|
||||
nm_connection_clear_secrets (priv->applied_connection);
|
||||
}
|
||||
break;
|
||||
case PROP_INT_DEVICE:
|
||||
nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
|
||||
@@ -778,16 +872,16 @@ get_property (GObject *object, guint prop_id,
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CONNECTION:
|
||||
g_value_set_string (value, nm_connection_get_path (priv->connection));
|
||||
g_value_set_string (value, nm_connection_get_path (NM_CONNECTION (priv->settings_connection)));
|
||||
break;
|
||||
case PROP_ID:
|
||||
g_value_set_string (value, nm_connection_get_id (priv->connection));
|
||||
g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection)));
|
||||
break;
|
||||
case PROP_UUID:
|
||||
g_value_set_string (value, nm_connection_get_uuid (priv->connection));
|
||||
g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection)));
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
g_value_set_string (value, nm_connection_get_connection_type (priv->connection));
|
||||
g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection)));
|
||||
break;
|
||||
case PROP_SPECIFIC_OBJECT:
|
||||
g_value_set_string (value, priv->specific_object ? priv->specific_object : "/");
|
||||
@@ -883,7 +977,8 @@ dispose (GObject *object)
|
||||
g_free (priv->specific_object);
|
||||
priv->specific_object = NULL;
|
||||
|
||||
g_clear_object (&priv->connection);
|
||||
g_clear_object (&priv->settings_connection);
|
||||
g_clear_object (&priv->applied_connection);
|
||||
|
||||
_device_cleanup (self);
|
||||
|
||||
@@ -1024,10 +1119,10 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
|
||||
|
||||
/* Internal properties */
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_INT_CONNECTION,
|
||||
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_CONNECTION, "", "",
|
||||
NM_TYPE_CONNECTION,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
(object_class, PROP_INT_SETTINGS_CONNECTION,
|
||||
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "",
|
||||
NM_TYPE_SETTINGS_CONNECTION,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
|
Reference in New Issue
Block a user