Commit a3d8cb9b authored by Dan Williams's avatar Dan Williams

core: rework pending activation to be more flexible

In preparation for more granular permissions.
parent c4946a6d
...@@ -150,13 +150,17 @@ static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *u ...@@ -150,13 +150,17 @@ static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *u
#define ORIGDEV_TAG "originating-device" #define ORIGDEV_TAG "originating-device"
typedef struct { typedef struct {
DBusGMethodInvocation *context; NMManager *manager;
/* More than one caller may have requested this connection */
GSList *contexts;
NMConnectionScope scope; NMConnectionScope scope;
char *connection_path; char *connection_path;
char *specific_object_path; char *specific_object_path;
char *device_path; char *device_path;
guint timeout_id; guint timeout_id;
} PendingConnectionInfo; } PendingActivation;
typedef struct { typedef struct {
gboolean enabled; gboolean enabled;
...@@ -189,7 +193,7 @@ typedef struct { ...@@ -189,7 +193,7 @@ typedef struct {
GSList *secrets_calls; GSList *secrets_calls;
PendingConnectionInfo *pending_connection_info; GSList *pending_activations;
RadioState radio_states[RFKILL_TYPE_MAX]; RadioState radio_states[RFKILL_TYPE_MAX];
gboolean sleeping; gboolean sleeping;
...@@ -573,19 +577,73 @@ emit_removed (gpointer key, gpointer value, gpointer user_data) ...@@ -573,19 +577,73 @@ emit_removed (gpointer key, gpointer value, gpointer user_data)
} }
static void static void
pending_connection_info_destroy (PendingConnectionInfo *info) nm_manager_pending_activation_remove (NMManager *self,
PendingActivation *pending)
{ {
if (!info) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
return;
if (info->timeout_id) priv->pending_activations = g_slist_remove (priv->pending_activations, pending);
g_source_remove (info->timeout_id); }
g_free (info->connection_path); static PendingActivation *
g_free (info->specific_object_path); pending_activation_new (NMManager *manager,
g_free (info->device_path); const char *device_path,
NMConnectionScope scope,
const char *connection_path,
const char *specific_object_path)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
PendingActivation *pending;
pending = g_slice_new0 (PendingActivation);
pending->manager = manager;
pending->device_path = g_strdup (device_path);
pending->scope = scope;
pending->connection_path = g_strdup (connection_path);
pending->specific_object_path = g_strdup (specific_object_path);
g_slice_free (PendingConnectionInfo, info); priv->pending_activations = g_slist_append (priv->pending_activations, pending);
return pending;
}
static void
pending_activation_add_caller (PendingActivation *pending,
DBusGMethodInvocation *context)
{
/* Ensure no dupes */
if (!g_slist_find (pending->contexts, context))
pending->contexts = g_slist_prepend (pending->contexts, context);
}
static void
pending_activation_destroy (PendingActivation *pending,
GError *error,
const char *ac_path)
{
GSList *iter;
g_return_if_fail (pending != NULL);
if (pending->timeout_id)
g_source_remove (pending->timeout_id);
g_free (pending->connection_path);
g_free (pending->specific_object_path);
g_free (pending->device_path);
/* Send a reply (either error or the ActiveConnection path) if needed */
for (iter = pending->contexts; iter; iter = g_slist_next (iter)) {
DBusGMethodInvocation *context = iter->data;
if (error)
dbus_g_method_return_error (context, error);
else if (ac_path)
dbus_g_method_return (context, ac_path);
}
g_slist_free (pending->contexts);
memset (pending, 0, sizeof (PendingActivation));
g_slice_free (PendingActivation, pending);
} }
static GPtrArray * static GPtrArray *
...@@ -2253,25 +2311,21 @@ internal_activate_device (NMManager *manager, ...@@ -2253,25 +2311,21 @@ internal_activate_device (NMManager *manager,
static gboolean static gboolean
wait_for_connection_expired (gpointer data) wait_for_connection_expired (gpointer data)
{ {
NMManager *manager = NM_MANAGER (data); PendingActivation *pending = data;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
PendingConnectionInfo *info = priv->pending_connection_info;
GError *error = NULL; GError *error = NULL;
g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (pending != NULL, FALSE);
g_set_error (&error, nm_log_warn (LOGD_CORE, "connection %s (scope %d) failed to activate (timeout)",
NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, pending->scope, pending->connection_path);
"%s", "Connection was not provided by any settings service");
nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate (timeout): (%d) %s",
info->scope, info->connection_path, error->code, error->message);
dbus_g_method_return_error (info->context, error);
g_error_free (error);
info->timeout_id = 0; nm_manager_pending_activation_remove (pending->manager, pending);
pending_connection_info_destroy (priv->pending_connection_info);
priv->pending_connection_info = NULL;
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
"Connection was not provided by any settings service");
pending_activation_destroy (pending, error, NULL);
g_error_free (error);
return FALSE; return FALSE;
} }
...@@ -2382,45 +2436,55 @@ nm_manager_activate_connection (NMManager *manager, ...@@ -2382,45 +2436,55 @@ nm_manager_activate_connection (NMManager *manager,
return path; return path;
} }
static PendingActivation *
nm_manager_pending_activation_find (NMManager *self,
const char *path,
NMConnectionScope scope)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) {
PendingActivation *pending = iter->data;
if (!strcmp (pending->connection_path, path) && (pending->scope == scope))
return pending;
}
return NULL;
}
static void static void
connection_added_default_handler (NMManager *manager, connection_added_default_handler (NMManager *manager,
NMConnection *connection, NMConnection *connection,
NMConnectionScope scope) NMConnectionScope scope)
{ {
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); PendingActivation *pending;
PendingConnectionInfo *info = priv->pending_connection_info; const char *path = NULL;
const char *path;
GError *error = NULL; GError *error = NULL;
if (!info) pending = nm_manager_pending_activation_find (manager,
return; nm_connection_get_path (connection),
scope);
if (scope != info->scope) if (!pending)
return;
if (strcmp (info->connection_path, nm_connection_get_path (connection)))
return; return;
/* Will destroy below; can't be valid during the initial activation start */ /* Will destroy below; can't be valid during the initial activation start */
priv->pending_connection_info = NULL; nm_manager_pending_activation_remove (manager, pending);
path = nm_manager_activate_connection (manager, path = nm_manager_activate_connection (manager,
connection, connection,
info->specific_object_path, pending->specific_object_path,
info->device_path, pending->device_path,
TRUE, TRUE,
&error); &error);
if (path) { if (!path) {
dbus_g_method_return (info->context, path);
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
} else {
dbus_g_method_return_error (info->context, error);
nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s", nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s",
scope, info->connection_path, error->code, error->message); scope, pending->connection_path, error->code, error->message);
g_error_free (error); } else
} g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
pending_connection_info_destroy (info); pending_activation_destroy (pending, error, path);
g_clear_error (&error);
} }
static gboolean static gboolean
...@@ -2559,28 +2623,19 @@ impl_manager_activate_connection (NMManager *manager, ...@@ -2559,28 +2623,19 @@ impl_manager_activate_connection (NMManager *manager,
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS); g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
} }
} else { } else {
PendingConnectionInfo *info; PendingActivation *pending;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (priv->pending_connection_info) {
pending_connection_info_destroy (priv->pending_connection_info);
priv->pending_connection_info = NULL;
}
/* Don't have the connection quite yet, probably created by /* Don't have the connection quite yet, probably created by
* the client on-the-fly. Defer the activation until we have it * the client on-the-fly. Defer the activation until we have it.
*/ */
info = g_slice_new0 (PendingConnectionInfo); pending = nm_manager_pending_activation_find (manager, connection_path, scope);
info->context = context; if (!pending) {
info->device_path = g_strdup (device_path); pending = pending_activation_new (manager, device_path, scope, connection_path, real_sop);
info->scope = scope; /* Add a timeout waiting for the connection to be added */
info->connection_path = g_strdup (connection_path); pending->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, pending);
info->specific_object_path = g_strdup (real_sop); }
info->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, manager); pending_activation_add_caller (pending, context);
// FIXME: should probably be per-device, not global to the manager
NM_MANAGER_GET_PRIVATE (manager)->pending_connection_info = info;
} }
err: err:
...@@ -3373,6 +3428,7 @@ dispose (GObject *object) ...@@ -3373,6 +3428,7 @@ dispose (GObject *object)
{ {
NMManager *manager = NM_MANAGER (object); NMManager *manager = NM_MANAGER (object);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
if (priv->disposed) { if (priv->disposed) {
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object); G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
...@@ -3380,8 +3436,10 @@ dispose (GObject *object) ...@@ -3380,8 +3436,10 @@ dispose (GObject *object)
} }
priv->disposed = TRUE; priv->disposed = TRUE;
pending_connection_info_destroy (priv->pending_connection_info); for (iter = priv->pending_activations; iter; iter = g_slist_next (iter))
priv->pending_connection_info = NULL; pending_activation_destroy ((PendingActivation *) iter->data, NULL, NULL);
g_slist_free (priv->pending_activations);
priv->pending_activations = NULL;
g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL); g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL);
g_slist_free (priv->auth_chains); g_slist_free (priv->auth_chains);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment