From d9c99a29a0d3384c9c3d2adce430f5cb1134ab6a Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Wed, 30 Mar 2016 00:56:30 +0200 Subject: Imported Upstream version 1.1.92 --- libnm/Makefile.in | 2 + libnm/libnm.ver | 2 + libnm/nm-client.c | 12 +++ libnm/nm-device.c | 14 +++- libnm/nm-ifcfg-rh-docs.xml | 2 + libnm/nm-manager.c | 2 +- libnm/nm-object.c | 130 ++++++++++++++++++----------- libnm/nm-property-docs.xml | 10 ++- libnm/nm-remote-connection.c | 12 ++- libnm/nm-secret-agent-old.c | 11 +-- libnm/nm-setting-docs.xml | 10 ++- libnm/nm-vpn-plugin-old.c | 34 +++++--- libnm/nm-vpn-service-plugin.c | 34 +++++--- libnm/tests/test-nm-client.c | 184 +++++++++++++++++++++++++++++++++--------- 14 files changed, 318 insertions(+), 141 deletions(-) (limited to 'libnm') diff --git a/libnm/Makefile.in b/libnm/Makefile.in index 6e7fcd42..81d1aa4a 100644 --- a/libnm/Makefile.in +++ b/libnm/Makefile.in @@ -618,6 +618,7 @@ libnm_core_headers = \ $(core)/nm-vpn-plugin-info.h libnm_core_private_headers = \ + $(top_builddir)/shared/nm-shared-utils.h \ $(core)/crypto.h \ $(core)/nm-connection-private.h \ $(core)/nm-core-internal.h \ @@ -629,6 +630,7 @@ libnm_core_private_headers = \ $(core)/nm-utils-private.h libnm_core_sources = \ + $(top_builddir)/shared/nm-shared-utils.c \ $(core_build)/nm-core-enum-types.c \ $(core)/crypto.c \ $(core)/nm-connection.c \ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index e3ede1d2..7ece1b2f 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -942,6 +942,8 @@ global: nm_lldp_neighbor_unref; nm_metered_get_type; nm_setting_802_1x_check_cert_scheme; + nm_setting_802_1x_get_domain_suffix_match; + nm_setting_802_1x_get_phase2_domain_suffix_match; nm_setting_bridge_get_multicast_snooping; nm_setting_connection_autoconnect_slaves_get_type; nm_setting_connection_get_autoconnect_slaves; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 57a43ca8..a7ecdb55 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -1189,6 +1189,9 @@ nm_client_deactivate_connection_finish (NMClient *client, * Returns: (transfer none) (element-type NMRemoteConnection): an array * containing all connections provided by the remote settings service. The * returned array is owned by the #NMClient object and should not be modified. + * + * The connections are as received from D-Bus and might not validate according + * to nm_connection_verify(). **/ const GPtrArray * nm_client_get_connections (NMClient *client) @@ -1207,6 +1210,9 @@ nm_client_get_connections (NMClient *client) * * Returns: (transfer none): the remote connection object on success, or %NULL if no * matching object was found. + * + * The connection is as received from D-Bus and might not validate according + * to nm_connection_verify(). **/ NMRemoteConnection * nm_client_get_connection_by_id (NMClient *client, const char *id) @@ -1226,6 +1232,9 @@ nm_client_get_connection_by_id (NMClient *client, const char *id) * * Returns: (transfer none): the remote connection object on success, or %NULL if the object was * not known + * + * The connection is as received from D-Bus and might not validate according + * to nm_connection_verify(). **/ NMRemoteConnection * nm_client_get_connection_by_path (NMClient *client, const char *path) @@ -1245,6 +1254,9 @@ nm_client_get_connection_by_path (NMClient *client, const char *path) * * Returns: (transfer none): the remote connection object on success, or %NULL if the object was * not known + * + * The connection is as received from D-Bus and might not validate according + * to nm_connection_verify(). **/ NMRemoteConnection * nm_client_get_connection_by_uuid (NMClient *client, const char *uuid) diff --git a/libnm/nm-device.c b/libnm/nm-device.c index fa32b4c7..496dd87a 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -61,7 +61,7 @@ #include "nmdbus-device.h" static GType _nm_device_decide_type (GVariant *value); -gboolean connection_compatible (NMDevice *device, NMConnection *connection, GError **error); +static gboolean connection_compatible (NMDevice *device, NMConnection *connection, GError **error); static NMLldpNeighbor *nm_lldp_neighbor_dup (NMLldpNeighbor *neighbor); G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT, @@ -2329,6 +2329,9 @@ nm_device_reapply_finish (NMDevice *device, * Returns: (transfer full): a %NMConnection with the currently applied settings * or %NULL on error. * + * The connection is as received from D-Bus and might not validate according + * to nm_connection_verify(). + * * Since: 1.2 **/ NMConnection * @@ -2355,7 +2358,7 @@ nm_device_get_applied_connection (NMDevice *device, return NULL; } - connection = nm_simple_connection_new_from_dbus (dict, error); + connection = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, error); if (!connection) return NULL; @@ -2397,7 +2400,7 @@ device_get_applied_connection_cb (GObject *proxy, goto out; } - connection = nm_simple_connection_new_from_dbus (dict, &error); + connection = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_simple_async_result_take_error (simple, error); goto out; @@ -2457,6 +2460,9 @@ nm_device_get_applied_connection_async (NMDevice *device, * Returns: (transfer full): a currently applied %NMConnection or %NULL in case * of error. * + * The connection is as received from D-Bus and might not validate according + * to nm_connection_verify(). + * * Since: 1.2 **/ NMConnection * @@ -2712,7 +2718,7 @@ nm_device_connection_valid (NMDevice *device, NMConnection *connection) return nm_device_connection_compatible (device, connection, NULL); } -gboolean +static gboolean connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { const char *config_iface, *device_iface; diff --git a/libnm/nm-ifcfg-rh-docs.xml b/libnm/nm-ifcfg-rh-docs.xml index 9bb7b401..ef01a16a 100644 --- a/libnm/nm-ifcfg-rh-docs.xml +++ b/libnm/nm-ifcfg-rh-docs.xml @@ -12,6 +12,7 @@ + @@ -22,6 +23,7 @@ can contain values both for 'phase2-auth' and 'phase2-autheap&apo IEEE_8021X_INNER_AUTH_METHODS is also used for 'phase2-auth' values."/> + diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c index 17a51f24..a6c1f3f9 100644 --- a/libnm/nm-manager.c +++ b/libnm/nm-manager.c @@ -1212,7 +1212,7 @@ free_devices (NMManager *manager, gboolean in_dispose) if (all_devices && all_devices->len > 0) devices = all_devices; - else if (devices && devices->len > 0) + else if (real_devices && real_devices->len > 0) devices = real_devices; if (real_devices && devices != real_devices) { diff --git a/libnm/nm-object.c b/libnm/nm-object.c index b35f6822..3b41041e 100644 --- a/libnm/nm-object.c +++ b/libnm/nm-object.c @@ -205,24 +205,6 @@ deferred_notify_cb (gpointer data) if (priv->reload_remaining) return G_SOURCE_REMOVE; - /* If not all added object are finished yet, then defer the deferred - * notification. */ - for (iter = priv->notify_items; iter; iter = g_slist_next (iter)) { - NotifyItem *item = iter->data; - NMObjectPrivate *item_priv; - - if (!item->changed) - continue; - - item_priv = NM_OBJECT_GET_PRIVATE (item->changed); - if (!item_priv->inited) { - if (!g_slist_find (item_priv->waiters, object)) - item_priv->waiters = g_slist_prepend (item_priv->waiters, - g_object_ref (object)); - return G_SOURCE_REMOVE; - } - } - /* Clear priv->notify_items early so that an NMObject subclass that * listens to property changes can queue up other property changes * during the g_object_notify() call separately from the property @@ -458,6 +440,32 @@ _nm_object_create (GType type, GDBusConnection *connection, const char *path) return object; } +typedef struct { + NMObject *self; + PropertyInfo *pi; + + GObject **objects; + int length, remaining; + + GPtrArray *array; + const char *property_name; +} ObjectCreatedData; + +static void +odata_free (gpointer data) +{ + ObjectCreatedData *odata = data; + + g_object_unref (odata->self); + g_free (odata->objects); + if (odata->array) + g_ptr_array_unref (odata->array); + g_slice_free (ObjectCreatedData, odata); +} + +static void object_property_maybe_complete (ObjectCreatedData *odata); + + typedef void (*NMObjectCreateCallbackFunc) (GObject *, const char *, gpointer); typedef struct { char *path; @@ -497,13 +505,13 @@ create_async_inited (GObject *object, GAsyncResult *result, gpointer user_data) if (object) { NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object); - /* Re-queue notification checks for whoever was waiting for - * this object to initialize. */ + /* There are some object properties whose creation couldn't proceed + * because it depended on this object. */ while (priv->waiters) { - NMObject *item = priv->waiters->data; - priv->waiters = g_slist_remove (priv->waiters, item); - _nm_object_defer_notify (item); - g_object_unref (item); + ObjectCreatedData *odata = priv->waiters->data; + + priv->waiters = g_slist_remove (priv->waiters, odata); + object_property_maybe_complete (odata); } } } @@ -656,17 +664,6 @@ add_to_object_array_unique (GPtrArray *array, GObject *obj) } } -typedef struct { - NMObject *self; - PropertyInfo *pi; - - GObject **objects; - int length, remaining; - - GPtrArray *array; - const char *property_name; -} ObjectCreatedData; - /* Places items from 'needles' that are not in 'haystack' into 'diff' */ static void array_diff (GPtrArray *needles, GPtrArray *haystack, GPtrArray *diff) @@ -700,19 +697,59 @@ queue_added_removed_signal (NMObject *self, _nm_object_queue_notify_full (self, NULL, signal_prefix, added, changed); } +static gboolean +already_awaits (ObjectCreatedData *odata, GObject *object) +{ + NMObject *self = odata->self; + NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); + GSList *iter; + + if ((GObject *)odata->self == object) + return TRUE; + + for (iter = priv->waiters; iter; iter = g_slist_next (iter)) { + if (already_awaits (iter->data, object)) + return TRUE; + } + + return FALSE; +} + static void -object_property_complete (ObjectCreatedData *odata) +object_property_maybe_complete (ObjectCreatedData *odata) { NMObject *self = odata->self; NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); PropertyInfo *pi = odata->pi; gboolean different = TRUE; + int i; + + /* Only complete the array property load when all the objects are initialized. */ + for (i = 0; i < odata->length; i++) { + GObject *obj = odata->objects[i]; + NMObjectPrivate *obj_priv; + + /* Could not load the object. Perhaps it was removed. */ + if (!obj) + continue; + + obj_priv = NM_OBJECT_GET_PRIVATE (obj); + if (!obj_priv->inited) { + + /* The object is not finished because we block its creation. */ + if (already_awaits (odata, obj)) + continue; + + if (!g_slist_find (obj_priv->waiters, odata)) + obj_priv->waiters = g_slist_prepend (obj_priv->waiters, odata); + return; + } + } if (odata->array) { GPtrArray *pi_old = *((GPtrArray **) pi->field); GPtrArray *old = odata->array; GPtrArray *new; - int i; /* Build up new array */ new = g_ptr_array_new_full (odata->length, g_object_unref); @@ -776,11 +813,7 @@ object_property_complete (ObjectCreatedData *odata) if (--priv->reload_remaining == 0) reload_complete (self, FALSE); - g_object_unref (self); - g_free (odata->objects); - if (odata->array) - g_ptr_array_unref (odata->array); - g_slice_free (ObjectCreatedData, odata); + odata_free (odata); } static void @@ -799,7 +832,7 @@ object_created (GObject *obj, const char *path, gpointer user_data) odata->objects[--odata->remaining] = obj; if (!odata->remaining) - object_property_complete (odata); + object_property_maybe_complete (odata); } static gboolean @@ -874,7 +907,7 @@ handle_object_array_property (NMObject *self, const char *property_name, GVarian priv->reload_remaining++; if (npaths == 0) { - object_property_complete (odata); + object_property_maybe_complete (odata); return TRUE; } @@ -994,8 +1027,10 @@ process_properties_changed (NMObject *self, GVariant *properties, gboolean synch return; g_variant_iter_init (&iter, properties); - while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) + while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) { handle_property_changed (self, name, value, synchronously); + g_variant_unref (value); + } } static void @@ -1280,11 +1315,10 @@ _nm_object_reload_property (NMObject *object, G_DBUS_CALL_FLAGS_NONE, 15000, NULL, &err); if (!ret) { - dbgmsg ("%s: Error getting '%s' for %s: (%d) %s\n", + dbgmsg ("%s: Error getting '%s' for %s: %s\n", __func__, prop_name, nm_object_get_path (object), - err->code, err->message); g_clear_error (&err); return; @@ -1753,7 +1787,7 @@ dispose (GObject *object) g_slist_free_full (priv->notify_items, (GDestroyNotify) notify_item_free); priv->notify_items = NULL; - g_slist_free_full (priv->waiters, g_object_unref); + g_slist_free_full (priv->waiters, odata_free); g_clear_pointer (&priv->proxies, g_hash_table_unref); g_clear_object (&priv->properties_proxy); diff --git a/libnm/nm-property-docs.xml b/libnm/nm-property-docs.xml index eacbddea..c4a6685e 100644 --- a/libnm/nm-property-docs.xml +++ b/libnm/nm-property-docs.xml @@ -9,6 +9,7 @@ + @@ -26,16 +27,17 @@ + - + - + @@ -160,7 +162,7 @@ - + @@ -181,7 +183,7 @@ - + diff --git a/libnm/nm-remote-connection.c b/libnm/nm-remote-connection.c index d2b55bd8..eb2874a0 100644 --- a/libnm/nm-remote-connection.c +++ b/libnm/nm-remote-connection.c @@ -26,6 +26,7 @@ #include "nm-dbus-interface.h" #include "nm-utils.h" #include "nm-setting-connection.h" +#include "nm-core-internal.h" #include "nm-remote-connection.h" #include "nm-remote-connection-private.h" @@ -563,14 +564,11 @@ replace_settings (NMRemoteConnection *self, GVariant *new_settings) { GError *error = NULL; - if (!nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error)) { - g_warning ("%s: error updating connection %s settings: (%d) %s", - __func__, - nm_connection_get_path (NM_CONNECTION (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (!_nm_connection_replace_settings ((NMConnection *) self, + new_settings, + NM_SETTING_PARSE_FLAGS_BEST_EFFORT, + &error)) g_clear_error (&error); - } } static void diff --git a/libnm/nm-secret-agent-old.c b/libnm/nm-secret-agent-old.c index 8edb224c..02a3f685 100644 --- a/libnm/nm-secret-agent-old.c +++ b/libnm/nm-secret-agent-old.c @@ -27,6 +27,7 @@ #include "nm-enum-types.h" #include "nm-dbus-helpers.h" #include "nm-simple-connection.h" +#include "nm-core-internal.h" #include "nmdbus-secret-agent.h" #include "nmdbus-agent-manager.h" @@ -273,7 +274,7 @@ verify_request (NMSecretAgentOld *self, /* Make sure the given connection is valid */ g_assert (out_connection); - connection = nm_simple_connection_new_from_dbus (connection_dict, &local); + connection = _nm_simple_connection_new_from_dbus (connection_dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &local); if (connection) { nm_connection_set_path (connection, connection_path); *out_connection = connection; @@ -745,9 +746,6 @@ nm_secret_agent_old_register_finish (NMSecretAgentOld *self, * indicating to NetworkManager that the agent will no longer provide or * store secrets on behalf of this user. * - * It is a programmer error to attempt to unregister an agent that is not - * registered. - * * Returns: %TRUE if unregistration was successful, %FALSE on error **/ gboolean @@ -762,7 +760,6 @@ nm_secret_agent_old_unregister (NMSecretAgentOld *self, priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self); - g_return_val_if_fail (priv->registered == TRUE, FALSE); g_return_val_if_fail (priv->bus != NULL, FALSE); g_return_val_if_fail (priv->manager_proxy != NULL, FALSE); @@ -810,9 +807,6 @@ unregister_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) * Asynchronously unregisters the #NMSecretAgentOld with the NetworkManager secret * manager, indicating to NetworkManager that the agent will no longer provide * or store secrets on behalf of this user. - * - * It is a programmer error to attempt to unregister an agent that is not - * registered. **/ void nm_secret_agent_old_unregister_async (NMSecretAgentOld *self, @@ -828,7 +822,6 @@ nm_secret_agent_old_unregister_async (NMSecretAgentOld *self, priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self); - g_return_if_fail (priv->registered == TRUE); g_return_if_fail (priv->bus != NULL); g_return_if_fail (priv->manager_proxy != NULL); diff --git a/libnm/nm-setting-docs.xml b/libnm/nm-setting-docs.xml index 7e08b114..323709b0 100644 --- a/libnm/nm-setting-docs.xml +++ b/libnm/nm-setting-docs.xml @@ -9,6 +9,7 @@ + @@ -26,16 +27,17 @@ + - + - + @@ -163,7 +165,7 @@ - + @@ -186,7 +188,7 @@ - + diff --git a/libnm/nm-vpn-plugin-old.c b/libnm/nm-vpn-plugin-old.c index 9bbac414..634e61a2 100644 --- a/libnm/nm-vpn-plugin-old.c +++ b/libnm/nm-vpn-plugin-old.c @@ -293,12 +293,15 @@ fail_stop (gpointer data) } static void -schedule_fail_stop (NMVpnPluginOld *plugin) +schedule_fail_stop (NMVpnPluginOld *plugin, guint timeout_secs) { NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); nm_clear_g_source (&priv->fail_stop_id); - priv->fail_stop_id = g_idle_add (fail_stop, plugin); + if (timeout_secs) + priv->fail_stop_id = g_timeout_add_seconds (timeout_secs, fail_stop, plugin); + else + priv->fail_stop_id = g_idle_add (fail_stop, plugin); } /** @@ -450,6 +453,7 @@ _connect_generic (NMVpnPluginOld *plugin, NMConnection *connection; gboolean success = FALSE; GError *error = NULL; + guint fail_stop_timeout = 0; if (priv->state != NM_VPN_SERVICE_STATE_STOPPED && priv->state != NM_VPN_SERVICE_STATE_INIT) { @@ -461,13 +465,13 @@ _connect_generic (NMVpnPluginOld *plugin, return; } - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Invalid connection: (%d) %s", - error->code, error->message); + "Invalid connection: %s", + error->message); g_clear_error (&error); } @@ -480,15 +484,21 @@ _connect_generic (NMVpnPluginOld *plugin, return; } - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + nm_clear_g_source (&priv->fail_stop_id); if (details) { priv->interactive = TRUE; success = vpn_class->connect_interactive (plugin, connection, details, &error); + if (g_error_matches (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED)) { + /* Give NetworkManager a bit of time to fall back to Connect() */ + fail_stop_timeout = 5; + } } else success = vpn_class->connect (plugin, connection, &error); if (success) { + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + g_dbus_method_invocation_return_value (context, NULL); /* Add a timer to make sure we do not wait indefinitely for the successful connect. */ @@ -499,7 +509,7 @@ _connect_generic (NMVpnPluginOld *plugin, /* Stop the plugin from an idle handler so that the Connect * method return gets sent before the STOP StateChanged signal. */ - schedule_fail_stop (plugin); + schedule_fail_stop (plugin, fail_stop_timeout); } g_object_unref (connection); @@ -537,7 +547,7 @@ impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin, gboolean needed; GError *error = NULL; - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, @@ -596,13 +606,13 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, return; } - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Invalid connection: (%d) %s", - error->code, error->message); + "Invalid connection: %s", + error->message); g_clear_error (&error); return; } @@ -628,7 +638,7 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, /* Stop the plugin from and idle handler so that the NewSecrets * method return gets sent before the STOP StateChanged signal. */ - schedule_fail_stop (plugin); + schedule_fail_stop (plugin, 0); } g_object_unref (connection); diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 4e301e91..82e29ee8 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -291,12 +291,15 @@ fail_stop (gpointer data) } static void -schedule_fail_stop (NMVpnServicePlugin *plugin) +schedule_fail_stop (NMVpnServicePlugin *plugin, guint timeout_secs) { NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); nm_clear_g_source (&priv->fail_stop_id); - priv->fail_stop_id = g_idle_add (fail_stop, plugin); + if (timeout_secs) + priv->fail_stop_id = g_timeout_add_seconds (timeout_secs, fail_stop, plugin); + else + priv->fail_stop_id = g_idle_add (fail_stop, plugin); } void @@ -466,6 +469,7 @@ _connect_generic (NMVpnServicePlugin *plugin, NMConnection *connection; gboolean success = FALSE; GError *error = NULL; + guint fail_stop_timeout = 0; if (priv->state != NM_VPN_SERVICE_STATE_STOPPED && priv->state != NM_VPN_SERVICE_STATE_INIT) { @@ -477,13 +481,13 @@ _connect_generic (NMVpnServicePlugin *plugin, return; } - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Invalid connection: (%d) %s", - error->code, error->message); + "Invalid connection: %s", + error->message); g_clear_error (&error); return; } @@ -497,7 +501,7 @@ _connect_generic (NMVpnServicePlugin *plugin, return; } - nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + nm_clear_g_source (&priv->fail_stop_id); if (priv->dbus_watch_peer) priv->peer_watch_id = watch_peer (plugin, context); @@ -505,10 +509,16 @@ _connect_generic (NMVpnServicePlugin *plugin, if (details) { priv->interactive = TRUE; success = vpn_class->connect_interactive (plugin, connection, details, &error); + if (g_error_matches (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED)) { + /* Give NetworkManager a bit of time to fall back to Connect() */ + fail_stop_timeout = 5; + } } else success = vpn_class->connect (plugin, connection, &error); if (success) { + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + g_dbus_method_invocation_return_value (context, NULL); /* Add a timer to make sure we do not wait indefinitely for the successful connect. */ @@ -519,7 +529,7 @@ _connect_generic (NMVpnServicePlugin *plugin, /* Stop the plugin from an idle handler so that the Connect * method return gets sent before the STOP StateChanged signal. */ - schedule_fail_stop (plugin); + schedule_fail_stop (plugin, fail_stop_timeout); } g_object_unref (connection); @@ -557,7 +567,7 @@ impl_vpn_service_plugin_need_secrets (NMVpnServicePlugin *plugin, gboolean needed; GError *error = NULL; - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, @@ -616,13 +626,13 @@ impl_vpn_service_plugin_new_secrets (NMVpnServicePlugin *plugin, return; } - connection = nm_simple_connection_new_from_dbus (properties, &error); + connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error); if (!connection) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Invalid connection: (%d) %s", - error->code, error->message); + "Invalid connection: %s", + error->message); g_clear_error (&error); return; } @@ -648,7 +658,7 @@ impl_vpn_service_plugin_new_secrets (NMVpnServicePlugin *plugin, /* Stop the plugin from and idle handler so that the NewSecrets * method return gets sent before the STOP StateChanged signal. */ - schedule_fail_stop (plugin); + schedule_fail_stop (plugin, 0); } g_object_unref (connection); diff --git a/libnm/tests/test-nm-client.c b/libnm/tests/test-nm-client.c index 9e9d480e..3a7c4d5d 100644 --- a/libnm/tests/test-nm-client.c +++ b/libnm/tests/test-nm-client.c @@ -1002,9 +1002,8 @@ client_devices_changed_cb (GObject *client, g_assert_cmpstr (nm_device_get_iface (device), ==, "eth0.1"); - if (nm_device_get_active_connection (device)) - info->remaining--; - else { + if (!nm_device_get_active_connection (device)) { + info->remaining++; g_signal_connect (device, "notify::" NM_DEVICE_ACTIVE_CONNECTION, G_CALLBACK (device_ac_changed_cb), info); } @@ -1094,8 +1093,10 @@ test_activate_virtual (void) 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. + /* We're expecting a client::devices change, client::activate callback, + * and a device::active-connection change. + * The client::devices callback can hook a client::active-connections + * change and bump this if the property is not yet loaded. */ info.remaining = 3; @@ -1242,10 +1243,12 @@ _test_connection_invalid_find_connections (gpointer element, gpointer needle, gp } #define ASSERT_IDX(i) \ - g_assert_cmpint (idx[i], >=, 0); \ - g_assert (path##i && *path##i); \ - g_assert (NM_IS_REMOTE_CONNECTION (connections->pdata[idx[i]])); \ - g_assert_cmpstr (nm_connection_get_path (connections->pdata[idx[i]]), ==, path##i); + G_STMT_START { \ + g_assert_cmpint (idx[i], >=, 0); \ + g_assert (path##i && *path##i); \ + g_assert (NM_IS_REMOTE_CONNECTION (connections->pdata[idx[i]])); \ + g_assert_cmpstr (nm_connection_get_path (connections->pdata[idx[i]]), ==, path##i); \ + } G_STMT_END static void test_connection_invalid (void) @@ -1259,12 +1262,14 @@ test_connection_invalid (void) gs_free char *path0 = NULL; gs_free char *path1 = NULL; gs_free char *path2 = NULL; + gs_free char *path3 = NULL; gs_free char *uuid2 = NULL; gsize n_found; - gssize idx[3]; + gssize idx[4]; + gs_unref_variant GVariant *variant = NULL; /************************************************************************** - * Add two connection before starting libnm. One valid, one invalid. + * Add three connections before starting libnm. One valid, two invalid. *************************************************************************/ connection = nmtst_create_minimal_connection ("test-connection-invalid-0", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con); @@ -1288,6 +1293,21 @@ test_connection_invalid (void) FALSE, &path1); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "test-connection-invalid-2", + NM_SETTING_CONNECTION_TYPE, "invalid-type-2", + NM_SETTING_CONNECTION_UUID, nmtst_uuid_generate (), + NULL); + variant = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); + NMTST_VARIANT_EDITOR (variant, + NMTST_VARIANT_ADD_SETTING ("invalid-type-2", + nmtst_variant_new_vardict ("some-key1", g_variant_new_string ("some-value1"), + "some-key2", g_variant_new_uint32 (4722)))); + g_variant_ref_sink (variant); + nmtstc_service_add_connection_variant (my_sinfo, + variant, + FALSE, + &path2); client = nm_client_new (NULL, &error); g_assert_no_error (error); @@ -1295,19 +1315,21 @@ test_connection_invalid (void) connections = nm_client_get_connections (client); g_assert (connections); - g_assert_cmpint (connections->len, ==, 2); + g_assert_cmpint (connections->len, ==, 3); n_found = nmtst_find_all_indexes (connections->pdata, connections->len, - (gpointer *) ((const char *[]) { path0, path1 }), - 2, + (gpointer *) ((const char *[]) { path0, path1, path2 }), + 3, _test_connection_invalid_find_connections, NULL, idx); - g_assert_cmpint (n_found, ==, 2); + g_assert_cmpint (n_found, ==, 3); ASSERT_IDX (0); ASSERT_IDX (1); + ASSERT_IDX (2); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0); /************************************************************************** * After having the client up and running, add another invalid connection @@ -1321,7 +1343,7 @@ test_connection_invalid (void) nmtstc_service_add_connection (my_sinfo, connection, FALSE, - &path2); + &path3); nmtst_main_loop_run (loop, 100); @@ -1330,21 +1352,97 @@ test_connection_invalid (void) connections = nm_client_get_connections (client); g_assert (connections); - g_assert_cmpint (connections->len, ==, 3); + g_assert_cmpint (connections->len, ==, 4); n_found = nmtst_find_all_indexes (connections->pdata, connections->len, - (gpointer *) ((const char *[]) { path0, path1, path2 }), - 3, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, _test_connection_invalid_find_connections, NULL, idx); - g_assert_cmpint (n_found, ==, 3); + g_assert_cmpint (n_found, ==, 4); + ASSERT_IDX (0); + ASSERT_IDX (1); + ASSERT_IDX (2); + ASSERT_IDX (3); + nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0); + + /************************************************************************** + * Modify the invalid connection (still invalid) + *************************************************************************/ + + NMTST_VARIANT_EDITOR (variant, + NMTST_VARIANT_CHANGE_PROPERTY ("invalid-type-2", + "some-key2", "u", 4721)); + g_variant_ref_sink (variant); + nmtstc_service_update_connection_variant (my_sinfo, + path2, + variant, + FALSE); + + nmtst_main_loop_run (loop, 100); + + connections = nm_client_get_connections (client); + g_assert (connections); + + g_assert_cmpint (connections->len, ==, 4); + n_found = nmtst_find_all_indexes (connections->pdata, + connections->len, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, + _test_connection_invalid_find_connections, + NULL, + idx); + g_assert_cmpint (n_found, ==, 4); ASSERT_IDX (0); ASSERT_IDX (1); ASSERT_IDX (2); + ASSERT_IDX (3); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0); + + /************************************************************************** + * Modify the invalid connection (becomes valid) + *************************************************************************/ + + NMTST_VARIANT_EDITOR (variant, + NMTST_VARIANT_DROP_SETTING ("invalid-type-2")); + NMTST_VARIANT_EDITOR (variant, + NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TYPE, "s", NM_SETTING_WIRED_SETTING_NAME)); + g_variant_ref_sink (variant); + nmtstc_service_update_connection_variant (my_sinfo, + path2, + variant, + FALSE); + + nmtst_main_loop_run (loop, 100); + + connections = nm_client_get_connections (client); + g_assert (connections); + + g_assert_cmpint (connections->len, ==, 4); + n_found = nmtst_find_all_indexes (connections->pdata, + connections->len, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, + _test_connection_invalid_find_connections, + NULL, + idx); + g_assert_cmpint (n_found, ==, 4); + ASSERT_IDX (0); + ASSERT_IDX (1); + ASSERT_IDX (2); + ASSERT_IDX (3); + nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); + nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0); /************************************************************************** * Modify the invalid connection (still invalid) @@ -1354,7 +1452,7 @@ test_connection_invalid (void) NM_SETTING_CONNECTION_ID, "test-connection-invalid-2x", NULL); nmtstc_service_update_connection (my_sinfo, - path2, + path3, connection, FALSE); @@ -1363,22 +1461,24 @@ test_connection_invalid (void) connections = nm_client_get_connections (client); g_assert (connections); - g_assert_cmpint (connections->len, ==, 3); + g_assert_cmpint (connections->len, ==, 4); n_found = nmtst_find_all_indexes (connections->pdata, connections->len, - (gpointer *) ((const char *[]) { path0, path1, path2 }), - 3, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, _test_connection_invalid_find_connections, NULL, idx); - g_assert_cmpint (n_found, ==, 3); + g_assert_cmpint (n_found, ==, 4); ASSERT_IDX (0); ASSERT_IDX (1); ASSERT_IDX (2); + ASSERT_IDX (3); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); - nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0); - g_assert_cmpstr ("test-connection-invalid-2x", ==, nm_connection_get_id (connections->pdata[idx[2]])); + nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0); + g_assert_cmpstr ("test-connection-invalid-2x", ==, nm_connection_get_id (connections->pdata[idx[3]])); /************************************************************************** * Modify the invalid connection (now becomes valid) @@ -1394,7 +1494,7 @@ test_connection_invalid (void) NULL); nmtstc_service_update_connection (my_sinfo, - path2, + path3, connection, FALSE); @@ -1403,22 +1503,24 @@ test_connection_invalid (void) connections = nm_client_get_connections (client); g_assert (connections); - g_assert_cmpint (connections->len, ==, 3); + g_assert_cmpint (connections->len, ==, 4); n_found = nmtst_find_all_indexes (connections->pdata, connections->len, - (gpointer *) ((const char *[]) { path0, path1, path2 }), - 3, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, _test_connection_invalid_find_connections, NULL, idx); - g_assert_cmpint (n_found, ==, 3); + g_assert_cmpint (n_found, ==, 4); ASSERT_IDX (0); ASSERT_IDX (1); ASSERT_IDX (2); + ASSERT_IDX (3); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0); - nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]); - g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[2]])); + nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[3]]); + g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[3]])); /************************************************************************** * Modify the invalid connection and make it valid @@ -1443,23 +1545,25 @@ test_connection_invalid (void) connections = nm_client_get_connections (client); g_assert (connections); - g_assert_cmpint (connections->len, ==, 3); + g_assert_cmpint (connections->len, ==, 4); n_found = nmtst_find_all_indexes (connections->pdata, connections->len, - (gpointer *) ((const char *[]) { path0, path1, path2 }), - 3, + (gpointer *) ((const char *[]) { path0, path1, path2, path3 }), + 4, _test_connection_invalid_find_connections, NULL, idx); - g_assert_cmpint (n_found, ==, 3); + g_assert_cmpint (n_found, ==, 4); ASSERT_IDX (0); ASSERT_IDX (1); ASSERT_IDX (2); + ASSERT_IDX (3); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]); nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[1]]); - nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]); + nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0); + nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[3]]); g_assert_cmpstr ("test-connection-invalid-1x", ==, nm_connection_get_id (connections->pdata[idx[1]])); - g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[2]])); + g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[3]])); #undef ASSERT_IDX } -- cgit 1.3.0-6-gf8a5