summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2014-10-19 09:27:53 -0400
committerDan Winship <danw@gnome.org>2014-10-19 09:27:53 -0400
commit7b1aae969d2b1bdc6a13bbc464ee13ad30cf66f9 (patch)
tree760061cb20094e9f86befa784fc74b406be42283
parent88efa1c4376b7fc55bf2ba9bf74ddbecb4ed5075 (diff)
parentbe8060f42fd3b3c15755e97f0c35886596a4732c (diff)
downloadNetworkManager-7b1aae969d2b1bdc6a13bbc464ee13ad30cf66f9.tar.gz
libnm, core: fix problems with device activation (bgo 737993)
-rw-r--r--libnm/nm-active-connection.c5
-rw-r--r--libnm/nm-device-bond.c4
-rw-r--r--libnm/nm-device-bridge.c4
-rw-r--r--libnm/nm-device-team.c4
-rw-r--r--libnm/nm-device-wifi.c4
-rw-r--r--libnm/nm-manager.c189
-rw-r--r--libnm/nm-manager.h2
-rw-r--r--libnm/nm-object.c28
-rw-r--r--libnm/nm-remote-settings.c1
-rw-r--r--libnm/tests/common.c67
-rw-r--r--libnm/tests/common.h6
-rw-r--r--libnm/tests/test-nm-client.c516
-rw-r--r--libnm/tests/test-secret-agent.c55
-rw-r--r--src/nm-active-connection.c11
-rwxr-xr-xtools/test-networkmanager-service.py144
15 files changed, 747 insertions, 293 deletions
diff --git a/libnm/nm-active-connection.c b/libnm/nm-active-connection.c
index ae36bf78ee..a64877be23 100644
--- a/libnm/nm-active-connection.c
+++ b/libnm/nm-active-connection.c
@@ -362,8 +362,11 @@ nm_active_connection_get_master (NMActiveConnection *connection)
}
static void
-nm_active_connection_init (NMActiveConnection *ap)
+nm_active_connection_init (NMActiveConnection *connection)
{
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
+
+ priv->devices = g_ptr_array_new ();
}
static void
diff --git a/libnm/nm-device-bond.c b/libnm/nm-device-bond.c
index b22d8b30fb..9656de631e 100644
--- a/libnm/nm-device-bond.c
+++ b/libnm/nm-device-bond.c
@@ -173,7 +173,11 @@ get_hw_address (NMDevice *device)
static void
nm_device_bond_init (NMDeviceBond *device)
{
+ NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
+
_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_BOND);
+
+ priv->slaves = g_ptr_array_new ();
}
static void
diff --git a/libnm/nm-device-bridge.c b/libnm/nm-device-bridge.c
index b4ee25b811..63d9040d49 100644
--- a/libnm/nm-device-bridge.c
+++ b/libnm/nm-device-bridge.c
@@ -173,7 +173,11 @@ get_hw_address (NMDevice *device)
static void
nm_device_bridge_init (NMDeviceBridge *device)
{
+ NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
+
_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_BRIDGE);
+
+ priv->slaves = g_ptr_array_new ();
}
static void
diff --git a/libnm/nm-device-team.c b/libnm/nm-device-team.c
index 06db4cf84a..ce7a82f9cd 100644
--- a/libnm/nm-device-team.c
+++ b/libnm/nm-device-team.c
@@ -173,7 +173,11 @@ get_setting_type (NMDevice *device)
static void
nm_device_team_init (NMDeviceTeam *device)
{
+ NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
+
_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_TEAM);
+
+ priv->slaves = g_ptr_array_new ();
}
static void
diff --git a/libnm/nm-device-wifi.c b/libnm/nm-device-wifi.c
index 1d0cd39aa7..f804875719 100644
--- a/libnm/nm-device-wifi.c
+++ b/libnm/nm-device-wifi.c
@@ -565,12 +565,16 @@ get_hw_address (NMDevice *device)
static void
nm_device_wifi_init (NMDeviceWifi *device)
{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
+
_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_WIFI);
g_signal_connect (device,
"notify::" NM_DEVICE_STATE,
G_CALLBACK (state_changed_cb),
NULL);
+
+ priv->aps = g_ptr_array_new ();
}
static void
diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c
index 7bfab68a86..4088548344 100644
--- a/libnm/nm-manager.c
+++ b/libnm/nm-manager.c
@@ -105,6 +105,8 @@ enum {
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
+ ACTIVE_CONNECTION_ADDED,
+ ACTIVE_CONNECTION_REMOVED,
PERMISSION_CHANGED,
LAST_SIGNAL
@@ -127,6 +129,8 @@ nm_manager_init (NMManager *manager)
priv->connectivity = NM_CONNECTIVITY_UNKNOWN;
priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
+ priv->devices = g_ptr_array_new ();
+ priv->active_connections = g_ptr_array_new ();
}
static void
@@ -150,8 +154,6 @@ wireless_enabled_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
}
static void manager_recheck_permissions (NMDBusManager *proxy, gpointer user_data);
-static void active_connections_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data);
-static void object_creation_failed_cb (GObject *object, GError *error, char *failed_path);
static void
init_dbus (NMObject *object)
@@ -168,7 +170,7 @@ init_dbus (NMObject *object)
{ NM_MANAGER_WWAN_HARDWARE_ENABLED, &priv->wwan_hw_enabled },
{ NM_MANAGER_WIMAX_ENABLED, &priv->wimax_enabled },
{ NM_MANAGER_WIMAX_HARDWARE_ENABLED, &priv->wimax_hw_enabled },
- { NM_MANAGER_ACTIVE_CONNECTIONS, &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION },
+ { NM_MANAGER_ACTIVE_CONNECTIONS, &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION, "active-connection" },
{ NM_MANAGER_CONNECTIVITY, &priv->connectivity },
{ NM_MANAGER_PRIMARY_CONNECTION, &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
{ NM_MANAGER_ACTIVATING_CONNECTION, &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
@@ -647,9 +649,6 @@ nm_manager_get_device_by_path (NMManager *manager, const char *object_path)
g_return_val_if_fail (object_path, NULL);
devices = nm_manager_get_devices (manager);
- if (!devices)
- return NULL;
-
for (i = 0; i < devices->len; i++) {
NMDevice *candidate = g_ptr_array_index (devices, i);
if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), object_path)) {
@@ -672,9 +671,6 @@ nm_manager_get_device_by_iface (NMManager *manager, const char *iface)
g_return_val_if_fail (iface, NULL);
devices = nm_manager_get_devices (manager);
- if (!devices)
- return NULL;
-
for (i = 0; i < devices->len; i++) {
NMDevice *candidate = g_ptr_array_index (devices, i);
if (!strcmp (nm_device_get_iface (candidate), iface)) {
@@ -749,56 +745,56 @@ activate_info_complete (ActivateInfo *info,
g_slice_free (ActivateInfo, info);
}
-static void
-recheck_pending_activations (NMManager *self, const char *failed_path, GError *error)
+static NMActiveConnection *
+find_active_connection_by_path (NMManager *self, const char *ac_path)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GSList *iter, *next;
- const GPtrArray *active_connections;
- gboolean found_in_active = FALSE;
- gboolean found_in_pending = FALSE;
- ActivateInfo *ainfo = NULL;
int i;
- active_connections = nm_manager_get_active_connections (self);
+ for (i = 0; i < priv->active_connections->len; i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (priv->active_connections, i);
+ const char *candidate_path = nm_object_get_path (NM_OBJECT (candidate));
+
+ if (g_strcmp0 (ac_path, candidate_path) == 0)
+ return candidate;
+ }
+
+ return NULL;
+}
- /* For each pending activation, look for a active connection that has
- * the pending activation's object path, and call pending connection's
- * callback.
- * If the connection to activate doesn't make it to active_connections,
- * due to an error, we have to call the callback for failed_path.
+static void
+recheck_pending_activations (NMManager *self)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GSList *iter, *next;
+ NMActiveConnection *candidate;
+ const GPtrArray *devices;
+ NMDevice *device;
+
+ /* For each pending activation, look for an active connection that has the
+ * pending activation's object path, where the active connection and its
+ * device have both updated their properties to point to each other, and
+ * call the pending connection's callback.
*/
for (iter = priv->pending_activations; iter; iter = next) {
ActivateInfo *info = iter->data;
next = g_slist_next (iter);
- if (!found_in_pending && failed_path && g_strcmp0 (failed_path, info->active_path) == 0) {
- found_in_pending = TRUE;
- ainfo = info;
- }
-
- for (i = 0; i < active_connections->len; i++) {
- NMActiveConnection *active = g_ptr_array_index (active_connections, i);
- const char *active_path = nm_object_get_path (NM_OBJECT (active));
+ candidate = find_active_connection_by_path (self, info->active_path);
+ if (!candidate)
+ continue;
- if (!found_in_active && failed_path && g_strcmp0 (failed_path, active_path) == 0)
- found_in_active = TRUE;
+ /* Check that the AC and device are both ready */
+ devices = nm_active_connection_get_devices (candidate);
+ if (devices->len == 0)
+ continue;
+ device = devices->pdata[0];
+ if (nm_device_get_active_connection (device) != candidate)
+ continue;
- if (g_strcmp0 (info->active_path, active_path) == 0) {
- /* Call the pending activation's callback and it all up */
- activate_info_complete (info, active, NULL);
- break;
- }
- }
- }
-
- if (!found_in_active && found_in_pending) {
- /* A newly activated connection failed due to some immediate error
- * and disappeared from active connection list. Make sure the
- * callback gets called.
- */
- activate_info_complete (ainfo, NULL, error);
+ activate_info_complete (info, candidate, NULL);
+ break;
}
}
@@ -832,7 +828,7 @@ activate_cb (GObject *object,
G_CALLBACK (activation_cancelled), info);
}
- recheck_pending_activations (info->manager, NULL, NULL);
+ recheck_pending_activations (info->manager);
} else {
activate_info_complete (info, NULL, error);
g_clear_error (&error);
@@ -907,7 +903,7 @@ add_activate_cb (GObject *object,
G_CALLBACK (activation_cancelled), info);
}
- recheck_pending_activations (info->manager, NULL, NULL);
+ recheck_pending_activations (info->manager);
} else {
activate_info_complete (info, NULL, error);
g_clear_error (&error);
@@ -971,16 +967,71 @@ nm_manager_add_and_activate_connection_finish (NMManager *manager,
}
static void
-active_connections_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+device_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ NMManager *self = user_data;
+
+ recheck_pending_activations (self);
+}
+
+static void
+device_added (NMManager *self, NMDevice *device)
+{
+ g_signal_connect (device, "notify::" NM_DEVICE_ACTIVE_CONNECTION,
+ G_CALLBACK (device_ac_changed), self);
+}
+
+static void
+device_removed (NMManager *self, NMDevice *device)
+{
+ g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_ac_changed), self);
+}
+
+static void
+ac_devices_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ NMManager *self = user_data;
+
+ recheck_pending_activations (self);
+}
+
+static void
+active_connection_added (NMManager *self, NMActiveConnection *ac)
+{
+ g_signal_connect (ac, "notify::" NM_ACTIVE_CONNECTION_DEVICES,
+ G_CALLBACK (ac_devices_changed), self);
+ recheck_pending_activations (self);
+}
+
+static void
+active_connection_removed (NMManager *self, NMActiveConnection *ac)
{
- recheck_pending_activations (NM_MANAGER (object), NULL, NULL);
+ g_signal_handlers_disconnect_by_func (ac, G_CALLBACK (ac_devices_changed), self);
}
static void
object_creation_failed_cb (GObject *object, GError *error, char *failed_path)
{
- if (error)
- recheck_pending_activations (NM_MANAGER (object), failed_path, error);
+ NMManager *self = NM_MANAGER (object);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GSList *iter;
+
+ g_return_if_fail (error != NULL);
+ g_return_if_fail (find_active_connection_by_path (self, failed_path) == NULL);
+
+ /* A newly activated connection failed due to some immediate error
+ * and disappeared from active connection list. Make sure the
+ * callback gets called.
+ */
+
+ for (iter = priv->pending_activations; iter; iter = iter->next) {
+ ActivateInfo *info = iter->data;
+
+ if (g_strcmp0 (failed_path, info->active_path) == 0) {
+ activate_info_complete (info, NULL, error);
+ return;
+ }
+ }
}
gboolean
@@ -1097,19 +1148,21 @@ free_active_connections (NMManager *manager, gboolean in_dispose)
return;
active_connections = priv->active_connections;
- priv->active_connections = NULL;
+ if (in_dispose)
+ priv->active_connections = NULL;
+ else
+ priv->active_connections = g_ptr_array_new ();
for (i = 0; i < active_connections->len; i++) {
active_connection = active_connections->pdata[i];
+ g_signal_emit (manager, signals[ACTIVE_CONNECTION_REMOVED], 0, active_connection);
/* Break circular refs */
g_object_run_dispose (G_OBJECT (active_connection));
}
g_ptr_array_unref (active_connections);
- if (!in_dispose) {
- priv->active_connections = g_ptr_array_new ();
+ if (!in_dispose)
g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
- }
}
static void
@@ -1176,9 +1229,6 @@ constructed (GObject *object)
g_signal_connect (object, "notify::" NM_MANAGER_WIRELESS_ENABLED,
G_CALLBACK (wireless_enabled_cb), NULL);
- g_signal_connect (object, "notify::" NM_MANAGER_ACTIVE_CONNECTIONS,
- G_CALLBACK (active_connections_changed_cb), NULL);
-
g_signal_connect (object, "object-creation-failed",
G_CALLBACK (object_creation_failed_cb), NULL);
}
@@ -1455,6 +1505,11 @@ nm_manager_class_init (NMManagerClass *manager_class)
nm_object_class->init_dbus = init_dbus;
+ manager_class->device_added = device_added;
+ manager_class->device_removed = device_removed;
+ manager_class->active_connection_added = active_connection_added;
+ manager_class->active_connection_removed = active_connection_removed;
+
/* properties */
g_object_class_install_property
@@ -1574,6 +1629,22 @@ nm_manager_class_init (NMManagerClass *manager_class)
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
+ signals[ACTIVE_CONNECTION_ADDED] =
+ g_signal_new ("active-connection-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMManagerClass, active_connection_added),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+ signals[ACTIVE_CONNECTION_REMOVED] =
+ g_signal_new ("active-connection-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMManagerClass, active_connection_removed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
signals[PERMISSION_CHANGED] =
g_signal_new ("permission-changed",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/libnm/nm-manager.h b/libnm/nm-manager.h
index 430b038e03..ca9f7dd60b 100644
--- a/libnm/nm-manager.h
+++ b/libnm/nm-manager.h
@@ -61,6 +61,8 @@ typedef struct {
/* Signals */
void (*device_added) (NMManager *manager, NMDevice *device);
void (*device_removed) (NMManager *manager, NMDevice *device);
+ void (*active_connection_added) (NMManager *manager, NMActiveConnection *ac);
+ void (*active_connection_removed) (NMManager *manager, NMActiveConnection *ac);
void (*permission_changed) (NMManager *manager,
NMClientPermission permission,
NMClientPermissionResult result);
diff --git a/libnm/nm-object.c b/libnm/nm-object.c
index 73dbade4ab..0e82861fc4 100644
--- a/libnm/nm-object.c
+++ b/libnm/nm-object.c
@@ -736,21 +736,7 @@ create_async_inited (GObject *object, GAsyncResult *result, gpointer user_data)
NMObjectTypeAsyncData *async_data = user_data;
GError *error = NULL;
- if (g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error)) {
- NMObject *cached;
-
- /* Unlike in the sync case, in the async case we can't cache the object
- * until it is completely initialized. But that means someone else might
- * have been creating it at the same time, and they might have finished
- * before us.
- */
- cached = _nm_object_cache_get (nm_object_get_path (NM_OBJECT (object)));
- if (cached) {
- g_object_unref (object);
- object = G_OBJECT (cached);
- } else
- _nm_object_cache_add (NM_OBJECT (object));
- } else {
+ if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error)) {
dbgmsg ("Could not create object for %s: %s",
nm_object_get_path (NM_OBJECT (object)),
error->message);
@@ -766,6 +752,17 @@ create_async_got_type (NMObjectTypeAsyncData *async_data, GType type)
{
GObject *object;
+ /* Ensure we don't have the object already; we may get multiple type
+ * requests for the same object if there are multiple properties on
+ * other objects that refer to the object at this path. One of those
+ * other requests may have already completed.
+ */
+ object = (GObject *) _nm_object_cache_get (async_data->path);
+ if (object) {
+ create_async_complete (object, async_data);
+ return;
+ }
+
if (type == G_TYPE_INVALID) {
/* Don't know how to create this object */
create_async_complete (NULL, async_data);
@@ -776,6 +773,7 @@ create_async_got_type (NMObjectTypeAsyncData *async_data, GType type)
NM_OBJECT_PATH, async_data->path,
NM_OBJECT_DBUS_CONNECTION, async_data->connection,
NULL);
+ _nm_object_cache_add (NM_OBJECT (object));
g_async_initable_init_async (G_ASYNC_INITABLE (object), G_PRIORITY_DEFAULT,
NULL, create_async_inited, async_data);
}
diff --git a/libnm/nm-remote-settings.c b/libnm/nm-remote-settings.c
index 2c2dd597e6..e072e9ac1c 100644
--- a/libnm/nm-remote-settings.c
+++ b/libnm/nm-remote-settings.c
@@ -652,6 +652,7 @@ nm_remote_settings_init (NMRemoteSettings *self)
{
NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ priv->all_connections = g_ptr_array_new ();
priv->visible_connections = g_ptr_array_new ();
}
diff --git a/libnm/tests/common.c b/libnm/tests/common.c
index 109ab04322..79308329a0 100644
--- a/libnm/tests/common.c
+++ b/libnm/tests/common.c
@@ -116,3 +116,70 @@ nm_test_service_cleanup (NMTestServiceInfo *info)
memset (info, 0, sizeof (*info));
g_free (info);
}
+
+typedef struct {
+ GMainLoop *loop;
+ const char *ifname;
+ char *path;
+ NMDevice *device;
+} AddDeviceInfo;
+
+static void
+device_added_cb (NMClient *client,
+ NMDevice *device,
+ gpointer user_data)
+{
+ AddDeviceInfo *info = user_data;
+
+ g_assert (device);
+ g_assert_cmpstr (nm_object_get_path (NM_OBJECT (device)), ==, info->path);
+ g_assert_cmpstr (nm_device_get_iface (device), ==, info->ifname);
+
+ info->device = device;
+ g_main_loop_quit (info->loop);
+}
+
+static gboolean
+timeout (gpointer user_data)
+{
+ g_assert_not_reached ();
+ return G_SOURCE_REMOVE;
+}
+
+NMDevice *
+nm_test_service_add_device (NMTestServiceInfo *sinfo, NMClient *client,
+ const char *method, const char *ifname)
+{
+ AddDeviceInfo info;
+ GError *error = NULL;
+ GVariant *ret;
+ guint timeout_id;
+
+ ret = g_dbus_proxy_call_sync (sinfo->proxy,
+ method,
+ g_variant_new ("(s)", ifname),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 3000,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+ g_variant_get (ret, "(o)", &info.path);
+ g_variant_unref (ret);
+
+ /* Wait for libnm to find the device */
+ info.ifname = ifname;
+ info.loop = g_main_loop_new (NULL, FALSE);
+ g_signal_connect (client, "device-added",
+ G_CALLBACK (device_added_cb), &info);
+ timeout_id = g_timeout_add_seconds (5, timeout, NULL);
+ g_main_loop_run (info.loop);
+
+ g_source_remove (timeout_id);
+ g_signal_handlers_disconnect_by_func (client, device_added_cb, &info);
+ g_free (info.path);
+ g_main_loop_unref (info.loop);
+
+ return info.device;
+}
diff --git a/libnm/tests/common.h b/libnm/tests/common.h
index 7c49d2532b..aa15167b85 100644
--- a/libnm/tests/common.h
+++ b/libnm/tests/common.h
@@ -19,6 +19,7 @@
*/
#include <gio/gio.h>
+#include <NetworkManager.h>
typedef struct {
GDBusConnection *bus;
@@ -29,3 +30,8 @@ typedef struct {
NMTestServiceInfo *nm_test_service_init (void);
void nm_test_service_cleanup (NMTestServiceInfo *info);
+
+NMDevice *nm_test_service_add_device (NMTestServiceInfo *info,
+ NMClient *client,
+ const char *method,
+ const char *ifname);
diff --git a/libnm/tests/test-nm-client.c b/libnm/tests/test-nm-client.c
index e666551f49..26ffbec4ac 100644
--- a/libnm/tests/test-nm-client.c
+++ b/libnm/tests/test-nm-client.c
@@ -28,6 +28,8 @@
#include "common.h"
+#include "nm-test-utils.h"
+
static GMainLoop *loop = NULL;
static NMTestServiceInfo *sinfo;
@@ -40,65 +42,14 @@ loop_quit (gpointer user_data)
return G_SOURCE_REMOVE;
}
-static gboolean
-add_device (const char *method, const char *ifname, char **out_path)
-{
- GError *error = NULL;
- GVariant *ret;
-
- ret = g_dbus_proxy_call_sync (sinfo->proxy,
- method,
- g_variant_new ("(s)", ifname),
- G_DBUS_CALL_FLAGS_NO_AUTO_START,
- 3000,
- NULL,
- &error);
- g_assert_no_error (error);
- g_assert (ret);
- g_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
- if (out_path)
- g_variant_get (ret, "(o)", out_path);
- g_variant_unref (ret);
- return TRUE;
-}
-
/*******************************************************************/
-typedef struct {
- GMainLoop *loop;
- gboolean signaled;
- gboolean notified;
- guint quit_count;
- guint quit_id;
-} DeviceAddedInfo;
-
-static void
-device_add_check_quit (DeviceAddedInfo *info)
-{
- info->quit_count--;
- if (info->quit_count == 0) {
- g_source_remove (info->quit_id);
- info->quit_id = 0;
- g_main_loop_quit (info->loop);
- }
-}
-
-static void
-device_added_cb (NMClient *c,
- NMDevice *device,
- DeviceAddedInfo *info)
-{
- g_assert (device);
- g_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
- info->signaled = TRUE;
- device_add_check_quit (info);
-}
-
static void
devices_notify_cb (NMClient *c,
GParamSpec *pspec,
- DeviceAddedInfo *info)
+ gpointer user_data)
{
+ gboolean *notified = user_data;
const GPtrArray *devices;
NMDevice *device;
@@ -110,9 +61,7 @@ devices_notify_cb (NMClient *c,
g_assert (device);
g_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
- info->notified = TRUE;
-
- device_add_check_quit (info);
+ *notified = TRUE;
}
static void
@@ -121,7 +70,7 @@ test_device_added (void)
NMClient *client;
const GPtrArray *devices;
NMDevice *device;
- DeviceAddedInfo info = { loop, FALSE, FALSE, 0, 0 };
+ gboolean notified = FALSE;
GError *error = NULL;
sinfo = nm_test_service_init ();
@@ -131,30 +80,18 @@ test_device_added (void)
devices = nm_client_get_devices (client);
g_assert (devices->len == 0);
- /* Tell the test service to add a new device */
- add_device ("AddWiredDevice", "eth0", NULL);
-
- g_signal_connect (client,
- "device-added",
- (GCallback) device_added_cb,
- &info);
- info.quit_count++;
-
g_signal_connect (client,
"notify::devices",
(GCallback) devices_notify_cb,
- &info);
- info.quit_count++;
+ &notified);
- /* Wait for libnm to find the device */
- info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
- g_main_loop_run (loop);
+ /* Tell the test service to add a new device */
+ nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth0");
- g_assert (info.signaled);
- g_assert (info.notified);
+ while (!notified)
+ g_main_context_iteration (NULL, TRUE);
- g_signal_handlers_disconnect_by_func (client, device_added_cb, &info);
- g_signal_handlers_disconnect_by_func (client, devices_notify_cb, &info);
+ g_signal_handlers_disconnect_by_func (client, devices_notify_cb, &notified);
devices = nm_client_get_devices (client);
g_assert (devices);
@@ -194,16 +131,6 @@ wifi_check_quit (WifiApInfo *info)
}
static void
-wifi_device_added_cb (NMClient *c,
- NMDevice *device,
- WifiApInfo *info)
-{
- g_assert_cmpstr (nm_device_get_iface (device), ==, "wlan0");
- info->found = TRUE;
- wifi_check_quit (info);
-}
-
-static void
got_ap_path (WifiApInfo *info, const char *path)
{
if (info->ap_path)
@@ -288,26 +215,11 @@ test_wifi_ap_added_removed (void)
/*************************************/
/* Add the wifi device */
- add_device ("AddWifiDevice", "wlan0", NULL);
-
- g_signal_connect (client,
- "device-added",
- (GCallback) wifi_device_added_cb,
- &info);
- info.quit_count = 1;
-
- /* Wait for libnm to find the device */
- info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
- g_main_loop_run (loop);
-
- g_assert (info.found);
- g_signal_handlers_disconnect_by_func (client, wifi_device_added_cb, &info);
-
- wifi = (NMDeviceWifi *) nm_client_get_device_by_iface (client, "wlan0");
+ wifi = (NMDeviceWifi *) nm_test_service_add_device (sinfo, client, "AddWifiDevice", "wlan0");
g_assert (NM_IS_DEVICE_WIFI (wifi));
/*************************************/
- /* Add the wifi device */
+ /* Add the wifi AP */
info.signaled = FALSE;
info.notified = FALSE;
info.quit_id = 0;
@@ -418,16 +330,6 @@ wimax_check_quit (WimaxNspInfo *info)
}
static void
-wimax_device_added_cb (NMClient *c,
- NMDevice *device,
- WimaxNspInfo *info)
-{
- g_assert_cmpstr (nm_device_get_iface (device), ==, "wmx0");
- info->found = TRUE;
- wimax_check_quit (info);
-}
-
-static void
got_nsp_path (WimaxNspInfo *info, const char *path)
{
if (info->nsp_path)
@@ -512,22 +414,7 @@ test_wimax_nsp_added_removed (void)
/*************************************/
/* Add the wimax device */
- add_device ("AddWimaxDevice", "wmx0", NULL);
-
- g_signal_connect (client,
- "device-added",
- (GCallback) wimax_device_added_cb,
- &info);
- info.quit_count = 1;
-
- /* Wait for libnm to find the device */
- info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
- g_main_loop_run (loop);
-
- g_assert (info.found);
- g_signal_handlers_disconnect_by_func (client, wimax_device_added_cb, &info);
-
- wimax = (NMDeviceWimax *) nm_client_get_device_by_iface (client, "wmx0");
+ wimax = (NMDeviceWimax *) nm_test_service_add_device (sinfo, client, "AddWimaxDevice", "wmx0");
g_assert (NM_IS_DEVICE_WIMAX (wimax));
/*************************************/
@@ -638,14 +525,6 @@ da_check_quit (DaInfo *info)
}
static void
-da_device_added_cb (NMClient *c,
- NMDevice *device,
- DaInfo *info)
-{
- da_check_quit (info);
-}
-
-static void
da_device_removed_cb (NMClient *c,
NMDevice *device,
DaInfo *info)
@@ -700,8 +579,7 @@ test_devices_array (void)
{
NMClient *client = NULL;
DaInfo info = { loop };
- char *paths[3] = { NULL, NULL, NULL };
- NMDevice *device;
+ NMDevice *wlan0, *eth0, *eth1, *device;
const GPtrArray *devices;
GError *error = NULL;
GVariant *ret;
@@ -715,22 +593,9 @@ test_devices_array (void)
/*************************************/
/* Add some devices */
- add_device ("AddWifiDevice", "wlan0", &paths[0]);
- add_device ("AddWiredDevice", "eth0", &paths[1]);
- add_device ("AddWiredDevice", "eth1", &paths[2]);
- info.quit_count = 3;
-
- g_signal_connect (client,
- "device-added",
- (GCallback) da_device_added_cb,
- &info);
-
- /* Wait for libnm to find the device */
- info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
- g_main_loop_run (loop);
-
- g_assert_cmpint (info.quit_count, ==, 0);
- g_signal_handlers_disconnect_by_func (client, da_device_added_cb, &info);
+ wlan0 = nm_test_service_add_device (sinfo, client,"AddWifiDevice", "wlan0");
+ eth0 = nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth0");
+ eth1 = nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth1");
/* Ensure the devices now exist */
devices = nm_client_get_devices (client);
@@ -739,18 +604,21 @@ test_devices_array (void)
device = nm_client_get_device_by_iface (client, "wlan0");
g_assert (NM_IS_DEVICE_WIFI (device));
+ g_assert (device == wlan0);
device = nm_client_get_device_by_iface (client, "eth0");
g_assert (NM_IS_DEVICE_ETHERNET (device));
+ g_assert (device == eth0);
device = nm_client_get_device_by_iface (client, "eth1");
g_assert (NM_IS_DEVICE_ETHERNET (device));
+ g_assert (device == eth1);
/********************************/
/* Now remove the device in the middle */
ret = g_dbus_proxy_call_sync (sinfo->proxy,
"RemoveDevice",
- g_variant_new ("(o)", paths[1]),
+ g_variant_new ("(o)", nm_object_get_path (NM_OBJECT (eth0))),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
3000,
NULL,
@@ -770,7 +638,7 @@ test_devices_array (void)
&info);
info.quit_count = 2;
- /* Wait for libnm to find the device */
+ /* Wait for libnm to notice the changes */
info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
g_main_loop_run (loop);
@@ -785,13 +653,11 @@ test_devices_array (void)
device = nm_client_get_device_by_iface (client, "wlan0");
g_assert (NM_IS_DEVICE_WIFI (device));
+ g_assert (device == wlan0);
device = nm_client_get_device_by_iface (client, "eth1");
g_assert (NM_IS_DEVICE_ETHERNET (device));
-
- g_free (paths[0]);
- g_free (paths[1]);
- g_free (paths[2]);
+ g_assert (device == eth1);
g_object_unref (client);
g_clear_pointer (&sinfo, nm_test_service_cleanup);
@@ -866,8 +732,333 @@ test_client_nm_running (void)
g_object_unref (client2);
}
+typedef struct {
+ GMainLoop *loop;
+ NMActiveConnection *ac;
+
+ int remaining;
+} TestACInfo;
+
+static void
+assert_ac_and_device (NMClient *client)
+{
+ const GPtrArray *devices, *acs, *ac_devices;
+ NMDevice *device, *ac_device;
+ NMActiveConnection *ac, *device_ac;
+
+ acs = nm_client_get_active_connections (client);
+ g_assert (acs != NULL);
+ g_assert_cmpint (acs->len, ==, 1);
+ devices = nm_client_get_devices (client);
+ g_assert (devices != NULL);
+ g_assert_cmpint (devices->len, >=, 1);
+
+ ac = acs->pdata[0];
+ ac_devices = nm_active_connection_get_devices (ac);
+ g_assert (ac_devices != NULL);
+ g_assert_cmpint (ac_devices->len, ==, 1);
+ ac_device = ac_devices->pdata[0];
+ g_assert (ac_device != NULL);
+
+ device = devices->pdata[0];
+ if (device != ac_device && devices->len > 1)
+ device = devices->pdata[1];
+ device_ac = nm_device_get_active_connection (device);
+ g_assert (device_ac != NULL);
+
+ g_assert_cmpstr (nm_object_get_path (NM_OBJECT (device)), ==, nm_object_get_path (NM_OBJECT (ac_device)));
+ g_assert (device == ac_device);
+ g_assert_cmpstr (nm_object_get_path (NM_OBJECT (ac)), ==, nm_object_get_path (NM_OBJECT (device_ac)));
+ g_assert (ac == device_ac);
+}
+
+static void
+add_and_activate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ TestACInfo *info = user_data;
+ GError *error = NULL;
+
+ info->ac = nm_client_add_and_activate_connection_finish (client, result, &error);
+ g_assert_no_error (error);
+ g_assert (info->ac != NULL);
+
+ assert_ac_and_device (client);
+
+ info->remaining--;
+ if (!info->remaining)
+ g_main_loop_quit (info->loop);
+}
+
+static void
+client_acs_changed_cb (GObject *client,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ TestACInfo *info = user_data;
+ const GPtrArray *acs;
+
+ acs = nm_client_get_active_connections (NM_CLIENT (client));
+ g_assert (acs != NULL);
+ g_assert_cmpint (acs->len, ==, 1);
+
+ info->remaining--;
+ if (!info->remaining)
+ g_main_loop_quit (info->loop);
+}
+
+static void
+device_ac_changed_cb (GObject *device,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ TestACInfo *info = user_data;
+
+ g_assert (nm_device_get_active_connection (NM_DEVICE (device)) != NULL);
+
+ info->remaining--;
+ if (!info->remaining)
+ g_main_loop_quit (info->loop);
+}
+
+static void
+test_active_connections (void)
+{
+ NMClient *client;
+ NMDevice *device;
+ NMConnection *conn;
+ TestACInfo info = { loop, NULL, 0 };
+ GError *error = NULL;
+
+ sinfo = nm_test_service_init ();
+ client = nm_client_new (NULL, &error);
+ g_assert_no_error (error);
+
+ /* Tell the test service to add a new device */
+ device = nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth0");
+
+ conn = nmtst_create_minimal_connection ("test-ac", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+ nm_client_add_and_activate_connection_async (client, conn, device, NULL,
+ NULL, add_and_activate_cb, &info);
+ g_object_unref (conn);
+
+ g_signal_connect (client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
+ G_CALLBACK (client_acs_changed_cb), &info);
+ g_signal_connect (device, "notify::" NM_DEVICE_ACTIVE_CONNECTION,
+ G_CALLBACK (device_ac_changed_cb), &info);
+
+ /* Two signals plus activate_cb */
+ info.remaining = 3;
+ g_main_loop_run (loop);
+ g_signal_handlers_disconnect_by_func (client, client_acs_changed_cb, &info);
+ g_signal_handlers_disconnect_by_func (device, device_ac_changed_cb, &info);
+
+ g_assert (info.ac != NULL);
+
+ g_object_unref (info.ac);
+ g_object_unref (client);
+
+ /* Ensure that we can correctly resolve the recursive property link between the
+ * AC and the Device in a newly-created client.
+ */
+ client = nm_client_new (NULL, &error);
+ g_assert_no_error (error);
+ assert_ac_and_device (client);
+ g_object_unref (client);
+
+ client = NULL;
+ nm_client_new_async (NULL, new_client_cb, &client);
+ g_main_loop_run (loop);
+ assert_ac_and_device (client);
+ g_object_unref (client);
+
+ g_clear_pointer (&sinfo, nm_test_service_cleanup);
+}
+
+static void
+client_devices_changed_cb (GObject *client,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ TestACInfo *info = user_data;
+ const GPtrArray *devices;
+ NMDevice *device;
+
+ devices = nm_client_get_devices (NM_CLIENT (client));
+ g_assert (devices != NULL);
+ g_assert_cmpint (devices->len, ==, 2);
+
+ if (NM_IS_DEVICE_VLAN (devices->pdata[0]))
+ device = devices->pdata[0];
+ else if (NM_IS_DEVICE_VLAN (devices->pdata[1]))
+ device = devices->pdata[1];
+ else
+ g_assert_not_reached ();
+
+ g_assert_cmpstr (nm_device_get_iface (device), ==, "eth0.1");
+
+ if (nm_device_get_active_connection (device))
+ info->remaining--;
+ else {
+ g_signal_connect (device, "notify::" NM_DEVICE_ACTIVE_CONNECTION,
+ G_CALLBACK (device_ac_changed_cb), &info);
+ }
+
+ info->remaining--;
+ if (!info->remaining)
+ g_main_loop_quit (info->loop);
+}
+
+typedef struct {
+ GMainLoop *loop;
+ NMRemoteConnection *remote;
+} TestConnectionInfo;
+
+static void
+add_connection_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TestConnectionInfo *info = user_data;
+ GError *error = NULL;
+
+ info->remote = nm_client_add_connection_finish (NM_CLIENT (object), result, &error);
+ g_assert_no_error (error);
+ g_main_loop_quit (info->loop);
+}
+
+static void
+activate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ TestACInfo *info = user_data;
+ GError *error = NULL;
+
+ info->ac = nm_client_activate_connection_finish (client, result, &error);
+ g_assert_no_error (error);
+ g_assert (info->ac != NULL);
+
+ assert_ac_and_device (client);
+
+ info->remaining--;
+ if (!info->remaining)
+ g_main_loop_quit (info->loop);
+}
+
+static void
+test_activate_virtual (void)
+{
+ NMClient *client;
+ NMConnection *conn;
+ NMSettingConnection *s_con;
+ NMSettingVlan *s_vlan;
+ TestACInfo info = { loop, NULL, 0 };
+ TestConnectionInfo conn_info = { loop, NULL };
+ GError *error = NULL;
+
+ sinfo = nm_test_service_init ();
+ client = nm_client_new (NULL, &error);
+ g_assert_no_error (error);
+
+ nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth0");
+
+ conn = nmtst_create_minimal_connection ("test-ac", NULL, NM_SETTING_VLAN_SETTING_NAME, &s_con);
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0.1",
+ NULL);
+ s_vlan = nm_connection_get_setting_vlan (conn);
+ g_object_set (s_vlan,
+ NM_SETTING_VLAN_ID, 1,
+ NM_SETTING_VLAN_PARENT, "eth0",
+ NULL);
+
+ nm_client_add_connection_async (client, conn, TRUE,
+ NULL, add_connection_cb, &conn_info);
+ g_main_loop_run (loop);
+ g_object_unref (conn);
+ conn = NM_CONNECTION (conn_info.remote);
+
+ nm_client_activate_connection_async (client, conn, NULL, NULL,
+ NULL, activate_cb, &info);
+ g_object_unref (conn);
+
+ g_signal_connect (client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
+ G_CALLBACK (client_acs_changed_cb), &info);
+ g_signal_connect (client, "notify::" NM_CLIENT_DEVICES,
+ G_CALLBACK (client_devices_changed_cb), &info);
+
+ /* As with test_active_connections() above, except that now we're waiting
+ * for NMClient:devices to change rather than NMDevice:active-connections.
+ */
+ info.remaining = 3;
+
+ g_main_loop_run (loop);
+ g_signal_handlers_disconnect_by_func (client, client_acs_changed_cb, &info);
+ g_signal_handlers_disconnect_by_func (client, client_devices_changed_cb, &info);
+
+ g_assert (info.ac != NULL);
+
+ g_object_unref (info.ac);
+ g_object_unref (client);
+
+ g_clear_pointer (&sinfo, nm_test_service_cleanup);
+}
+
+static void
+activate_failed_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ NMClient *client = NM_CLIENT (object);
+ NMActiveConnection *ac;
+ GError *error = NULL;
+
+ ac = nm_client_activate_connection_finish (client, result, &error);
+ g_assert (ac == NULL);
+ g_assert_error (error, NM_OBJECT_ERROR, NM_OBJECT_ERROR_OBJECT_CREATION_FAILURE);
+ g_clear_error (&error);
+
+ g_main_loop_quit (loop);
+}
+
+static void
+test_activate_failed (void)
+{
+ NMClient *client;
+ NMDevice *device;
+ NMConnection *conn;
+ GError *error = NULL;
+
+ sinfo = nm_test_service_init ();
+ client = nm_client_new (NULL, &error);
+ g_assert_no_error (error);
+
+ device = nm_test_service_add_device (sinfo, client, "AddWiredDevice", "eth0");
+
+ /* Note that test-networkmanager-service.py checks for this exact name */
+ conn = nmtst_create_minimal_connection ("object-creation-failed-test", NULL,
+ NM_SETTING_WIRED_SETTING_NAME, NULL);
+
+ nm_client_add_and_activate_connection_async (client, conn, device, NULL,
+ NULL, activate_failed_cb, NULL);
+ g_test_expect_message ("libnm", G_LOG_LEVEL_WARNING, "*Method*doesn't exist*");
+ g_main_loop_run (loop);
+ g_test_assert_expected_messages ();
+
+ g_object_unref (conn);
+ g_object_unref (client);
+
+ g_clear_pointer (&sinfo, nm_test_service_cleanup);
+}
+
/*******************************************************************/
+NMTST_DEFINE ();
+
int
main (int argc, char **argv)
{
@@ -877,7 +1068,7 @@ main (int argc, char **argv)
g_type_init ();
#endif
- g_test_init (&argc, &argv, NULL);
+ nmtst_init (&argc, &argv, TRUE);
loop = g_main_loop_new (NULL, FALSE);
@@ -886,6 +1077,9 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/wimax-nsp-added-removed", test_wimax_nsp_added_removed);
g_test_add_func ("/libnm/devices-array", test_devices_array);
g_test_add_func ("/libnm/client-nm-running", test_client_nm_running);
+ g_test_add_func ("/libnm/active-connections", test_active_connections);
+ g_test_add_func ("/libnm/activate-virtual", test_activate_virtual);
+ g_test_add_func ("/libnm/activate-failed", test_activate_failed);
return g_test_run ();
}
diff --git a/libnm/tests/test-secret-agent.c b/libnm/tests/test-secret-agent.c
index de49893c75..a1ce5d5324 100644
--- a/libnm/tests/test-secret-agent.c
+++ b/libnm/tests/test-secret-agent.c
@@ -192,7 +192,6 @@ typedef struct {
char *ifname;
char *con_id;
- char *devpath;
int secrets_requested;
} TestSecretAgentData;
@@ -204,20 +203,6 @@ timeout_assert (gpointer user_data)
}
static void
-device_added_cb (NMClient *c,
- NMDevice *device,
- gpointer user_data)
-{
- TestSecretAgentData *sadata = user_data;
-
- g_assert (device);
- g_assert_cmpstr (nm_device_get_iface (device), ==, sadata->ifname);
-
- sadata->device = device;
- g_main_loop_quit (sadata->loop);
-}
-
-static void
connection_added_cb (GObject *s,
GAsyncResult *result,
gpointer user_data)
@@ -261,8 +246,6 @@ test_setup (TestSecretAgentData *sadata, gconstpointer test_data)
GBytes *ssid;
NMSetting *s_wsec;
GError *error = NULL;
- GVariant *ret;
- gulong handler;
sadata->sinfo = nm_test_service_init ();
sadata->client = nm_client_new (NULL, &error);
@@ -276,24 +259,8 @@ test_setup (TestSecretAgentData *sadata, gconstpointer test_data)
counter++;
/* Create the device */
- ret = g_dbus_proxy_call_sync (sadata->sinfo->proxy,
- "AddWifiDevice",
- g_variant_new ("(s)", sadata->ifname),
- G_DBUS_CALL_FLAGS_NO_AUTO_START,
- 3000,
- NULL,
- &error);
- g_assert_no_error (error);
- g_assert (ret);
- g_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
- g_variant_get (ret, "(o)", &sadata->devpath);
- g_variant_unref (ret);
-
- handler = g_signal_connect (sadata->client, "device-added",
- G_CALLBACK (device_added_cb), sadata);
- g_main_loop_run (sadata->loop);
- g_signal_handler_disconnect (sadata->client, handler);
- g_assert (sadata->device);
+ sadata->device = nm_test_service_add_device (sadata->sinfo, sadata->client,
+ "AddWifiDevice", sadata->ifname);
/* Create the connection */
connection = nmtst_create_minimal_connection (sadata->con_id, NULL, NM_SETTING_WIRELESS_SETTING_NAME, &s_con);
@@ -353,12 +320,9 @@ test_cleanup (TestSecretAgentData *sadata, gconstpointer test_data)
g_object_unref (sadata->agent);
}
- g_object_unref (sadata->connection);
- g_object_unref (sadata->client);
-
ret = g_dbus_proxy_call_sync (sadata->sinfo->proxy,
"RemoveDevice",
- g_variant_new ("(s)", sadata->devpath),
+ g_variant_new ("(s)", nm_object_get_path (NM_OBJECT (sadata->device))),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
3000,
NULL,
@@ -366,6 +330,9 @@ test_cleanup (TestSecretAgentData *sadata, gconstpointer test_data)
g_assert_no_error (error);
g_variant_unref (ret);
+ g_object_unref (sadata->connection);
+ g_object_unref (sadata->client);
+
nm_test_service_cleanup (sadata->sinfo);
g_source_remove (sadata->timeout_id);
@@ -373,7 +340,6 @@ test_cleanup (TestSecretAgentData *sadata, gconstpointer test_data)
g_free (sadata->ifname);
g_free (sadata->con_id);
- g_free (sadata->devpath);
}
/*******************************************************************/
@@ -531,14 +497,9 @@ connection_activated_good_cb (GObject *c,
GError *error = NULL;
ac = nm_client_activate_connection_finish (sadata->client, result, &error);
+ g_assert_no_error (error);
- /* test-networkmanager-service.py doesn't implement activation, but
- * we should at least get as far as the error telling us that (which the
- * other tests won't get to).
- */
- g_assert (error != NULL);
- g_dbus_error_strip_remote_error (error);
- g_assert_cmpstr (error->message, ==, "Not yet implemented");
+ g_object_unref (ac);
g_main_loop_quit (sadata->loop);
}
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 3e532e5225..d91f462663 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -51,6 +51,7 @@ typedef struct {
gboolean is_default;
gboolean is_default6;
NMActiveConnectionState state;
+ gboolean state_set;
gboolean vpn;
NMAuthSubject *subject;
@@ -138,6 +139,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
old_state = priv->state;
priv->state = new_state;
+ priv->state_set = TRUE;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
check_master_ready (self);
@@ -748,7 +750,14 @@ get_property (GObject *object, guint prop_id,
g_value_take_boxed (value, devices);
break;
case PROP_STATE:
- g_value_set_uint (value, priv->state);
+ if (priv->state_set)
+ g_value_set_uint (value, priv->state);
+ else {
+ /* When the AC has just been created, its externally-visible state should
+ * be "ACTIVATING", even though internally it is "UNKNOWN".
+ */
+ g_value_set_uint (value, NM_ACTIVE_CONNECTION_STATE_ACTIVATING);
+ }
break;
case PROP_DEFAULT:
g_value_set_boolean (value, priv->is_default);
diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py
index defc320937..d98174ce20 100755
--- a/tools/test-networkmanager-service.py
+++ b/tools/test-networkmanager-service.py
@@ -37,6 +37,7 @@ NM_DEVICE_STATE_ACTIVATED = 100
NM_DEVICE_STATE_DEACTIVATING = 110
NM_DEVICE_STATE_FAILED = 120
+# Device type
NM_DEVICE_TYPE_UNKNOWN = 0
NM_DEVICE_TYPE_ETHERNET = 1
NM_DEVICE_TYPE_WIFI = 2
@@ -54,6 +55,13 @@ NM_DEVICE_TYPE_BRIDGE = 13
NM_DEVICE_TYPE_GENERIC = 14
NM_DEVICE_TYPE_TEAM = 15
+# AC state
+NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
+NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
+NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
+NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
+NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4
+
#########################################################
IFACE_DBUS = 'org.freedesktop.DBus'
@@ -171,6 +179,9 @@ class Device(ExportedObj):
def PropertiesChanged(self, changed):
pass
+ def set_active_connection(self, ac):
+ self.active_connection = ac
+ self.__notify(PD_ACTIVE_CONNECTION)
###################################################################
@@ -215,6 +226,34 @@ class WiredDevice(Device):
pass
###################################################################
+IFACE_VLAN = 'org.freedesktop.NetworkManager.Device.Vlan'
+
+PV_HW_ADDRESS = "HwAddress"
+PV_CARRIER = "Carrier"
+PV_VLAN_ID = "VlanId"
+
+class VlanDevice(Device):
+ def __init__(self, bus, iface):
+ Device.__init__(self, bus, iface, NM_DEVICE_TYPE_VLAN)
+ self.add_dbus_interface(IFACE_VLAN, self.__get_props)
+
+ self.mac = random_mac()
+ self.carrier = False
+ self.vlan_id = 1
+
+ # Properties interface
+ def __get_props(self):
+ props = {}
+ props[PV_HW_ADDRESS] = self.mac
+ props[PV_CARRIER] = self.carrier
+ props[PV_VLAN_ID] = self.vlan_id
+ return props
+
+ @dbus.service.signal(IFACE_VLAN, signature='a{sv}')
+ def PropertiesChanged(self, changed):
+ pass
+
+###################################################################
IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint'
PP_FLAGS = "Flags"
@@ -508,6 +547,73 @@ class WimaxDevice(Device):
raise NspNotFoundException("NSP %s not found" % path)
###################################################################
+IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active'
+
+PAC_CONNECTION = "Connection"
+PAC_SPECIFIC_OBJECT = "SpecificObject"
+PAC_ID = "Id"
+PAC_UUID = "Uuid"
+PAC_TYPE = "Type"
+PAC_DEVICES = "Devices"
+PAC_STATE = "State"
+PAC_DEFAULT = "Default"
+PAC_IP4CONFIG = "Ip4Config"
+PAC_DHCP4CONFIG = "Dhcp4Config"
+PAC_DEFAULT6 = "Default6"
+PAC_IP6CONFIG = "Ip6Config"
+PAC_DHCP6CONFIG = "Dhcp6Config"
+PAC_VPN = "Vpn"
+PAC_MASTER = "Master"
+
+class ActiveConnection(ExportedObj):
+ counter = 1
+
+ def __init__(self, bus, device, connection, specific_object):
+ object_path = "/org/freedesktop/NetworkManager/ActiveConnection/%d" % ActiveConnection.counter
+ ActiveConnection.counter = ActiveConnection.counter + 1
+ ExportedObj.__init__(self, bus, object_path)
+ self.add_dbus_interface(IFACE_ACTIVE_CONNECTION, self.__get_props)
+
+ self.device = device
+ self.conn = connection
+ self.specific_object = specific_object
+ self.state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN
+ self.default = False
+ self.ip4config = None
+ self.dhcp4config = None
+ self.default6 = False
+ self.ip6config = None
+ self.dhcp6config = None
+ self.vpn = False
+ self.master = None
+
+ # Properties interface
+ def __get_props(self):
+ props = {}
+ props[PAC_CONNECTION] = to_path(self.conn)
+ props[PAC_SPECIFIC_OBJECT] = to_path(self.specific_object)
+ conn_settings = self.conn.GetSettings()
+ s_con = conn_settings['connection']
+ props[PAC_ID] = s_con['id']
+ props[PAC_UUID] = s_con['uuid']
+ props[PAC_TYPE] = s_con['type']
+ props[PAC_DEVICES] = to_path_array([self.device])
+ props[PAC_STATE] = dbus.UInt32(self.state)
+ props[PAC_DEFAULT] = self.default
+ props[PAC_IP4CONFIG] = to_path(self.ip4config)
+ props[PAC_DHCP4CONFIG] = to_path(self.dhcp4config)
+ props[PAC_DEFAULT6] = self.default6
+ props[PAC_IP6CONFIG] = to_path(self.ip6config)
+ props[PAC_DHCP6CONFIG] = to_path(self.dhcp6config)
+ props[PAC_VPN] = self.vpn
+ props[PAC_MASTER] = to_path(self.master)
+ return props
+
+ @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='a{sv}')
+ def PropertiesChanged(self, changed):
+ pass
+
+###################################################################
IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest'
IFACE_NM = 'org.freedesktop.NetworkManager'
@@ -536,11 +642,15 @@ PM_STATE = 'State'
PM_VERSION = 'Version'
PM_CONNECTIVITY = 'Connectivity'
+def set_device_ac_cb(device, ac):
+ device.set_active_connection(ac)
+
class NetworkManager(ExportedObj):
def __init__(self, bus, object_path):
ExportedObj.__init__(self, bus, object_path)
self.add_dbus_interface(IFACE_NM, self.__get_props)
+ self._bus = bus;
self.devices = []
self.active_connections = []
self.primary_connection = None
@@ -571,21 +681,27 @@ class NetworkManager(ExportedObj):
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
def ActivateConnection(self, conpath, devpath, specific_object):
+ try:
+ connection = settings.get_connection(conpath)
+ except Exception as e:
+ raise UnknownConnectionException("Connection not found")
+
+ hash = connection.GetSettings()
+ s_con = hash['connection']
+
device = None
for d in self.devices:
if d.path == devpath:
device = d
break
+ if not device and s_con['type'] == 'vlan':
+ ifname = s_con['interface-name']
+ device = VlanDevice(self._bus, ifname)
+ self.add_device(device)
if not device:
raise UnknownDeviceException("No device found for the requested iface.")
- try:
- connection = settings.get_connection(conpath)
- except Exception as e:
- raise UnknownConnectionException("Connection not found")
-
# See if we need secrets. For the moment, we only support WPA
- hash = connection.GetSettings()
if hash.has_key('802-11-wireless-security'):
s_wsec = hash['802-11-wireless-security']
if (s_wsec['key-mgmt'] == 'wpa-psk' and not s_wsec.has_key('psk')):
@@ -598,7 +714,17 @@ class NetworkManager(ExportedObj):
if not s_wsec.has_key('psk'):
raise NoSecretsException("No secrets provided")
- raise PermissionDeniedException("Not yet implemented")
+ ac = ActiveConnection(self._bus, device, connection, None)
+ self.active_connections.append(ac)
+ self.__notify(PM_ACTIVE_CONNECTIONS)
+
+ if s_con['id'] == 'object-creation-failed-test':
+ self.active_connections.remove(ac)
+ ac.remove_from_connection()
+ else:
+ GLib.timeout_add(50, set_device_ac_cb, device, ac)
+
+ return to_path(ac)
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
def AddAndActivateConnection(self, connection, devpath, specific_object):
@@ -610,8 +736,8 @@ class NetworkManager(ExportedObj):
if not device:
raise UnknownDeviceException("No device found for the requested iface.")
- conpath = manager.AddConnection(connection)
- return self.ActivateConnection(conpath, devpath, specific_object)
+ conpath = settings.AddConnection(connection)
+ return (conpath, self.ActivateConnection(conpath, devpath, specific_object))
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='')
def DeactivateConnection(self, active_connection):